"Fossies" - the Fresh Open Source Software Archive

Member "tmux-3.2a/window-copy.c" (10 Jun 2021, 135657 Bytes) of package /linux/misc/tmux-3.2a.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "window-copy.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.2_vs_3.2a.

    1 /* $OpenBSD$ */
    2 
    3 /*
    4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
   15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
   16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 
   19 #include <sys/types.h>
   20 
   21 #include <ctype.h>
   22 #include <regex.h>
   23 #include <stdlib.h>
   24 #include <string.h>
   25 #include <time.h>
   26 
   27 #include "tmux.h"
   28 
   29 struct window_copy_mode_data;
   30 
   31 static const char *window_copy_key_table(struct window_mode_entry *);
   32 static void window_copy_command(struct window_mode_entry *, struct client *,
   33             struct session *, struct winlink *, struct args *,
   34             struct mouse_event *);
   35 static struct screen *window_copy_init(struct window_mode_entry *,
   36             struct cmd_find_state *, struct args *);
   37 static struct screen *window_copy_view_init(struct window_mode_entry *,
   38             struct cmd_find_state *, struct args *);
   39 static void window_copy_free(struct window_mode_entry *);
   40 static void window_copy_resize(struct window_mode_entry *, u_int, u_int);
   41 static void window_copy_formats(struct window_mode_entry *,
   42             struct format_tree *);
   43 static void window_copy_pageup1(struct window_mode_entry *, int);
   44 static int  window_copy_pagedown(struct window_mode_entry *, int, int);
   45 static void window_copy_next_paragraph(struct window_mode_entry *);
   46 static void window_copy_previous_paragraph(struct window_mode_entry *);
   47 static void window_copy_redraw_selection(struct window_mode_entry *, u_int);
   48 static void window_copy_redraw_lines(struct window_mode_entry *, u_int,
   49             u_int);
   50 static void window_copy_redraw_screen(struct window_mode_entry *);
   51 static void window_copy_write_line(struct window_mode_entry *,
   52             struct screen_write_ctx *, u_int);
   53 static void window_copy_write_lines(struct window_mode_entry *,
   54             struct screen_write_ctx *, u_int, u_int);
   55 static char    *window_copy_match_at_cursor(struct window_copy_mode_data *);
   56 static void window_copy_scroll_to(struct window_mode_entry *, u_int, u_int,
   57             int);
   58 static int  window_copy_search_compare(struct grid *, u_int, u_int,
   59             struct grid *, u_int, int);
   60 static int  window_copy_search_lr(struct grid *, struct grid *, u_int *,
   61             u_int, u_int, u_int, int);
   62 static int  window_copy_search_rl(struct grid *, struct grid *, u_int *,
   63             u_int, u_int, u_int, int);
   64 static int  window_copy_last_regex(struct grid *, u_int, u_int, u_int,
   65             u_int, u_int *, u_int *, const char *, const regex_t *,
   66             int);
   67 static int  window_copy_search_mark_at(struct window_copy_mode_data *,
   68             u_int, u_int, u_int *);
   69 static char    *window_copy_stringify(struct grid *, u_int, u_int, u_int,
   70             char *, u_int *);
   71 static void window_copy_cstrtocellpos(struct grid *, u_int, u_int *,
   72             u_int *, const char *);
   73 static int  window_copy_search_marks(struct window_mode_entry *,
   74             struct screen *, int, int);
   75 static void window_copy_clear_marks(struct window_mode_entry *);
   76 static int  window_copy_is_lowercase(const char *);
   77 static void window_copy_search_back_overlap(struct grid *, regex_t *,
   78             u_int *, u_int *, u_int *, u_int);
   79 static int  window_copy_search_jump(struct window_mode_entry *,
   80             struct grid *, struct grid *, u_int, u_int, u_int, int, int,
   81             int, int);
   82 static int  window_copy_search(struct window_mode_entry *, int, int);
   83 static int  window_copy_search_up(struct window_mode_entry *, int);
   84 static int  window_copy_search_down(struct window_mode_entry *, int);
   85 static void window_copy_goto_line(struct window_mode_entry *, const char *);
   86 static void window_copy_update_cursor(struct window_mode_entry *, u_int,
   87             u_int);
   88 static void window_copy_start_selection(struct window_mode_entry *);
   89 static int  window_copy_adjust_selection(struct window_mode_entry *,
   90             u_int *, u_int *);
   91 static int  window_copy_set_selection(struct window_mode_entry *, int, int);
   92 static int  window_copy_update_selection(struct window_mode_entry *, int,
   93             int);
   94 static void window_copy_synchronize_cursor(struct window_mode_entry *, int);
   95 static void    *window_copy_get_selection(struct window_mode_entry *, size_t *);
   96 static void window_copy_copy_buffer(struct window_mode_entry *,
   97             const char *, void *, size_t);
   98 static void window_copy_pipe(struct window_mode_entry *,
   99             struct session *, const char *);
  100 static void window_copy_copy_pipe(struct window_mode_entry *,
  101             struct session *, const char *, const char *);
  102 static void window_copy_copy_selection(struct window_mode_entry *,
  103             const char *);
  104 static void window_copy_append_selection(struct window_mode_entry *);
  105 static void window_copy_clear_selection(struct window_mode_entry *);
  106 static void window_copy_copy_line(struct window_mode_entry *, char **,
  107             size_t *, u_int, u_int, u_int);
  108 static int  window_copy_in_set(struct window_mode_entry *, u_int, u_int,
  109             const char *);
  110 static u_int    window_copy_find_length(struct window_mode_entry *, u_int);
  111 static void window_copy_cursor_start_of_line(struct window_mode_entry *);
  112 static void window_copy_cursor_back_to_indentation(
  113             struct window_mode_entry *);
  114 static void window_copy_cursor_end_of_line(struct window_mode_entry *);
  115 static void window_copy_other_end(struct window_mode_entry *);
  116 static void window_copy_cursor_left(struct window_mode_entry *);
  117 static void window_copy_cursor_right(struct window_mode_entry *, int);
  118 static void window_copy_cursor_up(struct window_mode_entry *, int);
  119 static void window_copy_cursor_down(struct window_mode_entry *, int);
  120 static void window_copy_cursor_jump(struct window_mode_entry *);
  121 static void window_copy_cursor_jump_back(struct window_mode_entry *);
  122 static void window_copy_cursor_jump_to(struct window_mode_entry *);
  123 static void window_copy_cursor_jump_to_back(struct window_mode_entry *);
  124 static void window_copy_cursor_next_word(struct window_mode_entry *,
  125             const char *);
  126 static void window_copy_cursor_next_word_end_pos(struct window_mode_entry *,
  127             const char *, u_int *, u_int *);
  128 static void window_copy_cursor_next_word_end(struct window_mode_entry *,
  129             const char *, int);
  130 static void window_copy_cursor_previous_word_pos(struct window_mode_entry *,
  131             const char *, int, u_int *, u_int *);
  132 static void window_copy_cursor_previous_word(struct window_mode_entry *,
  133             const char *, int);
  134 static void window_copy_scroll_up(struct window_mode_entry *, u_int);
  135 static void window_copy_scroll_down(struct window_mode_entry *, u_int);
  136 static void window_copy_rectangle_set(struct window_mode_entry *, int);
  137 static void window_copy_move_mouse(struct mouse_event *);
  138 static void window_copy_drag_update(struct client *, struct mouse_event *);
  139 static void window_copy_drag_release(struct client *, struct mouse_event *);
  140 static void window_copy_jump_to_mark(struct window_mode_entry *);
  141 static void window_copy_acquire_cursor_up(struct window_mode_entry *,
  142             u_int, u_int, u_int, u_int, u_int);
  143 static void window_copy_acquire_cursor_down(struct window_mode_entry *,
  144             u_int, u_int, u_int, u_int, u_int, u_int, int);
  145 
  146 const struct window_mode window_copy_mode = {
  147     .name = "copy-mode",
  148 
  149     .init = window_copy_init,
  150     .free = window_copy_free,
  151     .resize = window_copy_resize,
  152     .key_table = window_copy_key_table,
  153     .command = window_copy_command,
  154     .formats = window_copy_formats,
  155 };
  156 
  157 const struct window_mode window_view_mode = {
  158     .name = "view-mode",
  159 
  160     .init = window_copy_view_init,
  161     .free = window_copy_free,
  162     .resize = window_copy_resize,
  163     .key_table = window_copy_key_table,
  164     .command = window_copy_command,
  165     .formats = window_copy_formats,
  166 };
  167 
  168 enum {
  169     WINDOW_COPY_OFF,
  170     WINDOW_COPY_SEARCHUP,
  171     WINDOW_COPY_SEARCHDOWN,
  172     WINDOW_COPY_JUMPFORWARD,
  173     WINDOW_COPY_JUMPBACKWARD,
  174     WINDOW_COPY_JUMPTOFORWARD,
  175     WINDOW_COPY_JUMPTOBACKWARD,
  176 };
  177 
  178 enum {
  179     WINDOW_COPY_REL_POS_ABOVE,
  180     WINDOW_COPY_REL_POS_ON_SCREEN,
  181     WINDOW_COPY_REL_POS_BELOW,
  182 };
  183 
  184 enum window_copy_cmd_action {
  185     WINDOW_COPY_CMD_NOTHING,
  186     WINDOW_COPY_CMD_REDRAW,
  187     WINDOW_COPY_CMD_CANCEL,
  188 };
  189 
  190 enum window_copy_cmd_clear {
  191     WINDOW_COPY_CMD_CLEAR_ALWAYS,
  192     WINDOW_COPY_CMD_CLEAR_NEVER,
  193     WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
  194 };
  195 
  196 struct window_copy_cmd_state {
  197     struct window_mode_entry    *wme;
  198     struct args         *args;
  199     struct mouse_event      *m;
  200 
  201     struct client           *c;
  202     struct session          *s;
  203     struct winlink          *wl;
  204 };
  205 
  206 /*
  207  * Copy mode's visible screen (the "screen" field) is filled from one of two
  208  * sources: the original contents of the pane (used when we actually enter via
  209  * the "copy-mode" command, to copy the contents of the current pane), or else
  210  * a series of lines containing the output from an output-writing tmux command
  211  * (such as any of the "show-*" or "list-*" commands).
  212  *
  213  * In either case, the full content of the copy-mode grid is pointed at by the
  214  * "backing" field, and is copied into "screen" as needed (that is, when
  215  * scrolling occurs). When copy-mode is backed by a pane, backing points
  216  * directly at that pane's screen structure (&wp->base); when backed by a list
  217  * of output-lines from a command, it points at a newly-allocated screen
  218  * structure (which is deallocated when the mode ends).
  219  */
  220 struct window_copy_mode_data {
  221     struct screen    screen;
  222 
  223     struct screen   *backing;
  224     int      backing_written; /* backing display started */
  225 
  226     int      viewmode;  /* view mode entered */
  227 
  228     u_int        oy;        /* number of lines scrolled up */
  229 
  230     u_int        selx;      /* beginning of selection */
  231     u_int        sely;
  232 
  233     u_int        endselx;   /* end of selection */
  234     u_int        endsely;
  235 
  236     enum {
  237         CURSORDRAG_NONE,    /* selection is independent of cursor */
  238         CURSORDRAG_ENDSEL,  /* end is synchronized with cursor */
  239         CURSORDRAG_SEL,     /* start is synchronized with cursor */
  240     } cursordrag;
  241 
  242     int      modekeys;
  243     enum {
  244         LINE_SEL_NONE,
  245         LINE_SEL_LEFT_RIGHT,
  246         LINE_SEL_RIGHT_LEFT,
  247     } lineflag;         /* line selection mode */
  248     int      rectflag;  /* in rectangle copy mode? */
  249     int      scroll_exit;   /* exit on scroll to end? */
  250     int      hide_position; /* hide position marker */
  251 
  252     enum {
  253         SEL_CHAR,       /* select one char at a time */
  254         SEL_WORD,       /* select one word at a time */
  255         SEL_LINE,       /* select one line at a time */
  256     } selflag;
  257 
  258     const char  *ws;        /* word separators */
  259 
  260     u_int        dx;        /* drag start position */
  261     u_int        dy;
  262 
  263     u_int        selrx;     /* selection reset positions */
  264     u_int        selry;
  265     u_int        endselrx;
  266     u_int        endselry;
  267 
  268     u_int        cx;
  269     u_int        cy;
  270 
  271     u_int        lastcx;    /* position in last line w/ content */
  272     u_int        lastsx;    /* size of last line w/ content */
  273 
  274     u_int        mx;        /* mark position */
  275     u_int        my;
  276     int      showmark;
  277 
  278     int      searchtype;
  279     int      searchdirection;
  280     int      searchregex;
  281     char        *searchstr;
  282     u_char      *searchmark;
  283     int      searchcount;
  284     int      searchmore;
  285     int      searchall;
  286     int      searchx;
  287     int      searchy;
  288     int      searcho;
  289     u_char       searchgen;
  290 
  291     int      timeout;   /* search has timed out */
  292 #define WINDOW_COPY_SEARCH_TIMEOUT 10000
  293 #define WINDOW_COPY_SEARCH_ALL_TIMEOUT 200
  294 
  295     int          jumptype;
  296     struct utf8_data    *jumpchar;
  297 
  298     struct event     dragtimer;
  299 #define WINDOW_COPY_DRAG_REPEAT_TIME 50000
  300 };
  301 
  302 static void
  303 window_copy_scroll_timer(__unused int fd, __unused short events, void *arg)
  304 {
  305     struct window_mode_entry    *wme = arg;
  306     struct window_pane      *wp = wme->wp;
  307     struct window_copy_mode_data    *data = wme->data;
  308     struct timeval           tv = {
  309         .tv_usec = WINDOW_COPY_DRAG_REPEAT_TIME
  310     };
  311 
  312     evtimer_del(&data->dragtimer);
  313 
  314     if (TAILQ_FIRST(&wp->modes) != wme)
  315         return;
  316 
  317     if (data->cy == 0) {
  318         evtimer_add(&data->dragtimer, &tv);
  319         window_copy_cursor_up(wme, 1);
  320     } else if (data->cy == screen_size_y(&data->screen) - 1) {
  321         evtimer_add(&data->dragtimer, &tv);
  322         window_copy_cursor_down(wme, 1);
  323     }
  324 }
  325 
  326 static struct screen *
  327 window_copy_clone_screen(struct screen *src, struct screen *hint, u_int *cx,
  328     u_int *cy, int trim)
  329 {
  330     struct screen       *dst;
  331     const struct grid_line  *gl;
  332     u_int            sy, wx, wy;
  333     int          reflow;
  334 
  335     dst = xcalloc(1, sizeof *dst);
  336 
  337     sy = screen_hsize(src) + screen_size_y(src);
  338     if (trim) {
  339         while (sy > screen_hsize(src)) {
  340             gl = grid_peek_line(src->grid, sy - 1);
  341             if (gl->cellused != 0)
  342                 break;
  343             sy--;
  344         }
  345     }
  346     log_debug("%s: target screen is %ux%u, source %ux%u", __func__,
  347         screen_size_x(src), sy, screen_size_x(hint),
  348         screen_hsize(src) + screen_size_y(src));
  349     screen_init(dst, screen_size_x(src), sy, screen_hlimit(src));
  350 
  351     /*
  352      * Ensure history is on for the backing grid so lines are not deleted
  353      * during resizing.
  354      */
  355     dst->grid->flags |= GRID_HISTORY;
  356     grid_duplicate_lines(dst->grid, 0, src->grid, 0, sy);
  357 
  358     dst->grid->sy = sy - screen_hsize(src);
  359     dst->grid->hsize = screen_hsize(src);
  360     dst->grid->hscrolled = src->grid->hscrolled;
  361     if (src->cy > dst->grid->sy - 1) {
  362         dst->cx = 0;
  363         dst->cy = dst->grid->sy - 1;
  364     } else {
  365         dst->cx = src->cx;
  366         dst->cy = src->cy;
  367     }
  368 
  369     if (cx != NULL && cy != NULL) {
  370         *cx = dst->cx;
  371         *cy = screen_hsize(dst) + dst->cy;
  372         reflow = (screen_size_x(hint) != screen_size_x(dst));
  373     }
  374     else
  375         reflow = 0;
  376     if (reflow)
  377         grid_wrap_position(dst->grid, *cx, *cy, &wx, &wy);
  378     screen_resize_cursor(dst, screen_size_x(hint), screen_size_y(hint), 1,
  379         0, 0);
  380     if (reflow)
  381         grid_unwrap_position(dst->grid, cx, cy, wx, wy);
  382 
  383     return (dst);
  384 }
  385 
  386 static struct window_copy_mode_data *
  387 window_copy_common_init(struct window_mode_entry *wme)
  388 {
  389     struct window_pane      *wp = wme->wp;
  390     struct window_copy_mode_data    *data;
  391     struct screen           *base = &wp->base;
  392 
  393     wme->data = data = xcalloc(1, sizeof *data);
  394 
  395     data->cursordrag = CURSORDRAG_NONE;
  396     data->lineflag = LINE_SEL_NONE;
  397     data->selflag = SEL_CHAR;
  398 
  399     if (wp->searchstr != NULL) {
  400         data->searchtype = WINDOW_COPY_SEARCHUP;
  401         data->searchregex = wp->searchregex;
  402         data->searchstr = xstrdup(wp->searchstr);
  403     } else {
  404         data->searchtype = WINDOW_COPY_OFF;
  405         data->searchregex = 0;
  406         data->searchstr = NULL;
  407     }
  408     data->searchx = data->searchy = data->searcho = -1;
  409     data->searchall = 1;
  410 
  411     data->jumptype = WINDOW_COPY_OFF;
  412     data->jumpchar = NULL;
  413 
  414     screen_init(&data->screen, screen_size_x(base), screen_size_y(base), 0);
  415     data->modekeys = options_get_number(wp->window->options, "mode-keys");
  416 
  417     evtimer_set(&data->dragtimer, window_copy_scroll_timer, wme);
  418 
  419     return (data);
  420 }
  421 
  422 static struct screen *
  423 window_copy_init(struct window_mode_entry *wme,
  424     __unused struct cmd_find_state *fs, struct args *args)
  425 {
  426     struct window_pane      *wp = wme->swp;
  427     struct window_copy_mode_data    *data;
  428     struct screen           *base = &wp->base;
  429     struct screen_write_ctx      ctx;
  430     u_int                i, cx, cy;
  431 
  432     data = window_copy_common_init(wme);
  433     data->backing = window_copy_clone_screen(base, &data->screen, &cx, &cy,
  434         wme->swp != wme->wp);
  435 
  436     data->cx = cx;
  437     if (cy < screen_hsize(data->backing)) {
  438         data->cy = 0;
  439         data->oy = screen_hsize(data->backing) - cy;
  440     } else {
  441         data->cy = cy - screen_hsize(data->backing);
  442         data->oy = 0;
  443     }
  444 
  445     data->scroll_exit = args_has(args, 'e');
  446     data->hide_position = args_has(args, 'H');
  447 
  448     data->screen.cx = data->cx;
  449     data->screen.cy = data->cy;
  450     data->mx = data->cx;
  451     data->my = screen_hsize(data->backing) + data->cy - data->oy;
  452     data->showmark = 0;
  453 
  454     screen_write_start(&ctx, &data->screen);
  455     for (i = 0; i < screen_size_y(&data->screen); i++)
  456         window_copy_write_line(wme, &ctx, i);
  457     screen_write_cursormove(&ctx, data->cx, data->cy, 0);
  458     screen_write_stop(&ctx);
  459 
  460     return (&data->screen);
  461 }
  462 
  463 static struct screen *
  464 window_copy_view_init(struct window_mode_entry *wme,
  465     __unused struct cmd_find_state *fs, __unused struct args *args)
  466 {
  467     struct window_pane      *wp = wme->wp;
  468     struct window_copy_mode_data    *data;
  469     struct screen           *base = &wp->base;
  470     struct screen           *s;
  471 
  472     data = window_copy_common_init(wme);
  473     data->viewmode = 1;
  474 
  475     data->backing = s = xmalloc(sizeof *data->backing);
  476     screen_init(s, screen_size_x(base), screen_size_y(base), UINT_MAX);
  477     data->mx = data->cx;
  478     data->my = screen_hsize(data->backing) + data->cy - data->oy;
  479     data->showmark = 0;
  480 
  481     return (&data->screen);
  482 }
  483 
  484 static void
  485 window_copy_free(struct window_mode_entry *wme)
  486 {
  487     struct window_copy_mode_data    *data = wme->data;
  488 
  489     evtimer_del(&data->dragtimer);
  490 
  491     free(data->searchmark);
  492     free(data->searchstr);
  493     free(data->jumpchar);
  494 
  495     screen_free(data->backing);
  496     free(data->backing);
  497 
  498     screen_free(&data->screen);
  499     free(data);
  500 }
  501 
  502 void
  503 window_copy_add(struct window_pane *wp, const char *fmt, ...)
  504 {
  505     va_list ap;
  506 
  507     va_start(ap, fmt);
  508     window_copy_vadd(wp, fmt, ap);
  509     va_end(ap);
  510 }
  511 
  512 void
  513 window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap)
  514 {
  515     struct window_mode_entry    *wme = TAILQ_FIRST(&wp->modes);
  516     struct window_copy_mode_data    *data = wme->data;
  517     struct screen           *backing = data->backing;
  518     struct screen_write_ctx      back_ctx, ctx;
  519     struct grid_cell         gc;
  520     u_int                old_hsize, old_cy;
  521 
  522     memcpy(&gc, &grid_default_cell, sizeof gc);
  523 
  524     old_hsize = screen_hsize(data->backing);
  525     screen_write_start(&back_ctx, backing);
  526     if (data->backing_written) {
  527         /*
  528          * On the second or later line, do a CRLF before writing
  529          * (so it's on a new line).
  530          */
  531         screen_write_carriagereturn(&back_ctx);
  532         screen_write_linefeed(&back_ctx, 0, 8);
  533     } else
  534         data->backing_written = 1;
  535     old_cy = backing->cy;
  536     screen_write_vnputs(&back_ctx, 0, &gc, fmt, ap);
  537     screen_write_stop(&back_ctx);
  538 
  539     data->oy += screen_hsize(data->backing) - old_hsize;
  540 
  541     screen_write_start_pane(&ctx, wp, &data->screen);
  542 
  543     /*
  544      * If the history has changed, draw the top line.
  545      * (If there's any history at all, it has changed.)
  546      */
  547     if (screen_hsize(data->backing))
  548         window_copy_redraw_lines(wme, 0, 1);
  549 
  550     /* Write the new lines. */
  551     window_copy_redraw_lines(wme, old_cy, backing->cy - old_cy + 1);
  552 
  553     screen_write_stop(&ctx);
  554 }
  555 
  556 void
  557 window_copy_pageup(struct window_pane *wp, int half_page)
  558 {
  559     window_copy_pageup1(TAILQ_FIRST(&wp->modes), half_page);
  560 }
  561 
  562 static void
  563 window_copy_pageup1(struct window_mode_entry *wme, int half_page)
  564 {
  565     struct window_copy_mode_data    *data = wme->data;
  566     struct screen           *s = &data->screen;
  567     u_int                n, ox, oy, px, py;
  568 
  569     oy = screen_hsize(data->backing) + data->cy - data->oy;
  570     ox = window_copy_find_length(wme, oy);
  571 
  572     if (data->cx != ox) {
  573         data->lastcx = data->cx;
  574         data->lastsx = ox;
  575     }
  576     data->cx = data->lastcx;
  577 
  578     n = 1;
  579     if (screen_size_y(s) > 2) {
  580         if (half_page)
  581             n = screen_size_y(s) / 2;
  582         else
  583             n = screen_size_y(s) - 2;
  584     }
  585 
  586     if (data->oy + n > screen_hsize(data->backing)) {
  587         data->oy = screen_hsize(data->backing);
  588         if (data->cy < n)
  589             data->cy = 0;
  590         else
  591             data->cy -= n;
  592     } else
  593         data->oy += n;
  594 
  595     if (data->screen.sel == NULL || !data->rectflag) {
  596         py = screen_hsize(data->backing) + data->cy - data->oy;
  597         px = window_copy_find_length(wme, py);
  598         if ((data->cx >= data->lastsx && data->cx != px) ||
  599             data->cx > px)
  600             window_copy_cursor_end_of_line(wme);
  601     }
  602 
  603     if (data->searchmark != NULL && !data->timeout)
  604         window_copy_search_marks(wme, NULL, data->searchregex, 1);
  605     window_copy_update_selection(wme, 1, 0);
  606     window_copy_redraw_screen(wme);
  607 }
  608 
  609 static int
  610 window_copy_pagedown(struct window_mode_entry *wme, int half_page,
  611     int scroll_exit)
  612 {
  613     struct window_copy_mode_data    *data = wme->data;
  614     struct screen           *s = &data->screen;
  615     u_int                n, ox, oy, px, py;
  616 
  617     oy = screen_hsize(data->backing) + data->cy - data->oy;
  618     ox = window_copy_find_length(wme, oy);
  619 
  620     if (data->cx != ox) {
  621         data->lastcx = data->cx;
  622         data->lastsx = ox;
  623     }
  624     data->cx = data->lastcx;
  625 
  626     n = 1;
  627     if (screen_size_y(s) > 2) {
  628         if (half_page)
  629             n = screen_size_y(s) / 2;
  630         else
  631             n = screen_size_y(s) - 2;
  632     }
  633 
  634     if (data->oy < n) {
  635         data->oy = 0;
  636         if (data->cy + (n - data->oy) >= screen_size_y(data->backing))
  637             data->cy = screen_size_y(data->backing) - 1;
  638         else
  639             data->cy += n - data->oy;
  640     } else
  641         data->oy -= n;
  642 
  643     if (data->screen.sel == NULL || !data->rectflag) {
  644         py = screen_hsize(data->backing) + data->cy - data->oy;
  645         px = window_copy_find_length(wme, py);
  646         if ((data->cx >= data->lastsx && data->cx != px) ||
  647             data->cx > px)
  648             window_copy_cursor_end_of_line(wme);
  649     }
  650 
  651     if (scroll_exit && data->oy == 0)
  652         return (1);
  653     if (data->searchmark != NULL && !data->timeout)
  654         window_copy_search_marks(wme, NULL, data->searchregex, 1);
  655     window_copy_update_selection(wme, 1, 0);
  656     window_copy_redraw_screen(wme);
  657     return (0);
  658 }
  659 
  660 static void
  661 window_copy_previous_paragraph(struct window_mode_entry *wme)
  662 {
  663     struct window_copy_mode_data    *data = wme->data;
  664     u_int                oy;
  665 
  666     oy = screen_hsize(data->backing) + data->cy - data->oy;
  667 
  668     while (oy > 0 && window_copy_find_length(wme, oy) == 0)
  669         oy--;
  670 
  671     while (oy > 0 && window_copy_find_length(wme, oy) > 0)
  672         oy--;
  673 
  674     window_copy_scroll_to(wme, 0, oy, 0);
  675 }
  676 
  677 static void
  678 window_copy_next_paragraph(struct window_mode_entry *wme)
  679 {
  680     struct window_copy_mode_data    *data = wme->data;
  681     struct screen           *s = &data->screen;
  682     u_int                maxy, ox, oy;
  683 
  684     oy = screen_hsize(data->backing) + data->cy - data->oy;
  685     maxy = screen_hsize(data->backing) + screen_size_y(s) - 1;
  686 
  687     while (oy < maxy && window_copy_find_length(wme, oy) == 0)
  688         oy++;
  689 
  690     while (oy < maxy && window_copy_find_length(wme, oy) > 0)
  691         oy++;
  692 
  693     ox = window_copy_find_length(wme, oy);
  694     window_copy_scroll_to(wme, ox, oy, 0);
  695 }
  696 
  697 char *
  698 window_copy_get_word(struct window_pane *wp, u_int x, u_int y)
  699 {
  700     struct window_mode_entry    *wme = TAILQ_FIRST(&wp->modes);
  701     struct window_copy_mode_data    *data = wme->data;
  702     struct grid         *gd = data->screen.grid;
  703 
  704     return (format_grid_word(gd, x, gd->hsize + y));
  705 }
  706 
  707 char *
  708 window_copy_get_line(struct window_pane *wp, u_int y)
  709 {
  710     struct window_mode_entry    *wme = TAILQ_FIRST(&wp->modes);
  711     struct window_copy_mode_data    *data = wme->data;
  712     struct grid         *gd = data->screen.grid;
  713 
  714     return (format_grid_line(gd, gd->hsize + y));
  715 }
  716 
  717 static void *
  718 window_copy_cursor_word_cb(struct format_tree *ft)
  719 {
  720     struct window_pane      *wp = format_get_pane(ft);
  721     struct window_mode_entry    *wme = TAILQ_FIRST(&wp->modes);
  722     struct window_copy_mode_data    *data = wme->data;
  723 
  724     return (window_copy_get_word(wp, data->cx, data->cy));
  725 }
  726 
  727 static void *
  728 window_copy_cursor_line_cb(struct format_tree *ft)
  729 {
  730     struct window_pane      *wp = format_get_pane(ft);
  731     struct window_mode_entry    *wme = TAILQ_FIRST(&wp->modes);
  732     struct window_copy_mode_data    *data = wme->data;
  733 
  734     return (window_copy_get_line(wp, data->cy));
  735 }
  736 
  737 static void *
  738 window_copy_search_match_cb(struct format_tree *ft)
  739 {
  740     struct window_pane      *wp = format_get_pane(ft);
  741     struct window_mode_entry    *wme = TAILQ_FIRST(&wp->modes);
  742     struct window_copy_mode_data    *data = wme->data;
  743 
  744     return (window_copy_match_at_cursor(data));
  745 }
  746 
  747 static void
  748 window_copy_formats(struct window_mode_entry *wme, struct format_tree *ft)
  749 {
  750     struct window_copy_mode_data    *data = wme->data;
  751 
  752     format_add(ft, "scroll_position", "%d", data->oy);
  753     format_add(ft, "rectangle_toggle", "%d", data->rectflag);
  754 
  755     format_add(ft, "copy_cursor_x", "%d", data->cx);
  756     format_add(ft, "copy_cursor_y", "%d", data->cy);
  757 
  758     format_add(ft, "selection_present", "%d", data->screen.sel != NULL);
  759     if (data->screen.sel != NULL) {
  760         format_add(ft, "selection_start_x", "%d", data->selx);
  761         format_add(ft, "selection_start_y", "%d", data->sely);
  762         format_add(ft, "selection_end_x", "%d", data->endselx);
  763         format_add(ft, "selection_end_y", "%d", data->endsely);
  764         format_add(ft, "selection_active", "%d",
  765             data->cursordrag != CURSORDRAG_NONE);
  766     } else
  767         format_add(ft, "selection_active", "%d", 0);
  768 
  769     format_add(ft, "search_present", "%d", data->searchmark != NULL);
  770     format_add_cb(ft, "search_match", window_copy_search_match_cb);
  771 
  772     format_add_cb(ft, "copy_cursor_word", window_copy_cursor_word_cb);
  773     format_add_cb(ft, "copy_cursor_line", window_copy_cursor_line_cb);
  774 }
  775 
  776 static void
  777 window_copy_size_changed(struct window_mode_entry *wme)
  778 {
  779     struct window_copy_mode_data    *data = wme->data;
  780     struct screen           *s = &data->screen;
  781     struct screen_write_ctx      ctx;
  782     int              search = (data->searchmark != NULL);
  783 
  784     window_copy_clear_selection(wme);
  785     window_copy_clear_marks(wme);
  786 
  787     screen_write_start(&ctx, s);
  788     window_copy_write_lines(wme, &ctx, 0, screen_size_y(s));
  789     screen_write_stop(&ctx);
  790 
  791     if (search && !data->timeout)
  792         window_copy_search_marks(wme, NULL, data->searchregex, 0);
  793     data->searchx = data->cx;
  794     data->searchy = data->cy;
  795     data->searcho = data->oy;
  796 }
  797 
  798 static void
  799 window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
  800 {
  801     struct window_copy_mode_data    *data = wme->data;
  802     struct screen           *s = &data->screen;
  803     struct grid         *gd = data->backing->grid;
  804     u_int                cx, cy, wx, wy;
  805     int              reflow;
  806 
  807     screen_resize(s, sx, sy, 0);
  808     cx = data->cx;
  809     cy = gd->hsize + data->cy - data->oy;
  810     reflow = (gd->sx != sx);
  811     if (reflow)
  812         grid_wrap_position(gd, cx, cy, &wx, &wy);
  813     screen_resize_cursor(data->backing, sx, sy, 1, 0, 0);
  814     if (reflow)
  815         grid_unwrap_position(gd, &cx, &cy, wx, wy);
  816 
  817     data->cx = cx;
  818     if (cy < gd->hsize) {
  819         data->cy = 0;
  820         data->oy = gd->hsize - cy;
  821     } else {
  822         data->cy = cy - gd->hsize;
  823         data->oy = 0;
  824     }
  825 
  826     window_copy_size_changed(wme);
  827     window_copy_redraw_screen(wme);
  828 }
  829 
  830 static const char *
  831 window_copy_key_table(struct window_mode_entry *wme)
  832 {
  833     struct window_pane  *wp = wme->wp;
  834 
  835     if (options_get_number(wp->window->options, "mode-keys") == MODEKEY_VI)
  836         return ("copy-mode-vi");
  837     return ("copy-mode");
  838 }
  839 
  840 static int
  841 window_copy_expand_search_string(struct window_copy_cmd_state *cs)
  842 {
  843     struct window_mode_entry    *wme = cs->wme;
  844     struct window_copy_mode_data    *data = wme->data;
  845     const char          *argument;
  846     char                *expanded;
  847 
  848     if (cs->args->argc == 2) {
  849         argument = cs->args->argv[1];
  850         if (*argument != '\0') {
  851             if (args_has(cs->args, 'F')) {
  852                 expanded = format_single(NULL, argument, NULL,
  853                     NULL, NULL, wme->wp);
  854                 if (*expanded == '\0') {
  855                     free(expanded);
  856                     return (0);
  857                 }
  858                 free(data->searchstr);
  859                 data->searchstr = expanded;
  860             } else {
  861                 free(data->searchstr);
  862                 data->searchstr = xstrdup(argument);
  863             }
  864         }
  865     }
  866     return (1);
  867 }
  868 
  869 static enum window_copy_cmd_action
  870 window_copy_cmd_append_selection(struct window_copy_cmd_state *cs)
  871 {
  872     struct window_mode_entry    *wme = cs->wme;
  873     struct session          *s = cs->s;
  874 
  875     if (s != NULL)
  876         window_copy_append_selection(wme);
  877     window_copy_clear_selection(wme);
  878     return (WINDOW_COPY_CMD_REDRAW);
  879 }
  880 
  881 static enum window_copy_cmd_action
  882 window_copy_cmd_append_selection_and_cancel(struct window_copy_cmd_state *cs)
  883 {
  884     struct window_mode_entry    *wme = cs->wme;
  885     struct session          *s = cs->s;
  886 
  887     if (s != NULL)
  888         window_copy_append_selection(wme);
  889     window_copy_clear_selection(wme);
  890     return (WINDOW_COPY_CMD_CANCEL);
  891 }
  892 
  893 static enum window_copy_cmd_action
  894 window_copy_cmd_back_to_indentation(struct window_copy_cmd_state *cs)
  895 {
  896     struct window_mode_entry    *wme = cs->wme;
  897 
  898     window_copy_cursor_back_to_indentation(wme);
  899     return (WINDOW_COPY_CMD_NOTHING);
  900 }
  901 
  902 static enum window_copy_cmd_action
  903 window_copy_cmd_begin_selection(struct window_copy_cmd_state *cs)
  904 {
  905     struct window_mode_entry    *wme = cs->wme;
  906     struct client           *c = cs->c;
  907     struct mouse_event      *m = cs->m;
  908     struct window_copy_mode_data    *data = wme->data;
  909 
  910     if (m != NULL) {
  911         window_copy_start_drag(c, m);
  912         return (WINDOW_COPY_CMD_NOTHING);
  913     }
  914 
  915     data->lineflag = LINE_SEL_NONE;
  916     data->selflag = SEL_CHAR;
  917     window_copy_start_selection(wme);
  918     return (WINDOW_COPY_CMD_REDRAW);
  919 }
  920 
  921 static enum window_copy_cmd_action
  922 window_copy_cmd_stop_selection(struct window_copy_cmd_state *cs)
  923 {
  924     struct window_mode_entry    *wme = cs->wme;
  925     struct window_copy_mode_data    *data = wme->data;
  926 
  927     data->cursordrag = CURSORDRAG_NONE;
  928     data->lineflag = LINE_SEL_NONE;
  929     data->selflag = SEL_CHAR;
  930     return (WINDOW_COPY_CMD_NOTHING);
  931 }
  932 
  933 static enum window_copy_cmd_action
  934 window_copy_cmd_bottom_line(struct window_copy_cmd_state *cs)
  935 {
  936     struct window_mode_entry    *wme = cs->wme;
  937     struct window_copy_mode_data    *data = wme->data;
  938 
  939     data->cx = 0;
  940     data->cy = screen_size_y(&data->screen) - 1;
  941 
  942     window_copy_update_selection(wme, 1, 0);
  943     return (WINDOW_COPY_CMD_REDRAW);
  944 }
  945 
  946 static enum window_copy_cmd_action
  947 window_copy_cmd_cancel(__unused struct window_copy_cmd_state *cs)
  948 {
  949     return (WINDOW_COPY_CMD_CANCEL);
  950 }
  951 
  952 static enum window_copy_cmd_action
  953 window_copy_cmd_clear_selection(struct window_copy_cmd_state *cs)
  954 {
  955     struct window_mode_entry    *wme = cs->wme;
  956 
  957     window_copy_clear_selection(wme);
  958     return (WINDOW_COPY_CMD_REDRAW);
  959 }
  960 
  961 static enum window_copy_cmd_action
  962 window_copy_cmd_copy_end_of_line(struct window_copy_cmd_state *cs)
  963 {
  964     struct window_mode_entry    *wme = cs->wme;
  965     struct client           *c = cs->c;
  966     struct session          *s = cs->s;
  967     struct winlink          *wl = cs->wl;
  968     struct window_pane      *wp = wme->wp;
  969     u_int                np = wme->prefix;
  970     char                *prefix = NULL;
  971 
  972     if (cs->args->argc == 2)
  973         prefix = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
  974 
  975     window_copy_start_selection(wme);
  976     for (; np > 1; np--)
  977         window_copy_cursor_down(wme, 0);
  978     window_copy_cursor_end_of_line(wme);
  979 
  980     if (s != NULL) {
  981         window_copy_copy_selection(wme, prefix);
  982 
  983         free(prefix);
  984         return (WINDOW_COPY_CMD_CANCEL);
  985     }
  986 
  987     free(prefix);
  988     return (WINDOW_COPY_CMD_REDRAW);
  989 }
  990 
  991 static enum window_copy_cmd_action
  992 window_copy_cmd_copy_line(struct window_copy_cmd_state *cs)
  993 {
  994     struct window_mode_entry    *wme = cs->wme;
  995     struct client           *c = cs->c;
  996     struct session          *s = cs->s;
  997     struct winlink          *wl = cs->wl;
  998     struct window_pane      *wp = wme->wp;
  999     struct window_copy_mode_data    *data = wme->data;
 1000     u_int                np = wme->prefix;
 1001     char                *prefix = NULL;
 1002 
 1003     if (cs->args->argc == 2)
 1004         prefix = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
 1005 
 1006     data->selflag = SEL_CHAR;
 1007     window_copy_cursor_start_of_line(wme);
 1008     window_copy_start_selection(wme);
 1009     for (; np > 1; np--)
 1010         window_copy_cursor_down(wme, 0);
 1011     window_copy_cursor_end_of_line(wme);
 1012 
 1013     if (s != NULL) {
 1014         window_copy_copy_selection(wme, prefix);
 1015 
 1016         free(prefix);
 1017         return (WINDOW_COPY_CMD_CANCEL);
 1018     }
 1019 
 1020     free(prefix);
 1021     return (WINDOW_COPY_CMD_REDRAW);
 1022 }
 1023 
 1024 static enum window_copy_cmd_action
 1025 window_copy_cmd_copy_selection_no_clear(struct window_copy_cmd_state *cs)
 1026 {
 1027     struct window_mode_entry    *wme = cs->wme;
 1028     struct client           *c = cs->c;
 1029     struct session          *s = cs->s;
 1030     struct winlink          *wl = cs->wl;
 1031     struct window_pane      *wp = wme->wp;
 1032     char                *prefix = NULL;
 1033 
 1034     if (cs->args->argc == 2)
 1035         prefix = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
 1036 
 1037     if (s != NULL)
 1038         window_copy_copy_selection(wme, prefix);
 1039 
 1040     free(prefix);
 1041     return (WINDOW_COPY_CMD_NOTHING);
 1042 }
 1043 
 1044 static enum window_copy_cmd_action
 1045 window_copy_cmd_copy_selection(struct window_copy_cmd_state *cs)
 1046 {
 1047     struct window_mode_entry    *wme = cs->wme;
 1048 
 1049     window_copy_cmd_copy_selection_no_clear(cs);
 1050     window_copy_clear_selection(wme);
 1051     return (WINDOW_COPY_CMD_REDRAW);
 1052 }
 1053 
 1054 static enum window_copy_cmd_action
 1055 window_copy_cmd_copy_selection_and_cancel(struct window_copy_cmd_state *cs)
 1056 {
 1057     struct window_mode_entry    *wme = cs->wme;
 1058 
 1059     window_copy_cmd_copy_selection_no_clear(cs);
 1060     window_copy_clear_selection(wme);
 1061     return (WINDOW_COPY_CMD_CANCEL);
 1062 }
 1063 
 1064 static enum window_copy_cmd_action
 1065 window_copy_cmd_cursor_down(struct window_copy_cmd_state *cs)
 1066 {
 1067     struct window_mode_entry    *wme = cs->wme;
 1068     u_int                np = wme->prefix;
 1069 
 1070     for (; np != 0; np--)
 1071         window_copy_cursor_down(wme, 0);
 1072     return (WINDOW_COPY_CMD_NOTHING);
 1073 }
 1074 
 1075 static enum window_copy_cmd_action
 1076 window_copy_cmd_cursor_down_and_cancel(struct window_copy_cmd_state *cs)
 1077 {
 1078     struct window_mode_entry    *wme = cs->wme;
 1079     struct window_copy_mode_data    *data = wme->data;
 1080     u_int                np = wme->prefix, cy;
 1081 
 1082     cy = data->cy;
 1083     for (; np != 0; np--)
 1084         window_copy_cursor_down(wme, 0);
 1085     if (cy == data->cy && data->oy == 0)
 1086         return (WINDOW_COPY_CMD_CANCEL);
 1087     return (WINDOW_COPY_CMD_NOTHING);
 1088 }
 1089 
 1090 static enum window_copy_cmd_action
 1091 window_copy_cmd_cursor_left(struct window_copy_cmd_state *cs)
 1092 {
 1093     struct window_mode_entry    *wme = cs->wme;
 1094     u_int                np = wme->prefix;
 1095 
 1096     for (; np != 0; np--)
 1097         window_copy_cursor_left(wme);
 1098     return (WINDOW_COPY_CMD_NOTHING);
 1099 }
 1100 
 1101 static enum window_copy_cmd_action
 1102 window_copy_cmd_cursor_right(struct window_copy_cmd_state *cs)
 1103 {
 1104     struct window_mode_entry    *wme = cs->wme;
 1105     struct window_copy_mode_data    *data = wme->data;
 1106     u_int                np = wme->prefix;
 1107 
 1108     for (; np != 0; np--) {
 1109         window_copy_cursor_right(wme, data->screen.sel != NULL &&
 1110             data->rectflag);
 1111     }
 1112     return (WINDOW_COPY_CMD_NOTHING);
 1113 }
 1114 
 1115 static enum window_copy_cmd_action
 1116 window_copy_cmd_cursor_up(struct window_copy_cmd_state *cs)
 1117 {
 1118     struct window_mode_entry    *wme = cs->wme;
 1119     u_int                np = wme->prefix;
 1120 
 1121     for (; np != 0; np--)
 1122         window_copy_cursor_up(wme, 0);
 1123     return (WINDOW_COPY_CMD_NOTHING);
 1124 }
 1125 
 1126 static enum window_copy_cmd_action
 1127 window_copy_cmd_end_of_line(struct window_copy_cmd_state *cs)
 1128 {
 1129     struct window_mode_entry    *wme = cs->wme;
 1130 
 1131     window_copy_cursor_end_of_line(wme);
 1132     return (WINDOW_COPY_CMD_NOTHING);
 1133 }
 1134 
 1135 static enum window_copy_cmd_action
 1136 window_copy_cmd_halfpage_down(struct window_copy_cmd_state *cs)
 1137 {
 1138     struct window_mode_entry    *wme = cs->wme;
 1139     struct window_copy_mode_data    *data = wme->data;
 1140     u_int                np = wme->prefix;
 1141 
 1142     for (; np != 0; np--) {
 1143         if (window_copy_pagedown(wme, 1, data->scroll_exit))
 1144             return (WINDOW_COPY_CMD_CANCEL);
 1145     }
 1146     return (WINDOW_COPY_CMD_NOTHING);
 1147 }
 1148 
 1149 static enum window_copy_cmd_action
 1150 window_copy_cmd_halfpage_down_and_cancel(struct window_copy_cmd_state *cs)
 1151 {
 1152 
 1153     struct window_mode_entry    *wme = cs->wme;
 1154     u_int                np = wme->prefix;
 1155 
 1156     for (; np != 0; np--) {
 1157         if (window_copy_pagedown(wme, 1, 1))
 1158             return (WINDOW_COPY_CMD_CANCEL);
 1159     }
 1160     return (WINDOW_COPY_CMD_NOTHING);
 1161 }
 1162 
 1163 static enum window_copy_cmd_action
 1164 window_copy_cmd_halfpage_up(struct window_copy_cmd_state *cs)
 1165 {
 1166     struct window_mode_entry    *wme = cs->wme;
 1167     u_int                np = wme->prefix;
 1168 
 1169     for (; np != 0; np--)
 1170         window_copy_pageup1(wme, 1);
 1171     return (WINDOW_COPY_CMD_NOTHING);
 1172 }
 1173 
 1174 static enum window_copy_cmd_action
 1175 window_copy_cmd_history_bottom(struct window_copy_cmd_state *cs)
 1176 {
 1177     struct window_mode_entry    *wme = cs->wme;
 1178     struct window_copy_mode_data    *data = wme->data;
 1179     struct screen           *s = data->backing;
 1180     u_int                oy;
 1181 
 1182     oy = screen_hsize(s) + data->cy - data->oy;
 1183     if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
 1184         window_copy_other_end(wme);
 1185 
 1186     data->cy = screen_size_y(&data->screen) - 1;
 1187     data->cx = window_copy_find_length(wme, screen_hsize(s) + data->cy);
 1188     data->oy = 0;
 1189 
 1190     if (data->searchmark != NULL && !data->timeout)
 1191         window_copy_search_marks(wme, NULL, data->searchregex, 1);
 1192     window_copy_update_selection(wme, 1, 0);
 1193     return (WINDOW_COPY_CMD_REDRAW);
 1194 }
 1195 
 1196 static enum window_copy_cmd_action
 1197 window_copy_cmd_history_top(struct window_copy_cmd_state *cs)
 1198 {
 1199     struct window_mode_entry    *wme = cs->wme;
 1200     struct window_copy_mode_data    *data = wme->data;
 1201     u_int                oy;
 1202 
 1203     oy = screen_hsize(data->backing) + data->cy - data->oy;
 1204     if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
 1205         window_copy_other_end(wme);
 1206 
 1207     data->cy = 0;
 1208     data->cx = 0;
 1209     data->oy = screen_hsize(data->backing);
 1210 
 1211     if (data->searchmark != NULL && !data->timeout)
 1212         window_copy_search_marks(wme, NULL, data->searchregex, 1);
 1213     window_copy_update_selection(wme, 1, 0);
 1214     return (WINDOW_COPY_CMD_REDRAW);
 1215 }
 1216 
 1217 static enum window_copy_cmd_action
 1218 window_copy_cmd_jump_again(struct window_copy_cmd_state *cs)
 1219 {
 1220     struct window_mode_entry    *wme = cs->wme;
 1221     struct window_copy_mode_data    *data = wme->data;
 1222     u_int                np = wme->prefix;
 1223 
 1224     switch (data->jumptype) {
 1225     case WINDOW_COPY_JUMPFORWARD:
 1226         for (; np != 0; np--)
 1227             window_copy_cursor_jump(wme);
 1228         break;
 1229     case WINDOW_COPY_JUMPBACKWARD:
 1230         for (; np != 0; np--)
 1231             window_copy_cursor_jump_back(wme);
 1232         break;
 1233     case WINDOW_COPY_JUMPTOFORWARD:
 1234         for (; np != 0; np--)
 1235             window_copy_cursor_jump_to(wme);
 1236         break;
 1237     case WINDOW_COPY_JUMPTOBACKWARD:
 1238         for (; np != 0; np--)
 1239             window_copy_cursor_jump_to_back(wme);
 1240         break;
 1241     }
 1242     return (WINDOW_COPY_CMD_NOTHING);
 1243 }
 1244 
 1245 static enum window_copy_cmd_action
 1246 window_copy_cmd_jump_reverse(struct window_copy_cmd_state *cs)
 1247 {
 1248     struct window_mode_entry    *wme = cs->wme;
 1249     struct window_copy_mode_data    *data = wme->data;
 1250     u_int                np = wme->prefix;
 1251 
 1252     switch (data->jumptype) {
 1253     case WINDOW_COPY_JUMPFORWARD:
 1254         for (; np != 0; np--)
 1255             window_copy_cursor_jump_back(wme);
 1256         break;
 1257     case WINDOW_COPY_JUMPBACKWARD:
 1258         for (; np != 0; np--)
 1259             window_copy_cursor_jump(wme);
 1260         break;
 1261     case WINDOW_COPY_JUMPTOFORWARD:
 1262         for (; np != 0; np--)
 1263             window_copy_cursor_jump_to_back(wme);
 1264         break;
 1265     case WINDOW_COPY_JUMPTOBACKWARD:
 1266         for (; np != 0; np--)
 1267             window_copy_cursor_jump_to(wme);
 1268         break;
 1269     }
 1270     return (WINDOW_COPY_CMD_NOTHING);
 1271 }
 1272 
 1273 static enum window_copy_cmd_action
 1274 window_copy_cmd_middle_line(struct window_copy_cmd_state *cs)
 1275 {
 1276     struct window_mode_entry    *wme = cs->wme;
 1277     struct window_copy_mode_data    *data = wme->data;
 1278 
 1279     data->cx = 0;
 1280     data->cy = (screen_size_y(&data->screen) - 1) / 2;
 1281 
 1282     window_copy_update_selection(wme, 1, 0);
 1283     return (WINDOW_COPY_CMD_REDRAW);
 1284 }
 1285 
 1286 static enum window_copy_cmd_action
 1287 window_copy_cmd_previous_matching_bracket(struct window_copy_cmd_state *cs)
 1288 {
 1289     struct window_mode_entry    *wme = cs->wme;
 1290     u_int                np = wme->prefix;
 1291     struct window_copy_mode_data    *data = wme->data;
 1292     struct screen           *s = data->backing;
 1293     char                 open[] = "{[(", close[] = "}])";
 1294     char                 tried, found, start, *cp;
 1295     u_int                px, py, xx, n;
 1296     struct grid_cell         gc;
 1297     int              failed;
 1298 
 1299     for (; np != 0; np--) {
 1300         /* Get cursor position and line length. */
 1301         px = data->cx;
 1302         py = screen_hsize(s) + data->cy - data->oy;
 1303         xx = window_copy_find_length(wme, py);
 1304         if (xx == 0)
 1305             break;
 1306 
 1307         /*
 1308          * Get the current character. If not on a bracket, try the
 1309          * previous. If still not, then behave like previous-word.
 1310          */
 1311         tried = 0;
 1312     retry:
 1313         grid_get_cell(s->grid, px, py, &gc);
 1314         if (gc.data.size != 1 || (gc.flags & GRID_FLAG_PADDING))
 1315             cp = NULL;
 1316         else {
 1317             found = *gc.data.data;
 1318             cp = strchr(close, found);
 1319         }
 1320         if (cp == NULL) {
 1321             if (data->modekeys == MODEKEY_EMACS) {
 1322                 if (!tried && px > 0) {
 1323                     px--;
 1324                     tried = 1;
 1325                     goto retry;
 1326                 }
 1327                 window_copy_cursor_previous_word(wme, "}]) ", 1);
 1328             }
 1329             continue;
 1330         }
 1331         start = open[cp - close];
 1332 
 1333         /* Walk backward until the matching bracket is reached. */
 1334         n = 1;
 1335         failed = 0;
 1336         do {
 1337             if (px == 0) {
 1338                 if (py == 0) {
 1339                     failed = 1;
 1340                     break;
 1341                 }
 1342                 do {
 1343                     py--;
 1344                     xx = window_copy_find_length(wme, py);
 1345                 } while (xx == 0 && py > 0);
 1346                 if (xx == 0 && py == 0) {
 1347                     failed = 1;
 1348                     break;
 1349                 }
 1350                 px = xx - 1;
 1351             } else
 1352                 px--;
 1353 
 1354             grid_get_cell(s->grid, px, py, &gc);
 1355             if (gc.data.size == 1 &&
 1356                 (~gc.flags & GRID_FLAG_PADDING)) {
 1357                 if (*gc.data.data == found)
 1358                     n++;
 1359                 else if (*gc.data.data == start)
 1360                     n--;
 1361             }
 1362         } while (n != 0);
 1363 
 1364         /* Move the cursor to the found location if any. */
 1365         if (!failed)
 1366             window_copy_scroll_to(wme, px, py, 0);
 1367     }
 1368 
 1369     return (WINDOW_COPY_CMD_NOTHING);
 1370 }
 1371 
 1372 static enum window_copy_cmd_action
 1373 window_copy_cmd_next_matching_bracket(struct window_copy_cmd_state *cs)
 1374 {
 1375     struct window_mode_entry    *wme = cs->wme;
 1376     u_int                np = wme->prefix;
 1377     struct window_copy_mode_data    *data = wme->data;
 1378     struct screen           *s = data->backing;
 1379     char                 open[] = "{[(", close[] = "}])";
 1380     char                 tried, found, end, *cp;
 1381     u_int                px, py, xx, yy, sx, sy, n;
 1382     struct grid_cell         gc;
 1383     int              failed;
 1384     struct grid_line        *gl;
 1385 
 1386     for (; np != 0; np--) {
 1387         /* Get cursor position and line length. */
 1388         px = data->cx;
 1389         py = screen_hsize(s) + data->cy - data->oy;
 1390         xx = window_copy_find_length(wme, py);
 1391         yy = screen_hsize(s) + screen_size_y(s) - 1;
 1392         if (xx == 0)
 1393             break;
 1394 
 1395         /*
 1396          * Get the current character. If not on a bracket, try the
 1397          * next. If still not, then behave like next-word.
 1398          */
 1399         tried = 0;
 1400     retry:
 1401         grid_get_cell(s->grid, px, py, &gc);
 1402         if (gc.data.size != 1 || (gc.flags & GRID_FLAG_PADDING))
 1403             cp = NULL;
 1404         else {
 1405             found = *gc.data.data;
 1406 
 1407             /*
 1408              * In vi mode, attempt to move to previous bracket if a
 1409              * closing bracket is found first. If this fails,
 1410              * return to the original cursor position.
 1411              */
 1412             cp = strchr(close, found);
 1413             if (cp != NULL && data->modekeys == MODEKEY_VI) {
 1414                 sx = data->cx;
 1415                 sy = screen_hsize(s) + data->cy - data->oy;
 1416 
 1417                 window_copy_scroll_to(wme, px, py, 0);
 1418                 window_copy_cmd_previous_matching_bracket(cs);
 1419 
 1420                 px = data->cx;
 1421                 py = screen_hsize(s) + data->cy - data->oy;
 1422                 grid_get_cell(s->grid, px, py, &gc);
 1423                 if (gc.data.size == 1 &&
 1424                     (~gc.flags & GRID_FLAG_PADDING) &&
 1425                     strchr(close, *gc.data.data) != NULL)
 1426                     window_copy_scroll_to(wme, sx, sy, 0);
 1427                 break;
 1428             }
 1429 
 1430             cp = strchr(open, found);
 1431         }
 1432         if (cp == NULL) {
 1433             if (data->modekeys == MODEKEY_EMACS) {
 1434                 if (!tried && px <= xx) {
 1435                     px++;
 1436                     tried = 1;
 1437                     goto retry;
 1438                 }
 1439                 window_copy_cursor_next_word_end(wme, "{[( ",
 1440                     0);
 1441                 continue;
 1442             }
 1443             /* For vi, continue searching for bracket until EOL. */
 1444             if (px > xx) {
 1445                 if (py == yy)
 1446                     continue;
 1447                 gl = grid_get_line(s->grid, py);
 1448                 if (~gl->flags & GRID_LINE_WRAPPED)
 1449                     continue;
 1450                 if (gl->cellsize > s->grid->sx)
 1451                     continue;
 1452                 px = 0;
 1453                 py++;
 1454                 xx = window_copy_find_length(wme, py);
 1455             } else
 1456                 px++;
 1457             goto retry;
 1458         }
 1459         end = close[cp - open];
 1460 
 1461         /* Walk forward until the matching bracket is reached. */
 1462         n = 1;
 1463         failed = 0;
 1464         do {
 1465             if (px > xx) {
 1466                 if (py == yy) {
 1467                     failed = 1;
 1468                     break;
 1469                 }
 1470                 px = 0;
 1471                 py++;
 1472                 xx = window_copy_find_length(wme, py);
 1473             } else
 1474                 px++;
 1475 
 1476             grid_get_cell(s->grid, px, py, &gc);
 1477             if (gc.data.size == 1 &&
 1478                 (~gc.flags & GRID_FLAG_PADDING)) {
 1479                 if (*gc.data.data == found)
 1480                     n++;
 1481                 else if (*gc.data.data == end)
 1482                     n--;
 1483             }
 1484         } while (n != 0);
 1485 
 1486         /* Move the cursor to the found location if any. */
 1487         if (!failed)
 1488             window_copy_scroll_to(wme, px, py, 0);
 1489     }
 1490 
 1491     return (WINDOW_COPY_CMD_NOTHING);
 1492 }
 1493 
 1494 static enum window_copy_cmd_action
 1495 window_copy_cmd_next_paragraph(struct window_copy_cmd_state *cs)
 1496 {
 1497     struct window_mode_entry    *wme = cs->wme;
 1498     u_int                np = wme->prefix;
 1499 
 1500     for (; np != 0; np--)
 1501         window_copy_next_paragraph(wme);
 1502     return (WINDOW_COPY_CMD_NOTHING);
 1503 }
 1504 
 1505 static enum window_copy_cmd_action
 1506 window_copy_cmd_next_space(struct window_copy_cmd_state *cs)
 1507 {
 1508     struct window_mode_entry    *wme = cs->wme;
 1509     u_int                np = wme->prefix;
 1510 
 1511     for (; np != 0; np--)
 1512         window_copy_cursor_next_word(wme, " ");
 1513     return (WINDOW_COPY_CMD_NOTHING);
 1514 }
 1515 
 1516 static enum window_copy_cmd_action
 1517 window_copy_cmd_next_space_end(struct window_copy_cmd_state *cs)
 1518 {
 1519     struct window_mode_entry    *wme = cs->wme;
 1520     u_int                np = wme->prefix;
 1521 
 1522     for (; np != 0; np--)
 1523         window_copy_cursor_next_word_end(wme, " ", 0);
 1524     return (WINDOW_COPY_CMD_NOTHING);
 1525 }
 1526 
 1527 static enum window_copy_cmd_action
 1528 window_copy_cmd_next_word(struct window_copy_cmd_state *cs)
 1529 {
 1530     struct window_mode_entry    *wme = cs->wme;
 1531     struct session          *s = cs->s;
 1532     u_int                np = wme->prefix;
 1533     const char          *ws;
 1534 
 1535     ws = options_get_string(s->options, "word-separators");
 1536     for (; np != 0; np--)
 1537         window_copy_cursor_next_word(wme, ws);
 1538     return (WINDOW_COPY_CMD_NOTHING);
 1539 }
 1540 
 1541 static enum window_copy_cmd_action
 1542 window_copy_cmd_next_word_end(struct window_copy_cmd_state *cs)
 1543 {
 1544     struct window_mode_entry    *wme = cs->wme;
 1545     struct session          *s = cs->s;
 1546     u_int                np = wme->prefix;
 1547     const char          *ws;
 1548 
 1549     ws = options_get_string(s->options, "word-separators");
 1550     for (; np != 0; np--)
 1551         window_copy_cursor_next_word_end(wme, ws, 0);
 1552     return (WINDOW_COPY_CMD_NOTHING);
 1553 }
 1554 
 1555 static enum window_copy_cmd_action
 1556 window_copy_cmd_other_end(struct window_copy_cmd_state *cs)
 1557 {
 1558     struct window_mode_entry    *wme = cs->wme;
 1559     u_int                np = wme->prefix;
 1560     struct window_copy_mode_data    *data = wme->data;
 1561 
 1562     data->selflag = SEL_CHAR;
 1563     if ((np % 2) != 0)
 1564         window_copy_other_end(wme);
 1565     return (WINDOW_COPY_CMD_NOTHING);
 1566 }
 1567 
 1568 static enum window_copy_cmd_action
 1569 window_copy_cmd_page_down(struct window_copy_cmd_state *cs)
 1570 {
 1571     struct window_mode_entry    *wme = cs->wme;
 1572     struct window_copy_mode_data    *data = wme->data;
 1573     u_int                np = wme->prefix;
 1574 
 1575     for (; np != 0; np--) {
 1576         if (window_copy_pagedown(wme, 0, data->scroll_exit))
 1577             return (WINDOW_COPY_CMD_CANCEL);
 1578     }
 1579     return (WINDOW_COPY_CMD_NOTHING);
 1580 }
 1581 
 1582 static enum window_copy_cmd_action
 1583 window_copy_cmd_page_down_and_cancel(struct window_copy_cmd_state *cs)
 1584 {
 1585     struct window_mode_entry    *wme = cs->wme;
 1586     u_int                np = wme->prefix;
 1587 
 1588     for (; np != 0; np--) {
 1589         if (window_copy_pagedown(wme, 0, 1))
 1590             return (WINDOW_COPY_CMD_CANCEL);
 1591     }
 1592     return (WINDOW_COPY_CMD_NOTHING);
 1593 }
 1594 
 1595 static enum window_copy_cmd_action
 1596 window_copy_cmd_page_up(struct window_copy_cmd_state *cs)
 1597 {
 1598     struct window_mode_entry    *wme = cs->wme;
 1599     u_int                np = wme->prefix;
 1600 
 1601     for (; np != 0; np--)
 1602         window_copy_pageup1(wme, 0);
 1603     return (WINDOW_COPY_CMD_NOTHING);
 1604 }
 1605 
 1606 static enum window_copy_cmd_action
 1607 window_copy_cmd_previous_paragraph(struct window_copy_cmd_state *cs)
 1608 {
 1609     struct window_mode_entry    *wme = cs->wme;
 1610     u_int                np = wme->prefix;
 1611 
 1612     for (; np != 0; np--)
 1613         window_copy_previous_paragraph(wme);
 1614     return (WINDOW_COPY_CMD_NOTHING);
 1615 }
 1616 
 1617 static enum window_copy_cmd_action
 1618 window_copy_cmd_previous_space(struct window_copy_cmd_state *cs)
 1619 {
 1620     struct window_mode_entry    *wme = cs->wme;
 1621     u_int                np = wme->prefix;
 1622 
 1623     for (; np != 0; np--)
 1624         window_copy_cursor_previous_word(wme, " ", 1);
 1625     return (WINDOW_COPY_CMD_NOTHING);
 1626 }
 1627 
 1628 static enum window_copy_cmd_action
 1629 window_copy_cmd_previous_word(struct window_copy_cmd_state *cs)
 1630 {
 1631     struct window_mode_entry    *wme = cs->wme;
 1632     struct session          *s = cs->s;
 1633     u_int                np = wme->prefix;
 1634     const char          *ws;
 1635 
 1636     ws = options_get_string(s->options, "word-separators");
 1637     for (; np != 0; np--)
 1638         window_copy_cursor_previous_word(wme, ws, 1);
 1639     return (WINDOW_COPY_CMD_NOTHING);
 1640 }
 1641 
 1642 static enum window_copy_cmd_action
 1643 window_copy_cmd_rectangle_on(struct window_copy_cmd_state *cs)
 1644 {
 1645     struct window_mode_entry    *wme = cs->wme;
 1646     struct window_copy_mode_data    *data = wme->data;
 1647 
 1648     data->lineflag = LINE_SEL_NONE;
 1649     window_copy_rectangle_set(wme, 1);
 1650 
 1651     return (WINDOW_COPY_CMD_NOTHING);
 1652 }
 1653 
 1654 static enum window_copy_cmd_action
 1655 window_copy_cmd_rectangle_off(struct window_copy_cmd_state *cs)
 1656 {
 1657     struct window_mode_entry    *wme = cs->wme;
 1658     struct window_copy_mode_data    *data = wme->data;
 1659 
 1660     data->lineflag = LINE_SEL_NONE;
 1661     window_copy_rectangle_set(wme, 0);
 1662 
 1663     return (WINDOW_COPY_CMD_NOTHING);
 1664 }
 1665 
 1666 static enum window_copy_cmd_action
 1667 window_copy_cmd_rectangle_toggle(struct window_copy_cmd_state *cs)
 1668 {
 1669     struct window_mode_entry    *wme = cs->wme;
 1670     struct window_copy_mode_data    *data = wme->data;
 1671 
 1672     data->lineflag = LINE_SEL_NONE;
 1673     window_copy_rectangle_set(wme, !data->rectflag);
 1674 
 1675     return (WINDOW_COPY_CMD_NOTHING);
 1676 }
 1677 
 1678 static enum window_copy_cmd_action
 1679 window_copy_cmd_scroll_down(struct window_copy_cmd_state *cs)
 1680 {
 1681     struct window_mode_entry    *wme = cs->wme;
 1682     struct window_copy_mode_data    *data = wme->data;
 1683     u_int                np = wme->prefix;
 1684 
 1685     for (; np != 0; np--)
 1686         window_copy_cursor_down(wme, 1);
 1687     if (data->scroll_exit && data->oy == 0)
 1688         return (WINDOW_COPY_CMD_CANCEL);
 1689     return (WINDOW_COPY_CMD_NOTHING);
 1690 }
 1691 
 1692 static enum window_copy_cmd_action
 1693 window_copy_cmd_scroll_down_and_cancel(struct window_copy_cmd_state *cs)
 1694 {
 1695     struct window_mode_entry    *wme = cs->wme;
 1696     struct window_copy_mode_data    *data = wme->data;
 1697     u_int                np = wme->prefix;
 1698 
 1699     for (; np != 0; np--)
 1700         window_copy_cursor_down(wme, 1);
 1701     if (data->oy == 0)
 1702         return (WINDOW_COPY_CMD_CANCEL);
 1703     return (WINDOW_COPY_CMD_NOTHING);
 1704 }
 1705 
 1706 static enum window_copy_cmd_action
 1707 window_copy_cmd_scroll_up(struct window_copy_cmd_state *cs)
 1708 {
 1709     struct window_mode_entry    *wme = cs->wme;
 1710     u_int                np = wme->prefix;
 1711 
 1712     for (; np != 0; np--)
 1713         window_copy_cursor_up(wme, 1);
 1714     return (WINDOW_COPY_CMD_NOTHING);
 1715 }
 1716 
 1717 static enum window_copy_cmd_action
 1718 window_copy_cmd_search_again(struct window_copy_cmd_state *cs)
 1719 {
 1720     struct window_mode_entry    *wme = cs->wme;
 1721     struct window_copy_mode_data    *data = wme->data;
 1722     u_int                np = wme->prefix;
 1723 
 1724     if (data->searchtype == WINDOW_COPY_SEARCHUP) {
 1725         for (; np != 0; np--)
 1726             window_copy_search_up(wme, data->searchregex);
 1727     } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
 1728         for (; np != 0; np--)
 1729             window_copy_search_down(wme, data->searchregex);
 1730     }
 1731     return (WINDOW_COPY_CMD_NOTHING);
 1732 }
 1733 
 1734 static enum window_copy_cmd_action
 1735 window_copy_cmd_search_reverse(struct window_copy_cmd_state *cs)
 1736 {
 1737     struct window_mode_entry    *wme = cs->wme;
 1738     struct window_copy_mode_data    *data = wme->data;
 1739     u_int                np = wme->prefix;
 1740 
 1741     if (data->searchtype == WINDOW_COPY_SEARCHUP) {
 1742         for (; np != 0; np--)
 1743             window_copy_search_down(wme, data->searchregex);
 1744     } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
 1745         for (; np != 0; np--)
 1746             window_copy_search_up(wme, data->searchregex);
 1747     }
 1748     return (WINDOW_COPY_CMD_NOTHING);
 1749 }
 1750 
 1751 static enum window_copy_cmd_action
 1752 window_copy_cmd_select_line(struct window_copy_cmd_state *cs)
 1753 {
 1754     struct window_mode_entry    *wme = cs->wme;
 1755     struct window_copy_mode_data    *data = wme->data;
 1756     u_int                np = wme->prefix;
 1757 
 1758     data->lineflag = LINE_SEL_LEFT_RIGHT;
 1759     data->rectflag = 0;
 1760     data->selflag = SEL_LINE;
 1761     data->dx = data->cx;
 1762     data->dy = screen_hsize(data->backing) + data->cy - data->oy;
 1763 
 1764     window_copy_cursor_start_of_line(wme);
 1765     data->selrx = data->cx;
 1766     data->selry = screen_hsize(data->backing) + data->cy - data->oy;
 1767     data->endselry = data->selry;
 1768     window_copy_start_selection(wme);
 1769     window_copy_cursor_end_of_line(wme);
 1770     data->endselry = screen_hsize(data->backing) + data->cy - data->oy;
 1771     data->endselrx = window_copy_find_length(wme, data->endselry);
 1772     for (; np > 1; np--) {
 1773         window_copy_cursor_down(wme, 0);
 1774         window_copy_cursor_end_of_line(wme);
 1775     }
 1776 
 1777     return (WINDOW_COPY_CMD_REDRAW);
 1778 }
 1779 
 1780 static enum window_copy_cmd_action
 1781 window_copy_cmd_select_word(struct window_copy_cmd_state *cs)
 1782 {
 1783     struct window_mode_entry    *wme = cs->wme;
 1784     struct session          *s = cs->s;
 1785     struct window_copy_mode_data    *data = wme->data;
 1786     u_int                px, py, nextx, nexty;
 1787 
 1788     data->lineflag = LINE_SEL_LEFT_RIGHT;
 1789     data->rectflag = 0;
 1790     data->selflag = SEL_WORD;
 1791     data->dx = data->cx;
 1792     data->dy = screen_hsize(data->backing) + data->cy - data->oy;
 1793 
 1794     data->ws = options_get_string(s->options, "word-separators");
 1795     window_copy_cursor_previous_word(wme, data->ws, 0);
 1796     px = data->cx;
 1797     py = screen_hsize(data->backing) + data->cy - data->oy;
 1798     data->selrx = px;
 1799     data->selry = py;
 1800     window_copy_start_selection(wme);
 1801 
 1802     /* Handle single character words. */
 1803     nextx = px + 1;
 1804     nexty = py;
 1805     if (grid_get_line(data->backing->grid, nexty)->flags &
 1806         GRID_LINE_WRAPPED && nextx > screen_size_x(data->backing) - 1) {
 1807         nextx = 0;
 1808         nexty++;
 1809     }
 1810     if (px >= window_copy_find_length(wme, py) ||
 1811         !window_copy_in_set(wme, nextx, nexty, data->ws))
 1812         window_copy_cursor_next_word_end(wme, data->ws, 1);
 1813     else {
 1814         window_copy_update_cursor(wme, px, data->cy);
 1815         if (window_copy_update_selection(wme, 1, 1))
 1816             window_copy_redraw_lines(wme, data->cy, 1);
 1817     }
 1818     data->endselrx = data->cx;
 1819     data->endselry = screen_hsize(data->backing) + data->cy - data->oy;
 1820     if (data->dy > data->endselry) {
 1821         data->dy = data->endselry;
 1822         data->dx = data->endselrx;
 1823     } else if (data->dx > data->endselrx)
 1824         data->dx = data->endselrx;
 1825 
 1826     return (WINDOW_COPY_CMD_REDRAW);
 1827 }
 1828 
 1829 static enum window_copy_cmd_action
 1830 window_copy_cmd_set_mark(struct window_copy_cmd_state *cs)
 1831 {
 1832     struct window_copy_mode_data    *data = cs->wme->data;
 1833 
 1834     data->mx = data->cx;
 1835     data->my = screen_hsize(data->backing) + data->cy - data->oy;
 1836     data->showmark = 1;
 1837     return (WINDOW_COPY_CMD_REDRAW);
 1838 }
 1839 
 1840 static enum window_copy_cmd_action
 1841 window_copy_cmd_start_of_line(struct window_copy_cmd_state *cs)
 1842 {
 1843     struct window_mode_entry    *wme = cs->wme;
 1844 
 1845     window_copy_cursor_start_of_line(wme);
 1846     return (WINDOW_COPY_CMD_NOTHING);
 1847 }
 1848 
 1849 static enum window_copy_cmd_action
 1850 window_copy_cmd_top_line(struct window_copy_cmd_state *cs)
 1851 {
 1852     struct window_mode_entry    *wme = cs->wme;
 1853     struct window_copy_mode_data    *data = wme->data;
 1854 
 1855     data->cx = 0;
 1856     data->cy = 0;
 1857 
 1858     window_copy_update_selection(wme, 1, 0);
 1859     return (WINDOW_COPY_CMD_REDRAW);
 1860 }
 1861 
 1862 static enum window_copy_cmd_action
 1863 window_copy_cmd_copy_pipe_no_clear(struct window_copy_cmd_state *cs)
 1864 {
 1865     struct window_mode_entry    *wme = cs->wme;
 1866     struct client           *c = cs->c;
 1867     struct session          *s = cs->s;
 1868     struct winlink          *wl = cs->wl;
 1869     struct window_pane      *wp = wme->wp;
 1870     char                *command = NULL;
 1871     char                *prefix = NULL;
 1872 
 1873     if (cs->args->argc == 3)
 1874         prefix = format_single(NULL, cs->args->argv[2], c, s, wl, wp);
 1875 
 1876     if (s != NULL && cs->args->argc > 1 && *cs->args->argv[1] != '\0')
 1877         command = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
 1878     window_copy_copy_pipe(wme, s, prefix, command);
 1879     free(command);
 1880 
 1881     free(prefix);
 1882     return (WINDOW_COPY_CMD_NOTHING);
 1883 }
 1884 
 1885 static enum window_copy_cmd_action
 1886 window_copy_cmd_copy_pipe(struct window_copy_cmd_state *cs)
 1887 {
 1888     struct window_mode_entry    *wme = cs->wme;
 1889 
 1890     window_copy_cmd_copy_pipe_no_clear(cs);
 1891     window_copy_clear_selection(wme);
 1892     return (WINDOW_COPY_CMD_REDRAW);
 1893 }
 1894 
 1895 static enum window_copy_cmd_action
 1896 window_copy_cmd_copy_pipe_and_cancel(struct window_copy_cmd_state *cs)
 1897 {
 1898     struct window_mode_entry    *wme = cs->wme;
 1899 
 1900     window_copy_cmd_copy_pipe_no_clear(cs);
 1901     window_copy_clear_selection(wme);
 1902     return (WINDOW_COPY_CMD_CANCEL);
 1903 }
 1904 
 1905 static enum window_copy_cmd_action
 1906 window_copy_cmd_pipe_no_clear(struct window_copy_cmd_state *cs)
 1907 {
 1908     struct window_mode_entry    *wme = cs->wme;
 1909     struct client           *c = cs->c;
 1910     struct session          *s = cs->s;
 1911     struct winlink          *wl = cs->wl;
 1912     struct window_pane      *wp = wme->wp;
 1913     char                *command = NULL;
 1914 
 1915     if (s != NULL && cs->args->argc > 1 && *cs->args->argv[1] != '\0')
 1916         command = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
 1917     window_copy_pipe(wme, s, command);
 1918     free(command);
 1919 
 1920     return (WINDOW_COPY_CMD_NOTHING);
 1921 }
 1922 
 1923 static enum window_copy_cmd_action
 1924 window_copy_cmd_pipe(struct window_copy_cmd_state *cs)
 1925 {
 1926     struct window_mode_entry    *wme = cs->wme;
 1927 
 1928     window_copy_cmd_pipe_no_clear(cs);
 1929     window_copy_clear_selection(wme);
 1930     return (WINDOW_COPY_CMD_REDRAW);
 1931 }
 1932 
 1933 static enum window_copy_cmd_action
 1934 window_copy_cmd_pipe_and_cancel(struct window_copy_cmd_state *cs)
 1935 {
 1936     struct window_mode_entry    *wme = cs->wme;
 1937 
 1938     window_copy_cmd_pipe_no_clear(cs);
 1939     window_copy_clear_selection(wme);
 1940     return (WINDOW_COPY_CMD_CANCEL);
 1941 }
 1942 
 1943 static enum window_copy_cmd_action
 1944 window_copy_cmd_goto_line(struct window_copy_cmd_state *cs)
 1945 {
 1946     struct window_mode_entry    *wme = cs->wme;
 1947     const char          *argument = cs->args->argv[1];
 1948 
 1949     if (*argument != '\0')
 1950         window_copy_goto_line(wme, argument);
 1951     return (WINDOW_COPY_CMD_NOTHING);
 1952 }
 1953 
 1954 static enum window_copy_cmd_action
 1955 window_copy_cmd_jump_backward(struct window_copy_cmd_state *cs)
 1956 {
 1957     struct window_mode_entry    *wme = cs->wme;
 1958     struct window_copy_mode_data    *data = wme->data;
 1959     u_int                np = wme->prefix;
 1960     const char          *argument = cs->args->argv[1];
 1961 
 1962     if (*argument != '\0') {
 1963         data->jumptype = WINDOW_COPY_JUMPBACKWARD;
 1964         free(data->jumpchar);
 1965         data->jumpchar = utf8_fromcstr(argument);
 1966         for (; np != 0; np--)
 1967             window_copy_cursor_jump_back(wme);
 1968     }
 1969     return (WINDOW_COPY_CMD_NOTHING);
 1970 }
 1971 
 1972 static enum window_copy_cmd_action
 1973 window_copy_cmd_jump_forward(struct window_copy_cmd_state *cs)
 1974 {
 1975     struct window_mode_entry    *wme = cs->wme;
 1976     struct window_copy_mode_data    *data = wme->data;
 1977     u_int                np = wme->prefix;
 1978     const char          *argument = cs->args->argv[1];
 1979 
 1980     if (*argument != '\0') {
 1981         data->jumptype = WINDOW_COPY_JUMPFORWARD;
 1982         free(data->jumpchar);
 1983         data->jumpchar = utf8_fromcstr(argument);
 1984         for (; np != 0; np--)
 1985             window_copy_cursor_jump(wme);
 1986     }
 1987     return (WINDOW_COPY_CMD_NOTHING);
 1988 }
 1989 
 1990 static enum window_copy_cmd_action
 1991 window_copy_cmd_jump_to_backward(struct window_copy_cmd_state *cs)
 1992 {
 1993     struct window_mode_entry    *wme = cs->wme;
 1994     struct window_copy_mode_data    *data = wme->data;
 1995     u_int                np = wme->prefix;
 1996     const char          *argument = cs->args->argv[1];
 1997 
 1998     if (*argument != '\0') {
 1999         data->jumptype = WINDOW_COPY_JUMPTOBACKWARD;
 2000         free(data->jumpchar);
 2001         data->jumpchar = utf8_fromcstr(argument);
 2002         for (; np != 0; np--)
 2003             window_copy_cursor_jump_to_back(wme);
 2004     }
 2005     return (WINDOW_COPY_CMD_NOTHING);
 2006 }
 2007 
 2008 static enum window_copy_cmd_action
 2009 window_copy_cmd_jump_to_forward(struct window_copy_cmd_state *cs)
 2010 {
 2011     struct window_mode_entry    *wme = cs->wme;
 2012     struct window_copy_mode_data    *data = wme->data;
 2013     u_int                np = wme->prefix;
 2014     const char          *argument = cs->args->argv[1];
 2015 
 2016     if (*argument != '\0') {
 2017         data->jumptype = WINDOW_COPY_JUMPTOFORWARD;
 2018         free(data->jumpchar);
 2019         data->jumpchar = utf8_fromcstr(argument);
 2020         for (; np != 0; np--)
 2021             window_copy_cursor_jump_to(wme);
 2022     }
 2023     return (WINDOW_COPY_CMD_NOTHING);
 2024 }
 2025 
 2026 static enum window_copy_cmd_action
 2027 window_copy_cmd_jump_to_mark(struct window_copy_cmd_state *cs)
 2028 {
 2029     struct window_mode_entry    *wme = cs->wme;
 2030 
 2031     window_copy_jump_to_mark(wme);
 2032     return (WINDOW_COPY_CMD_NOTHING);
 2033 }
 2034 
 2035 static enum window_copy_cmd_action
 2036 window_copy_cmd_search_backward(struct window_copy_cmd_state *cs)
 2037 {
 2038     struct window_mode_entry    *wme = cs->wme;
 2039     struct window_copy_mode_data    *data = wme->data;
 2040     u_int                np = wme->prefix;
 2041 
 2042     if (!window_copy_expand_search_string(cs))
 2043         return (WINDOW_COPY_CMD_NOTHING);
 2044 
 2045     if (data->searchstr != NULL) {
 2046         data->searchtype = WINDOW_COPY_SEARCHUP;
 2047         data->searchregex = 1;
 2048         data->timeout = 0;
 2049         for (; np != 0; np--)
 2050             window_copy_search_up(wme, 1);
 2051     }
 2052     return (WINDOW_COPY_CMD_NOTHING);
 2053 }
 2054 
 2055 static enum window_copy_cmd_action
 2056 window_copy_cmd_search_backward_text(struct window_copy_cmd_state *cs)
 2057 {
 2058     struct window_mode_entry    *wme = cs->wme;
 2059     struct window_copy_mode_data    *data = wme->data;
 2060     u_int                np = wme->prefix;
 2061 
 2062     if (!window_copy_expand_search_string(cs))
 2063         return (WINDOW_COPY_CMD_NOTHING);
 2064 
 2065     if (data->searchstr != NULL) {
 2066         data->searchtype = WINDOW_COPY_SEARCHUP;
 2067         data->searchregex = 0;
 2068         data->timeout = 0;
 2069         for (; np != 0; np--)
 2070             window_copy_search_up(wme, 0);
 2071     }
 2072     return (WINDOW_COPY_CMD_NOTHING);
 2073 }
 2074 
 2075 static enum window_copy_cmd_action
 2076 window_copy_cmd_search_forward(struct window_copy_cmd_state *cs)
 2077 {
 2078     struct window_mode_entry    *wme = cs->wme;
 2079     struct window_copy_mode_data    *data = wme->data;
 2080     u_int                np = wme->prefix;
 2081 
 2082     if (!window_copy_expand_search_string(cs))
 2083         return (WINDOW_COPY_CMD_NOTHING);
 2084 
 2085     if (data->searchstr != NULL) {
 2086         data->searchtype = WINDOW_COPY_SEARCHDOWN;
 2087         data->searchregex = 1;
 2088         data->timeout = 0;
 2089         for (; np != 0; np--)
 2090             window_copy_search_down(wme, 1);
 2091     }
 2092     return (WINDOW_COPY_CMD_NOTHING);
 2093 }
 2094 
 2095 static enum window_copy_cmd_action
 2096 window_copy_cmd_search_forward_text(struct window_copy_cmd_state *cs)
 2097 {
 2098     struct window_mode_entry    *wme = cs->wme;
 2099     struct window_copy_mode_data    *data = wme->data;
 2100     u_int                np = wme->prefix;
 2101 
 2102     if (!window_copy_expand_search_string(cs))
 2103         return (WINDOW_COPY_CMD_NOTHING);
 2104 
 2105     if (data->searchstr != NULL) {
 2106         data->searchtype = WINDOW_COPY_SEARCHDOWN;
 2107         data->searchregex = 0;
 2108         data->timeout = 0;
 2109         for (; np != 0; np--)
 2110             window_copy_search_down(wme, 0);
 2111     }
 2112     return (WINDOW_COPY_CMD_NOTHING);
 2113 }
 2114 
 2115 static enum window_copy_cmd_action
 2116 window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs)
 2117 {
 2118     struct window_mode_entry    *wme = cs->wme;
 2119     struct window_copy_mode_data    *data = wme->data;
 2120     const char          *argument = cs->args->argv[1];
 2121     const char          *ss = data->searchstr;
 2122     char                 prefix;
 2123     enum window_copy_cmd_action  action = WINDOW_COPY_CMD_NOTHING;
 2124 
 2125     data->timeout = 0;
 2126 
 2127     log_debug ("%s: %s", __func__, argument);
 2128 
 2129     prefix = *argument++;
 2130     if (data->searchx == -1 || data->searchy == -1) {
 2131         data->searchx = data->cx;
 2132         data->searchy = data->cy;
 2133         data->searcho = data->oy;
 2134     } else if (ss != NULL && strcmp(argument, ss) != 0) {
 2135         data->cx = data->searchx;
 2136         data->cy = data->searchy;
 2137         data->oy = data->searcho;
 2138         action = WINDOW_COPY_CMD_REDRAW;
 2139     }
 2140     if (*argument == '\0') {
 2141         window_copy_clear_marks(wme);
 2142         return (WINDOW_COPY_CMD_REDRAW);
 2143     }
 2144     switch (prefix) {
 2145     case '=':
 2146     case '-':
 2147         data->searchtype = WINDOW_COPY_SEARCHUP;
 2148         data->searchregex = 0;
 2149         free(data->searchstr);
 2150         data->searchstr = xstrdup(argument);
 2151         if (!window_copy_search_up(wme, 0)) {
 2152             window_copy_clear_marks(wme);
 2153             return (WINDOW_COPY_CMD_REDRAW);
 2154         }
 2155         break;
 2156     case '+':
 2157         data->searchtype = WINDOW_COPY_SEARCHDOWN;
 2158         data->searchregex = 0;
 2159         free(data->searchstr);
 2160         data->searchstr = xstrdup(argument);
 2161         if (!window_copy_search_down(wme, 0)) {
 2162             window_copy_clear_marks(wme);
 2163             return (WINDOW_COPY_CMD_REDRAW);
 2164         }
 2165         break;
 2166     }
 2167     return (action);
 2168 }
 2169 
 2170 static enum window_copy_cmd_action
 2171 window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs)
 2172 {
 2173     struct window_mode_entry    *wme = cs->wme;
 2174     struct window_copy_mode_data    *data = wme->data;
 2175     const char          *argument = cs->args->argv[1];
 2176     const char          *ss = data->searchstr;
 2177     char                 prefix;
 2178     enum window_copy_cmd_action  action = WINDOW_COPY_CMD_NOTHING;
 2179 
 2180     data->timeout = 0;
 2181 
 2182     log_debug ("%s: %s", __func__, argument);
 2183 
 2184     prefix = *argument++;
 2185     if (data->searchx == -1 || data->searchy == -1) {
 2186         data->searchx = data->cx;
 2187         data->searchy = data->cy;
 2188         data->searcho = data->oy;
 2189     } else if (ss != NULL && strcmp(argument, ss) != 0) {
 2190         data->cx = data->searchx;
 2191         data->cy = data->searchy;
 2192         data->oy = data->searcho;
 2193         action = WINDOW_COPY_CMD_REDRAW;
 2194     }
 2195     if (*argument == '\0') {
 2196         window_copy_clear_marks(wme);
 2197         return (WINDOW_COPY_CMD_REDRAW);
 2198     }
 2199     switch (prefix) {
 2200     case '=':
 2201     case '+':
 2202         data->searchtype = WINDOW_COPY_SEARCHDOWN;
 2203         data->searchregex = 0;
 2204         free(data->searchstr);
 2205         data->searchstr = xstrdup(argument);
 2206         if (!window_copy_search_down(wme, 0)) {
 2207             window_copy_clear_marks(wme);
 2208             return (WINDOW_COPY_CMD_REDRAW);
 2209         }
 2210         break;
 2211     case '-':
 2212         data->searchtype = WINDOW_COPY_SEARCHUP;
 2213         data->searchregex = 0;
 2214         free(data->searchstr);
 2215         data->searchstr = xstrdup(argument);
 2216         if (!window_copy_search_up(wme, 0)) {
 2217             window_copy_clear_marks(wme);
 2218             return (WINDOW_COPY_CMD_REDRAW);
 2219         }
 2220     }
 2221     return (action);
 2222 }
 2223 
 2224 static enum window_copy_cmd_action
 2225 window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state *cs)
 2226 {
 2227     struct window_mode_entry    *wme = cs->wme;
 2228     struct window_pane      *wp = wme->swp;
 2229     struct window_copy_mode_data    *data = wme->data;
 2230 
 2231     if (data->viewmode)
 2232         return (WINDOW_COPY_CMD_NOTHING);
 2233 
 2234     screen_free(data->backing);
 2235     free(data->backing);
 2236     data->backing = window_copy_clone_screen(&wp->base, &data->screen, NULL,
 2237         NULL, wme->swp != wme->wp);
 2238 
 2239     window_copy_size_changed(wme);
 2240     return (WINDOW_COPY_CMD_REDRAW);
 2241 }
 2242 
 2243 static const struct {
 2244     const char           *command;
 2245     int               minargs;
 2246     int               maxargs;
 2247     enum window_copy_cmd_clear    clear;
 2248     enum window_copy_cmd_action (*f)(struct window_copy_cmd_state *);
 2249 } window_copy_cmd_table[] = {
 2250     { "append-selection", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2251       window_copy_cmd_append_selection },
 2252     { "append-selection-and-cancel", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2253       window_copy_cmd_append_selection_and_cancel },
 2254     { "back-to-indentation", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2255       window_copy_cmd_back_to_indentation },
 2256     { "begin-selection", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2257       window_copy_cmd_begin_selection },
 2258     { "bottom-line", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2259       window_copy_cmd_bottom_line },
 2260     { "cancel", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2261       window_copy_cmd_cancel },
 2262     { "clear-selection", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2263       window_copy_cmd_clear_selection },
 2264     { "copy-end-of-line", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2265       window_copy_cmd_copy_end_of_line },
 2266     { "copy-line", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2267       window_copy_cmd_copy_line },
 2268     { "copy-pipe-no-clear", 0, 2, WINDOW_COPY_CMD_CLEAR_NEVER,
 2269       window_copy_cmd_copy_pipe_no_clear },
 2270     { "copy-pipe", 0, 2, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2271       window_copy_cmd_copy_pipe },
 2272     { "copy-pipe-and-cancel", 0, 2, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2273       window_copy_cmd_copy_pipe_and_cancel },
 2274     { "copy-selection-no-clear", 0, 1, WINDOW_COPY_CMD_CLEAR_NEVER,
 2275       window_copy_cmd_copy_selection_no_clear },
 2276     { "copy-selection", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2277       window_copy_cmd_copy_selection },
 2278     { "copy-selection-and-cancel", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2279       window_copy_cmd_copy_selection_and_cancel },
 2280     { "cursor-down", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2281       window_copy_cmd_cursor_down },
 2282     { "cursor-down-and-cancel", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2283       window_copy_cmd_cursor_down_and_cancel },
 2284     { "cursor-left", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2285       window_copy_cmd_cursor_left },
 2286     { "cursor-right", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2287       window_copy_cmd_cursor_right },
 2288     { "cursor-up", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2289       window_copy_cmd_cursor_up },
 2290     { "end-of-line", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2291       window_copy_cmd_end_of_line },
 2292     { "goto-line", 1, 1, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2293       window_copy_cmd_goto_line },
 2294     { "halfpage-down", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2295       window_copy_cmd_halfpage_down },
 2296     { "halfpage-down-and-cancel", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2297       window_copy_cmd_halfpage_down_and_cancel },
 2298     { "halfpage-up", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2299       window_copy_cmd_halfpage_up },
 2300     { "history-bottom", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2301       window_copy_cmd_history_bottom },
 2302     { "history-top", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2303       window_copy_cmd_history_top },
 2304     { "jump-again", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2305       window_copy_cmd_jump_again },
 2306     { "jump-backward", 1, 1, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2307       window_copy_cmd_jump_backward },
 2308     { "jump-forward", 1, 1, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2309       window_copy_cmd_jump_forward },
 2310     { "jump-reverse", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2311       window_copy_cmd_jump_reverse },
 2312     { "jump-to-backward", 1, 1, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2313       window_copy_cmd_jump_to_backward },
 2314     { "jump-to-forward", 1, 1, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2315       window_copy_cmd_jump_to_forward },
 2316     { "jump-to-mark", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2317       window_copy_cmd_jump_to_mark },
 2318     { "middle-line", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2319       window_copy_cmd_middle_line },
 2320     { "next-matching-bracket", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2321       window_copy_cmd_next_matching_bracket },
 2322     { "next-paragraph", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2323       window_copy_cmd_next_paragraph },
 2324     { "next-space", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2325       window_copy_cmd_next_space },
 2326     { "next-space-end", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2327       window_copy_cmd_next_space_end },
 2328     { "next-word", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2329       window_copy_cmd_next_word },
 2330     { "next-word-end", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2331       window_copy_cmd_next_word_end },
 2332     { "other-end", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2333       window_copy_cmd_other_end },
 2334     { "page-down", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2335       window_copy_cmd_page_down },
 2336     { "page-down-and-cancel", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2337       window_copy_cmd_page_down_and_cancel },
 2338     { "page-up", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2339       window_copy_cmd_page_up },
 2340     { "pipe-no-clear", 0, 1, WINDOW_COPY_CMD_CLEAR_NEVER,
 2341       window_copy_cmd_pipe_no_clear },
 2342     { "pipe", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2343       window_copy_cmd_pipe },
 2344     { "pipe-and-cancel", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2345       window_copy_cmd_pipe_and_cancel },
 2346     { "previous-matching-bracket", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2347       window_copy_cmd_previous_matching_bracket },
 2348     { "previous-paragraph", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2349       window_copy_cmd_previous_paragraph },
 2350     { "previous-space", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2351       window_copy_cmd_previous_space },
 2352     { "previous-word", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2353       window_copy_cmd_previous_word },
 2354     { "rectangle-on", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2355       window_copy_cmd_rectangle_on },
 2356     { "rectangle-off", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2357       window_copy_cmd_rectangle_off },
 2358     { "rectangle-toggle", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2359       window_copy_cmd_rectangle_toggle },
 2360     { "refresh-from-pane", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2361       window_copy_cmd_refresh_from_pane },
 2362     { "scroll-down", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2363       window_copy_cmd_scroll_down },
 2364     { "scroll-down-and-cancel", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2365       window_copy_cmd_scroll_down_and_cancel },
 2366     { "scroll-up", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2367       window_copy_cmd_scroll_up },
 2368     { "search-again", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2369       window_copy_cmd_search_again },
 2370     { "search-backward", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2371       window_copy_cmd_search_backward },
 2372     { "search-backward-text", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2373       window_copy_cmd_search_backward_text },
 2374     { "search-backward-incremental", 1, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2375       window_copy_cmd_search_backward_incremental },
 2376     { "search-forward", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2377       window_copy_cmd_search_forward },
 2378     { "search-forward-text", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2379       window_copy_cmd_search_forward_text },
 2380     { "search-forward-incremental", 1, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2381       window_copy_cmd_search_forward_incremental },
 2382     { "search-reverse", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2383       window_copy_cmd_search_reverse },
 2384     { "select-line", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2385       window_copy_cmd_select_line },
 2386     { "select-word", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2387       window_copy_cmd_select_word },
 2388     { "set-mark", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2389       window_copy_cmd_set_mark },
 2390     { "start-of-line", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2391       window_copy_cmd_start_of_line },
 2392     { "stop-selection", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
 2393       window_copy_cmd_stop_selection },
 2394     { "top-line", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
 2395       window_copy_cmd_top_line },
 2396 };
 2397 
 2398 static void
 2399 window_copy_command(struct window_mode_entry *wme, struct client *c,
 2400     struct session *s, struct winlink *wl, struct args *args,
 2401     struct mouse_event *m)
 2402 {
 2403     struct window_copy_mode_data    *data = wme->data;
 2404     struct window_copy_cmd_state     cs;
 2405     enum window_copy_cmd_action  action;
 2406     enum window_copy_cmd_clear   clear = WINDOW_COPY_CMD_CLEAR_NEVER;
 2407     const char          *command;
 2408     u_int                i;
 2409     int              keys;
 2410 
 2411     if (args->argc == 0)
 2412         return;
 2413     command = args->argv[0];
 2414 
 2415     if (m != NULL && m->valid && !MOUSE_WHEEL(m->b))
 2416         window_copy_move_mouse(m);
 2417 
 2418     cs.wme = wme;
 2419     cs.args = args;
 2420     cs.m = m;
 2421 
 2422     cs.c = c;
 2423     cs.s = s;
 2424     cs.wl = wl;
 2425 
 2426     action = WINDOW_COPY_CMD_NOTHING;
 2427     for (i = 0; i < nitems(window_copy_cmd_table); i++) {
 2428         if (strcmp(window_copy_cmd_table[i].command, command) == 0) {
 2429             if (args->argc - 1 < window_copy_cmd_table[i].minargs ||
 2430                 args->argc - 1 > window_copy_cmd_table[i].maxargs)
 2431                 break;
 2432             clear = window_copy_cmd_table[i].clear;
 2433             action = window_copy_cmd_table[i].f (&cs);
 2434             break;
 2435         }
 2436     }
 2437 
 2438     if (strncmp(command, "search-", 7) != 0 && data->searchmark != NULL) {
 2439         keys = options_get_number(wme->wp->window->options, "mode-keys");
 2440         if (clear == WINDOW_COPY_CMD_CLEAR_EMACS_ONLY &&
 2441             keys == MODEKEY_VI)
 2442             clear = WINDOW_COPY_CMD_CLEAR_NEVER;
 2443         if (clear != WINDOW_COPY_CMD_CLEAR_NEVER) {
 2444             window_copy_clear_marks(wme);
 2445             data->searchx = data->searchy = -1;
 2446         }
 2447         if (action == WINDOW_COPY_CMD_NOTHING)
 2448             action = WINDOW_COPY_CMD_REDRAW;
 2449     }
 2450     wme->prefix = 1;
 2451 
 2452     if (action == WINDOW_COPY_CMD_CANCEL)
 2453         window_pane_reset_mode(wme->wp);
 2454     else if (action == WINDOW_COPY_CMD_REDRAW)
 2455         window_copy_redraw_screen(wme);
 2456 }
 2457 
 2458 static void
 2459 window_copy_scroll_to(struct window_mode_entry *wme, u_int px, u_int py,
 2460     int no_redraw)
 2461 {
 2462     struct window_copy_mode_data    *data = wme->data;
 2463     struct grid         *gd = data->backing->grid;
 2464     u_int                offset, gap;
 2465 
 2466     data->cx = px;
 2467 
 2468     if (py >= gd->hsize - data->oy && py < gd->hsize - data->oy + gd->sy)
 2469         data->cy = py - (gd->hsize - data->oy);
 2470     else {
 2471         gap = gd->sy / 4;
 2472         if (py < gd->sy) {
 2473             offset = 0;
 2474             data->cy = py;
 2475         } else if (py > gd->hsize + gd->sy - gap) {
 2476             offset = gd->hsize;
 2477             data->cy = py - gd->hsize;
 2478         } else {
 2479             offset = py + gap - gd->sy;
 2480             data->cy = py - offset;
 2481         }
 2482         data->oy = gd->hsize - offset;
 2483     }
 2484 
 2485     if (!no_redraw && data->searchmark != NULL && !data->timeout)
 2486         window_copy_search_marks(wme, NULL, data->searchregex, 1);
 2487     window_copy_update_selection(wme, 1, 0);
 2488     if (!no_redraw)
 2489         window_copy_redraw_screen(wme);
 2490 }
 2491 
 2492 static int
 2493 window_copy_search_compare(struct grid *gd, u_int px, u_int py,
 2494     struct grid *sgd, u_int spx, int cis)
 2495 {
 2496     struct grid_cell     gc, sgc;
 2497     const struct utf8_data  *ud, *sud;
 2498 
 2499     grid_get_cell(gd, px, py, &gc);
 2500     ud = &gc.data;
 2501     grid_get_cell(sgd, spx, 0, &sgc);
 2502     sud = &sgc.data;
 2503 
 2504     if (ud->size != sud->size || ud->width != sud->width)
 2505         return (0);
 2506 
 2507     if (cis && ud->size == 1)
 2508         return (tolower(ud->data[0]) == sud->data[0]);
 2509 
 2510     return (memcmp(ud->data, sud->data, ud->size) == 0);
 2511 }
 2512 
 2513 static int
 2514 window_copy_search_lr(struct grid *gd, struct grid *sgd, u_int *ppx, u_int py,
 2515     u_int first, u_int last, int cis)
 2516 {
 2517     u_int            ax, bx, px, pywrap, endline;
 2518     int          matched;
 2519     struct grid_line    *gl;
 2520 
 2521     endline = gd->hsize + gd->sy - 1;
 2522     for (ax = first; ax < last; ax++) {
 2523         for (bx = 0; bx < sgd->sx; bx++) {
 2524             px = ax + bx;
 2525             pywrap = py;
 2526             /* Wrap line. */
 2527             while (px >= gd->sx && pywrap < endline) {
 2528                 gl = grid_get_line(gd, pywrap);
 2529                 if (~gl->flags & GRID_LINE_WRAPPED)
 2530                     break;
 2531                 px -= gd->sx;
 2532                 pywrap++;
 2533             }
 2534             /* We have run off the end of the grid. */
 2535             if (px >= gd->sx)
 2536                 break;
 2537             matched = window_copy_search_compare(gd, px, pywrap,
 2538                 sgd, bx, cis);
 2539             if (!matched)
 2540                 break;
 2541         }
 2542         if (bx == sgd->sx) {
 2543             *ppx = ax;
 2544             return (1);
 2545         }
 2546     }
 2547     return (0);
 2548 }
 2549 
 2550 static int
 2551 window_copy_search_rl(struct grid *gd,
 2552     struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
 2553 {
 2554     u_int            ax, bx, px, pywrap, endline;
 2555     int          matched;
 2556     struct grid_line    *gl;
 2557 
 2558     endline = gd->hsize + gd->sy - 1;
 2559     for (ax = last; ax > first; ax--) {
 2560         for (bx = 0; bx < sgd->sx; bx++) {
 2561             px = ax - 1 + bx;
 2562             pywrap = py;
 2563             /* Wrap line. */
 2564             while (px >= gd->sx && pywrap < endline) {
 2565                 gl = grid_get_line(gd, pywrap);
 2566                 if (~gl->flags & GRID_LINE_WRAPPED)
 2567                     break;
 2568                 px -= gd->sx;
 2569                 pywrap++;
 2570             }
 2571             /* We have run off the end of the grid. */
 2572             if (px >= gd->sx)
 2573                 break;
 2574             matched = window_copy_search_compare(gd, px, pywrap,
 2575                 sgd, bx, cis);
 2576             if (!matched)
 2577                 break;
 2578         }
 2579         if (bx == sgd->sx) {
 2580             *ppx = ax - 1;
 2581             return (1);
 2582         }
 2583     }
 2584     return (0);
 2585 }
 2586 
 2587 static int
 2588 window_copy_search_lr_regex(struct grid *gd, u_int *ppx, u_int *psx, u_int py,
 2589     u_int first, u_int last, regex_t *reg)
 2590 {
 2591     int         eflags = 0;
 2592     u_int           endline, foundx, foundy, len, pywrap, size = 1;
 2593     char               *buf;
 2594     regmatch_t      regmatch;
 2595     struct grid_line       *gl;
 2596 
 2597     /*
 2598      * This can happen during search if the last match was the last
 2599      * character on a line.
 2600      */
 2601     if (first >= last)
 2602         return (0);
 2603 
 2604     /* Set flags for regex search. */
 2605     if (first != 0)
 2606         eflags |= REG_NOTBOL;
 2607 
 2608     /* Need to look at the entire string. */
 2609     buf = xmalloc(size);
 2610     buf[0] = '\0';
 2611     buf = window_copy_stringify(gd, py, first, gd->sx, buf, &size);
 2612     len = gd->sx - first;
 2613     endline = gd->hsize + gd->sy - 1;
 2614     pywrap = py;
 2615     while (buf != NULL && pywrap <= endline) {
 2616         gl = grid_get_line(gd, pywrap);
 2617         if (~gl->flags & GRID_LINE_WRAPPED)
 2618             break;
 2619         pywrap++;
 2620         buf = window_copy_stringify(gd, pywrap, 0, gd->sx, buf, &size);
 2621         len += gd->sx;
 2622     }
 2623 
 2624     if (regexec(reg, buf, 1, &regmatch, eflags) == 0 &&
 2625         regmatch.rm_so != regmatch.rm_eo) {
 2626         foundx = first;
 2627         foundy = py;
 2628         window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
 2629             buf + regmatch.rm_so);
 2630         if (foundy == py && foundx < last) {
 2631             *ppx = foundx;
 2632             len -= foundx - first;
 2633             window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
 2634                 buf + regmatch.rm_eo);
 2635             *psx = foundx;
 2636             while (foundy > py) {
 2637                 *psx += gd->sx;
 2638                 foundy--;
 2639             }
 2640             *psx -= *ppx;
 2641             free(buf);
 2642             return (1);
 2643         }
 2644     }
 2645 
 2646     free(buf);
 2647     *ppx = 0;
 2648     *psx = 0;
 2649     return (0);
 2650 }
 2651 
 2652 static int
 2653 window_copy_search_rl_regex(struct grid *gd, u_int *ppx, u_int *psx, u_int py,
 2654     u_int first, u_int last, regex_t *reg)
 2655 {
 2656     int         eflags = 0;
 2657     u_int           endline, len, pywrap, size = 1;
 2658     char               *buf;
 2659     struct grid_line       *gl;
 2660 
 2661     /* Set flags for regex search. */
 2662     if (first != 0)
 2663         eflags |= REG_NOTBOL;
 2664 
 2665     /* Need to look at the entire string. */
 2666     buf = xmalloc(size);
 2667     buf[0] = '\0';
 2668     buf = window_copy_stringify(gd, py, first, gd->sx, buf, &size);
 2669     len = gd->sx - first;
 2670     endline = gd->hsize + gd->sy - 1;
 2671     pywrap = py;
 2672     while (buf != NULL && (pywrap <= endline)) {
 2673         gl = grid_get_line(gd, pywrap);
 2674         if (~gl->flags & GRID_LINE_WRAPPED)
 2675             break;
 2676         pywrap++;
 2677         buf = window_copy_stringify(gd, pywrap, 0, gd->sx, buf, &size);
 2678         len += gd->sx;
 2679     }
 2680 
 2681     if (window_copy_last_regex(gd, py, first, last, len, ppx, psx, buf,
 2682         reg, eflags))
 2683     {
 2684         free(buf);
 2685         return (1);
 2686     }
 2687 
 2688     free(buf);
 2689     *ppx = 0;
 2690     *psx = 0;
 2691     return (0);
 2692 }
 2693 
 2694 static const char *
 2695 window_copy_cellstring(const struct grid_line *gl, u_int px, size_t *size,
 2696     int *allocated)
 2697 {
 2698     static struct utf8_data  ud;
 2699     struct grid_cell_entry  *gce;
 2700     char            *copy;
 2701 
 2702     if (px >= gl->cellsize) {
 2703         *size = 1;
 2704         *allocated = 0;
 2705         return (" ");
 2706     }
 2707 
 2708     gce = &gl->celldata[px];
 2709     if (gce->flags & GRID_FLAG_PADDING) {
 2710         *size = 0;
 2711         *allocated = 0;
 2712         return (NULL);
 2713     }
 2714     if (~gce->flags & GRID_FLAG_EXTENDED) {
 2715         *size = 1;
 2716         *allocated = 0;
 2717         return (&gce->data.data);
 2718     }
 2719 
 2720     utf8_to_data(gl->extddata[gce->offset].data, &ud);
 2721     *size = ud.size;
 2722     *allocated = 1;
 2723 
 2724     copy = xmalloc(ud.size);
 2725     memcpy(copy, ud.data, ud.size);
 2726     return (copy);
 2727 }
 2728 
 2729 /* Find last match in given range. */
 2730 static int
 2731 window_copy_last_regex(struct grid *gd, u_int py, u_int first, u_int last,
 2732     u_int len, u_int *ppx, u_int *psx, const char *buf, const regex_t *preg,
 2733     int eflags)
 2734 {
 2735     u_int       foundx, foundy, oldx, px = 0, savepx, savesx = 0;
 2736     regmatch_t  regmatch;
 2737 
 2738     foundx = first;
 2739     foundy = py;
 2740     oldx = first;
 2741     while (regexec(preg, buf + px, 1, &regmatch, eflags) == 0) {
 2742         if (regmatch.rm_so == regmatch.rm_eo)
 2743             break;
 2744         window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
 2745             buf + px + regmatch.rm_so);
 2746         if (foundy > py || foundx >= last)
 2747             break;
 2748         len -= foundx - oldx;
 2749         savepx = foundx;
 2750         window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
 2751             buf + px + regmatch.rm_eo);
 2752         if (foundy > py || foundx >= last) {
 2753             *ppx = savepx;
 2754             *psx = foundx;
 2755             while (foundy > py) {
 2756                 *psx += gd->sx;
 2757                 foundy--;
 2758             }
 2759             *psx -= *ppx;
 2760             return (1);
 2761         } else {
 2762             savesx = foundx - savepx;
 2763             len -= savesx;
 2764             oldx = foundx;
 2765         }
 2766         px += regmatch.rm_eo;
 2767     }
 2768 
 2769     if (savesx > 0) {
 2770         *ppx = savepx;
 2771         *psx = savesx;
 2772         return (1);
 2773     } else {
 2774         *ppx = 0;
 2775         *psx = 0;
 2776         return (0);
 2777     }
 2778 }
 2779 
 2780 /* Stringify line and append to input buffer. Caller frees. */
 2781 static char *
 2782 window_copy_stringify(struct grid *gd, u_int py, u_int first, u_int last,
 2783     char *buf, u_int *size)
 2784 {
 2785     u_int            ax, bx, newsize = *size;
 2786     const struct grid_line  *gl;
 2787     const char      *d;
 2788     size_t           bufsize = 1024, dlen;
 2789     int          allocated;
 2790 
 2791     while (bufsize < newsize)
 2792         bufsize *= 2;
 2793     buf = xrealloc(buf, bufsize);
 2794 
 2795     gl = grid_peek_line(gd, py);
 2796     bx = *size - 1;
 2797     for (ax = first; ax < last; ax++) {
 2798         d = window_copy_cellstring(gl, ax, &dlen, &allocated);
 2799         newsize += dlen;
 2800         while (bufsize < newsize) {
 2801             bufsize *= 2;
 2802             buf = xrealloc(buf, bufsize);
 2803         }
 2804         if (dlen == 1)
 2805             buf[bx++] = *d;
 2806         else {
 2807             memcpy(buf + bx, d, dlen);
 2808             bx += dlen;
 2809         }
 2810         if (allocated)
 2811             free((void *)d);
 2812     }
 2813     buf[newsize - 1] = '\0';
 2814 
 2815     *size = newsize;
 2816     return (buf);
 2817 }
 2818 
 2819 /* Map start of C string containing UTF-8 data to grid cell position. */
 2820 static void
 2821 window_copy_cstrtocellpos(struct grid *gd, u_int ncells, u_int *ppx, u_int *ppy,
 2822     const char *str)
 2823 {
 2824     u_int            cell, ccell, px, pywrap, pos, len;
 2825     int          match;
 2826     const struct grid_line  *gl;
 2827     const char      *d;
 2828     size_t           dlen;
 2829     struct {
 2830         const char  *d;
 2831         size_t       dlen;
 2832         int      allocated;
 2833     } *cells;
 2834 
 2835     /* Populate the array of cell data. */
 2836     cells = xreallocarray(NULL, ncells, sizeof cells[0]);
 2837     cell = 0;
 2838     px = *ppx;
 2839     pywrap = *ppy;
 2840     gl = grid_peek_line(gd, pywrap);
 2841     while (cell < ncells) {
 2842         cells[cell].d = window_copy_cellstring(gl, px,
 2843             &cells[cell].dlen, &cells[cell].allocated);
 2844         cell++;
 2845         px++;
 2846         if (px == gd->sx) {
 2847             px = 0;
 2848             pywrap++;
 2849             gl = grid_peek_line(gd, pywrap);
 2850         }
 2851     }
 2852 
 2853     /* Locate starting cell. */
 2854     cell = 0;
 2855     len = strlen(str);
 2856     while (cell < ncells) {
 2857         ccell = cell;
 2858         pos = 0;
 2859         match = 1;
 2860         while (ccell < ncells) {
 2861             if (str[pos] == '\0') {
 2862                 match = 0;
 2863                 break;
 2864             }
 2865             d = cells[ccell].d;
 2866             dlen = cells[ccell].dlen;
 2867             if (dlen == 1) {
 2868                 if (str[pos] != *d) {
 2869                     match = 0;
 2870                     break;
 2871                 }
 2872                 pos++;
 2873             } else {
 2874                 if (dlen > len - pos)
 2875                     dlen = len - pos;
 2876                 if (memcmp(str + pos, d, dlen) != 0) {
 2877                     match = 0;
 2878                     break;
 2879                 }
 2880                 pos += dlen;
 2881             }
 2882             ccell++;
 2883         }
 2884         if (match)
 2885             break;
 2886         cell++;
 2887     }
 2888 
 2889     /* If not found this will be one past the end. */
 2890     px = *ppx + cell;
 2891     pywrap = *ppy;
 2892     while (px >= gd->sx) {
 2893         px -= gd->sx;
 2894         pywrap++;
 2895     }
 2896 
 2897     *ppx = px;
 2898     *ppy = pywrap;
 2899 
 2900     /* Free cell data. */
 2901     for (cell = 0; cell < ncells; cell++) {
 2902         if (cells[cell].allocated)
 2903             free((void *)cells[cell].d);
 2904     }
 2905     free(cells);
 2906 }
 2907 
 2908 static void
 2909 window_copy_move_left(struct screen *s, u_int *fx, u_int *fy, int wrapflag)
 2910 {
 2911     if (*fx == 0) { /* left */
 2912         if (*fy == 0) { /* top */
 2913             if (wrapflag) {
 2914                 *fx = screen_size_x(s) - 1;
 2915                 *fy = screen_hsize(s) + screen_size_y(s) - 1;
 2916             }
 2917             return;
 2918         }
 2919         *fx = screen_size_x(s) - 1;
 2920         *fy = *fy - 1;
 2921     } else
 2922         *fx = *fx - 1;
 2923 }
 2924 
 2925 static void
 2926 window_copy_move_right(struct screen *s, u_int *fx, u_int *fy, int wrapflag)
 2927 {
 2928     if (*fx == screen_size_x(s) - 1) { /* right */
 2929         if (*fy == screen_hsize(s) + screen_size_y(s) - 1) { /* bottom */
 2930             if (wrapflag) {
 2931                 *fx = 0;
 2932                 *fy = 0;
 2933             }
 2934             return;
 2935         }
 2936         *fx = 0;
 2937         *fy = *fy + 1;
 2938     } else
 2939         *fx = *fx + 1;
 2940 }
 2941 
 2942 static int
 2943 window_copy_is_lowercase(const char *ptr)
 2944 {
 2945     while (*ptr != '\0') {
 2946         if (*ptr != tolower((u_char)*ptr))
 2947             return (0);
 2948         ++ptr;
 2949     }
 2950     return (1);
 2951 }
 2952 
 2953 /*
 2954  * Handle backward wrapped regex searches with overlapping matches. In this case
 2955  * find the longest overlapping match from previous wrapped lines.
 2956  */
 2957 static void
 2958 window_copy_search_back_overlap(struct grid *gd, regex_t *preg, u_int *ppx,
 2959     u_int *psx, u_int *ppy, u_int endline)
 2960 {
 2961     u_int   endx, endy, oldendx, oldendy, px, py, sx;
 2962     int found = 1;
 2963 
 2964     oldendx = *ppx + *psx;
 2965     oldendy = *ppy - 1;
 2966     while (oldendx > gd->sx - 1) {
 2967         oldendx -= gd->sx;
 2968         oldendy++;
 2969     }
 2970     endx = oldendx;
 2971     endy = oldendy;
 2972     px = *ppx;
 2973     py = *ppy;
 2974     while (found && px == 0 && py - 1 > endline &&
 2975            grid_get_line(gd, py - 2)->flags & GRID_LINE_WRAPPED &&
 2976            endx == oldendx && endy == oldendy) {
 2977         py--;
 2978         found = window_copy_search_rl_regex(gd, &px, &sx, py - 1, 0,
 2979             gd->sx, preg);
 2980         if (found) {
 2981             endx = px + sx;
 2982             endy = py - 1;
 2983             while (endx > gd->sx - 1) {
 2984                 endx -= gd->sx;
 2985                 endy++;
 2986             }
 2987             if (endx == oldendx && endy == oldendy) {
 2988                 *ppx = px;
 2989                 *ppy = py;
 2990             }
 2991         }
 2992     }
 2993 }
 2994 
 2995 /*
 2996  * Search for text stored in sgd starting from position fx,fy up to endline. If
 2997  * found, jump to it. If cis then ignore case. The direction is 0 for searching
 2998  * up, down otherwise. If wrap then go to begin/end of grid and try again if
 2999  * not found.
 3000  */
 3001 static int
 3002 window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
 3003     struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap,
 3004     int direction, int regex)
 3005 {
 3006     u_int    i, px, sx, ssize = 1;
 3007     int  found = 0, cflags = REG_EXTENDED;
 3008     char    *sbuf;
 3009     regex_t  reg;
 3010 
 3011     if (regex) {
 3012         sbuf = xmalloc(ssize);
 3013         sbuf[0] = '\0';
 3014         sbuf = window_copy_stringify(sgd, 0, 0, sgd->sx, sbuf, &ssize);
 3015         if (cis)
 3016             cflags |= REG_ICASE;
 3017         if (regcomp(&reg, sbuf, cflags) != 0) {
 3018             free(sbuf);
 3019             return (0);
 3020         }
 3021         free(sbuf);
 3022     }
 3023 
 3024     if (direction) {
 3025         for (i = fy; i <= endline; i++) {
 3026             if (regex) {
 3027                 found = window_copy_search_lr_regex(gd,
 3028                     &px, &sx, i, fx, gd->sx, &reg);
 3029             } else {
 3030                 found = window_copy_search_lr(gd, sgd,
 3031                     &px, i, fx, gd->sx, cis);
 3032             }
 3033             if (found)
 3034                 break;
 3035             fx = 0;
 3036         }
 3037     } else {
 3038         for (i = fy + 1; endline < i; i--) {
 3039             if (regex) {
 3040                 found = window_copy_search_rl_regex(gd,
 3041                     &px, &sx, i - 1, 0, fx + 1, &reg);
 3042                 if (found) {
 3043                     window_copy_search_back_overlap(gd,
 3044                         &reg, &px, &sx, &i, endline);
 3045                 }
 3046             } else {
 3047                 found = window_copy_search_rl(gd, sgd,
 3048                     &px, i - 1, 0, fx + 1, cis);
 3049             }
 3050             if (found) {
 3051                 i--;
 3052                 break;
 3053             }
 3054             fx = gd->sx - 1;
 3055         }
 3056     }
 3057     if (regex)
 3058         regfree(&reg);
 3059 
 3060     if (found) {
 3061         window_copy_scroll_to(wme, px, i, 1);
 3062         return (1);
 3063     }
 3064     if (wrap) {
 3065         return (window_copy_search_jump(wme, gd, sgd,
 3066             direction ? 0 : gd->sx - 1,
 3067             direction ? 0 : gd->hsize + gd->sy - 1, fy, cis, 0,
 3068             direction, regex));
 3069     }
 3070     return (0);
 3071 }
 3072 
 3073 static void
 3074 window_copy_move_after_search_mark(struct window_copy_mode_data *data,
 3075     u_int *fx, u_int *fy, int wrapflag)
 3076 {
 3077     struct screen  *s = data->backing;
 3078     u_int       at, start;
 3079 
 3080     if (window_copy_search_mark_at(data, *fx, *fy, &start) == 0 &&
 3081         data->searchmark[start] != 0) {
 3082         while (window_copy_search_mark_at(data, *fx, *fy, &at) == 0) {
 3083             if (data->searchmark[at] != data->searchmark[start])
 3084                 break;
 3085             /* Stop if not wrapping and at the end of the grid. */
 3086             if (!wrapflag &&
 3087                 *fx == screen_size_x(s) - 1 &&
 3088                 *fy == screen_hsize(s) + screen_size_y(s) - 1)
 3089                 break;
 3090 
 3091             window_copy_move_right(s, fx, fy, wrapflag);
 3092         }
 3093     }
 3094 }
 3095 
 3096 /*
 3097  * Search in for text searchstr. If direction is 0 then search up, otherwise
 3098  * down.
 3099  */
 3100 static int
 3101 window_copy_search(struct window_mode_entry *wme, int direction, int regex)
 3102 {
 3103     struct window_pane      *wp = wme->wp;
 3104     struct window_copy_mode_data    *data = wme->data;
 3105     struct screen           *s = data->backing, ss;
 3106     struct screen_write_ctx      ctx;
 3107     struct grid         *gd = s->grid;
 3108     const char          *str = data->searchstr;
 3109     u_int                at, endline, fx, fy, start;
 3110     int              cis, found, keys, visible_only;
 3111     int              wrapflag;
 3112 
 3113     if (regex && str[strcspn(str, "^$*+()?[].\\")] == '\0')
 3114         regex = 0;
 3115 
 3116     data->searchdirection = direction;
 3117 
 3118     if (data->timeout)
 3119         return (0);
 3120 
 3121     if (data->searchall || wp->searchstr == NULL ||
 3122         wp->searchregex != regex) {
 3123         visible_only = 0;
 3124         data->searchall = 0;
 3125     } else
 3126         visible_only = (strcmp(wp->searchstr, str) == 0);
 3127     free(wp->searchstr);
 3128     wp->searchstr = xstrdup(str);
 3129     wp->searchregex = regex;
 3130 
 3131     fx = data->cx;
 3132     fy = screen_hsize(data->backing) - data->oy + data->cy;
 3133 
 3134     screen_init(&ss, screen_write_strlen("%s", str), 1, 0);
 3135     screen_write_start(&ctx, &ss);
 3136     screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", str);
 3137     screen_write_stop(&ctx);
 3138 
 3139     wrapflag = options_get_number(wp->window->options, "wrap-search");
 3140     cis = window_copy_is_lowercase(str);
 3141 
 3142     keys = options_get_number(wp->window->options, "mode-keys");
 3143 
 3144     if (direction) {
 3145         /*
 3146          * Behave according to mode-keys. If it is emacs, search forward
 3147          * leaves the cursor after the match. If it is vi, the cursor
 3148          * remains at the beginning of the match, regardless of
 3149          * direction, which means that we need to start the next search
 3150          * after the term the cursor is currently on when searching
 3151          * forward.
 3152          */
 3153         if (keys == MODEKEY_VI) {
 3154             if (data->searchmark != NULL)
 3155                 window_copy_move_after_search_mark(data, &fx,
 3156                     &fy, wrapflag);
 3157             else {
 3158                 /*
 3159                  * When there are no search marks, start the
 3160                  * search after the current cursor position.
 3161                  */
 3162                 window_copy_move_right(s, &fx, &fy, wrapflag);
 3163             }
 3164         }
 3165         endline = gd->hsize + gd->sy - 1;
 3166     }
 3167     else {
 3168         window_copy_move_left(s, &fx, &fy, wrapflag);
 3169         endline = 0;
 3170     }
 3171 
 3172     found = window_copy_search_jump(wme, gd, ss.grid, fx, fy, endline, cis,
 3173         wrapflag, direction, regex);
 3174     if (found) {
 3175         window_copy_search_marks(wme, &ss, regex, visible_only);
 3176         fx = data->cx;
 3177         fy = screen_hsize(data->backing) - data->oy + data->cy;
 3178 
 3179         /*
 3180          * When searching forward, if the cursor is not at the beginning
 3181          * of the mark, search again.
 3182          */
 3183         if (direction &&
 3184             window_copy_search_mark_at(data, fx, fy, &at) == 0 &&
 3185             at > 0 &&
 3186             data->searchmark[at] == data->searchmark[at - 1]) {
 3187             window_copy_move_after_search_mark(data, &fx, &fy,
 3188                 wrapflag);
 3189             window_copy_search_jump(wme, gd, ss.grid, fx,
 3190                 fy, endline, cis, wrapflag, direction,
 3191                 regex);
 3192             fx = data->cx;
 3193             fy = screen_hsize(data->backing) - data->oy + data->cy;
 3194         }
 3195 
 3196         if (direction) {
 3197             /*
 3198              * When in Emacs mode, position the cursor just after
 3199              * the mark.
 3200              */
 3201             if (keys == MODEKEY_EMACS) {
 3202                 window_copy_move_after_search_mark(data, &fx,
 3203                     &fy, wrapflag);
 3204                 data->cx = fx;
 3205                 data->cy = fy - screen_hsize(data->backing) +
 3206                     data-> oy;
 3207             }
 3208         }
 3209         else {
 3210             /*
 3211              * When searching backward, position the cursor at the
 3212              * beginning of the mark.
 3213              */
 3214             if (window_copy_search_mark_at(data, fx, fy,
 3215                     &start) == 0) {
 3216                 while (window_copy_search_mark_at(data, fx, fy,
 3217                            &at) == 0 &&
 3218                        data->searchmark[at] ==
 3219                            data->searchmark[start]) {
 3220                     data->cx = fx;
 3221                     data->cy = fy -
 3222                         screen_hsize(data->backing) +
 3223                         data-> oy;
 3224                     if (at == 0)
 3225                         break;
 3226 
 3227                     window_copy_move_left(s, &fx, &fy, 0);
 3228                 }
 3229             }
 3230         }
 3231     }
 3232     window_copy_redraw_screen(wme);
 3233 
 3234     screen_free(&ss);
 3235     return (found);
 3236 }
 3237 
 3238 static void
 3239 window_copy_visible_lines(struct window_copy_mode_data *data, u_int *start,
 3240     u_int *end)
 3241 {
 3242     struct grid     *gd = data->backing->grid;
 3243     const struct grid_line  *gl;
 3244 
 3245     for (*start = gd->hsize - data->oy; *start > 0; (*start)--) {
 3246         gl = grid_peek_line(gd, (*start) - 1);
 3247         if (~gl->flags & GRID_LINE_WRAPPED)
 3248             break;
 3249     }
 3250     *end = gd->hsize - data->oy + gd->sy;
 3251 }
 3252 
 3253 static int
 3254 window_copy_search_mark_at(struct window_copy_mode_data *data, u_int px,
 3255     u_int py, u_int *at)
 3256 {
 3257     struct screen   *s = data->backing;
 3258     struct grid *gd = s->grid;
 3259 
 3260     if (py < gd->hsize - data->oy)
 3261         return (-1);
 3262     if (py > gd->hsize - data->oy + gd->sy - 1)
 3263         return (-1);
 3264     *at = ((py - (gd->hsize - data->oy)) * gd->sx) + px;
 3265     return (0);
 3266 }
 3267 
 3268 static int
 3269 window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp,
 3270     int regex, int visible_only)
 3271 {
 3272     struct window_copy_mode_data    *data = wme->data;
 3273     struct screen           *s = data->backing, ss;
 3274     struct screen_write_ctx      ctx;
 3275     struct grid         *gd = s->grid;
 3276     int              found, cis, stopped = 0;
 3277     int              cflags = REG_EXTENDED;
 3278     u_int                px, py, i, b, nfound = 0, width;
 3279     u_int                ssize = 1, start, end;
 3280     char                *sbuf;
 3281     regex_t              reg;
 3282     uint64_t             stop = 0, tstart, t;
 3283 
 3284     if (ssp == NULL) {
 3285         width = screen_write_strlen("%s", data->searchstr);
 3286         screen_init(&ss, width, 1, 0);
 3287         screen_write_start(&ctx, &ss);
 3288         screen_write_nputs(&ctx, -1, &grid_default_cell, "%s",
 3289             data->searchstr);
 3290         screen_write_stop(&ctx);
 3291         ssp = &ss;
 3292     } else
 3293         width = screen_size_x(ssp);
 3294 
 3295     cis = window_copy_is_lowercase(data->searchstr);
 3296 
 3297     if (regex) {
 3298         sbuf = xmalloc(ssize);
 3299         sbuf[0] = '\0';
 3300         sbuf = window_copy_stringify(ssp->grid, 0, 0, ssp->grid->sx,
 3301             sbuf, &ssize);
 3302         if (cis)
 3303             cflags |= REG_ICASE;
 3304         if (regcomp(&reg, sbuf, cflags) != 0) {
 3305             free(sbuf);
 3306             return (0);
 3307         }
 3308         free(sbuf);
 3309     }
 3310     tstart = get_timer();
 3311 
 3312     if (visible_only)
 3313         window_copy_visible_lines(data, &start, &end);
 3314     else {
 3315         start = 0;
 3316         end = gd->hsize + gd->sy;
 3317         stop = get_timer() + WINDOW_COPY_SEARCH_ALL_TIMEOUT;
 3318     }
 3319 
 3320 again:
 3321     free(data->searchmark);
 3322     data->searchmark = xcalloc(gd->sx, gd->sy);
 3323     data->searchgen = 1;
 3324 
 3325     for (py = start; py < end; py++) {
 3326         px = 0;
 3327         for (;;) {
 3328             if (regex) {
 3329                 found = window_copy_search_lr_regex(gd,
 3330                     &px, &width, py, px, gd->sx, &reg);
 3331                 if (!found)
 3332                     break;
 3333             } else {
 3334                 found = window_copy_search_lr(gd, ssp->grid,
 3335                     &px, py, px, gd->sx, cis);
 3336                 if (!found)
 3337                     break;
 3338             }
 3339             nfound++;
 3340 
 3341             if (window_copy_search_mark_at(data, px, py, &b) == 0) {
 3342                 if (b + width > gd->sx * gd->sy)
 3343                     width = (gd->sx * gd->sy) - b;
 3344                 for (i = b; i < b + width; i++) {
 3345                     if (data->searchmark[i] != 0)
 3346                         continue;
 3347                     data->searchmark[i] = data->searchgen;
 3348                 }
 3349                 if (data->searchgen == UCHAR_MAX)
 3350                     data->searchgen = 1;
 3351                 else
 3352                     data->searchgen++;
 3353             }
 3354             px += width;
 3355         }
 3356 
 3357         t = get_timer();
 3358         if (t - tstart > WINDOW_COPY_SEARCH_TIMEOUT) {
 3359             data->timeout = 1;
 3360             break;
 3361         }
 3362         if (stop != 0 && t > stop) {
 3363             stopped = 1;
 3364             break;
 3365         }
 3366     }
 3367     if (data->timeout) {
 3368         window_copy_clear_marks(wme);
 3369         goto out;
 3370     }
 3371 
 3372     if (stopped && stop != 0) {
 3373         /* Try again but just the visible context. */
 3374         window_copy_visible_lines(data, &start, &end);
 3375         stop = 0;
 3376         goto again;
 3377     }
 3378 
 3379     if (!visible_only) {
 3380         if (stopped) {
 3381             if (nfound > 1000)
 3382                 data->searchcount = 1000;
 3383             else if (nfound > 100)
 3384                 data->searchcount = 100;
 3385             else if (nfound > 10)
 3386                 data->searchcount = 10;
 3387             else
 3388                 data->searchcount = -1;
 3389             data->searchmore = 1;
 3390         } else {
 3391             data->searchcount = nfound;
 3392             data->searchmore = 0;
 3393         }
 3394     }
 3395 
 3396 out:
 3397     if (ssp == &ss)
 3398         screen_free(&ss);
 3399     if (regex)
 3400         regfree(&reg);
 3401     return (1);
 3402 }
 3403 
 3404 static void
 3405 window_copy_clear_marks(struct window_mode_entry *wme)
 3406 {
 3407     struct window_copy_mode_data    *data = wme->data;
 3408 
 3409     free(data->searchmark);
 3410     data->searchmark = NULL;
 3411 }
 3412 
 3413 static int
 3414 window_copy_search_up(struct window_mode_entry *wme, int regex)
 3415 {
 3416     return (window_copy_search(wme, 0, regex));
 3417 }
 3418 
 3419 static int
 3420 window_copy_search_down(struct window_mode_entry *wme, int regex)
 3421 {
 3422     return (window_copy_search(wme, 1, regex));
 3423 }
 3424 
 3425 static void
 3426 window_copy_goto_line(struct window_mode_entry *wme, const char *linestr)
 3427 {
 3428     struct window_copy_mode_data    *data = wme->data;
 3429     const char          *errstr;
 3430     int              lineno;
 3431 
 3432     lineno = strtonum(linestr, -1, INT_MAX, &errstr);
 3433     if (errstr != NULL)
 3434         return;
 3435     if (lineno < 0 || (u_int)lineno > screen_hsize(data->backing))
 3436         lineno = screen_hsize(data->backing);
 3437 
 3438     data->oy = lineno;
 3439     window_copy_update_selection(wme, 1, 0);
 3440     window_copy_redraw_screen(wme);
 3441 }
 3442 
 3443 static void
 3444 window_copy_match_start_end(struct window_copy_mode_data *data, u_int at,
 3445     u_int *start, u_int *end)
 3446 {
 3447     struct grid *gd = data->backing->grid;
 3448     u_int        last = (gd->sy * gd->sx) - 1;
 3449     u_char       mark = data->searchmark[at];
 3450 
 3451     *start = *end = at;
 3452     while (*start != 0 && data->searchmark[*start] == mark)
 3453         (*start)--;
 3454     if (data->searchmark[*start] != mark)
 3455         (*start)++;
 3456     while (*end != last && data->searchmark[*end] == mark)
 3457         (*end)++;
 3458     if (data->searchmark[*end] != mark)
 3459         (*end)--;
 3460 }
 3461 
 3462 static char *
 3463 window_copy_match_at_cursor(struct window_copy_mode_data *data)
 3464 {
 3465     struct grid *gd = data->backing->grid;
 3466     struct grid_cell gc;
 3467     u_int        at, start, end, cy, px, py;
 3468     u_int        sx = screen_size_x(data->backing);
 3469     char        *buf = NULL;
 3470     size_t       len = 0;
 3471 
 3472     if (data->searchmark == NULL)
 3473         return (NULL);
 3474 
 3475     cy = screen_hsize(data->backing) - data->oy + data->cy;
 3476     if (window_copy_search_mark_at(data, data->cx, cy, &at) != 0)
 3477         return (NULL);
 3478     if (data->searchmark[at] == 0) {
 3479         /* Allow one position after the match. */
 3480         if (at == 0 || data->searchmark[--at] == 0)
 3481             return (NULL);
 3482     }
 3483     window_copy_match_start_end(data, at, &start, &end);
 3484 
 3485     /*
 3486      * Cells will not be set in the marked array unless they are valid text
 3487      * and wrapping will be taken care of, so we can just copy.
 3488      */
 3489     for (at = start; at <= end; at++) {
 3490         py = at / sx;
 3491         px = at - (py * sx);
 3492 
 3493         grid_get_cell(gd, px, gd->hsize + py - data->oy, &gc);
 3494         buf = xrealloc(buf, len + gc.data.size + 1);
 3495         memcpy(buf + len, gc.data.data, gc.data.size);
 3496         len += gc.data.size;
 3497     }
 3498     if (len != 0)
 3499         buf[len] = '\0';
 3500     return (buf);
 3501 }
 3502 
 3503 static void
 3504 window_copy_update_style(struct window_mode_entry *wme, u_int fx, u_int fy,
 3505     struct grid_cell *gc, const struct grid_cell *mgc,
 3506     const struct grid_cell *cgc, const struct grid_cell *mkgc)
 3507 {
 3508     struct window_pane      *wp = wme->wp;
 3509     struct window_copy_mode_data    *data = wme->data;
 3510     u_int                mark, start, end, cy, cursor, current;
 3511     int              inv = 0, found = 0;
 3512     int              keys;
 3513 
 3514     if (data->showmark && fy == data->my) {
 3515         gc->attr = mkgc->attr;
 3516         if (fx == data->mx)
 3517             inv = 1;
 3518         if (inv) {
 3519             gc->fg = mkgc->bg;
 3520             gc->bg = mkgc->fg;
 3521         }
 3522         else {
 3523             gc->fg = mkgc->fg;
 3524             gc->bg = mkgc->bg;
 3525         }
 3526     }
 3527 
 3528     if (data->searchmark == NULL)
 3529         return;
 3530 
 3531     if (window_copy_search_mark_at(data, fx, fy, &current) != 0)
 3532         return;
 3533     mark = data->searchmark[current];
 3534     if (mark == 0)
 3535         return;
 3536 
 3537     cy = screen_hsize(data->backing) - data->oy + data->cy;
 3538     if (window_copy_search_mark_at(data, data->cx, cy, &cursor) == 0) {
 3539         keys = options_get_number(wp->window->options, "mode-keys");
 3540         if (cursor != 0 &&
 3541             keys == MODEKEY_EMACS &&
 3542             data->searchdirection) {
 3543             if (data->searchmark[cursor - 1] == mark) {
 3544                 cursor--;
 3545                 found = 1;
 3546             }
 3547         } else if (data->searchmark[cursor] == mark)
 3548             found = 1;
 3549         if (found) {
 3550             window_copy_match_start_end(data, cursor, &start, &end);
 3551             if (current >= start && current <= end) {
 3552                 gc->attr = cgc->attr;
 3553                 if (inv) {
 3554                     gc->fg = cgc->bg;
 3555                     gc->bg = cgc->fg;
 3556                 }
 3557                 else {
 3558                     gc->fg = cgc->fg;
 3559                     gc->bg = cgc->bg;
 3560                 }
 3561                 return;
 3562             }
 3563         }
 3564     }
 3565 
 3566     gc->attr = mgc->attr;
 3567     if (inv) {
 3568         gc->fg = mgc->bg;
 3569         gc->bg = mgc->fg;
 3570     }
 3571     else {
 3572         gc->fg = mgc->fg;
 3573         gc->bg = mgc->bg;
 3574     }
 3575 }
 3576 
 3577 static void
 3578 window_copy_write_one(struct window_mode_entry *wme,
 3579     struct screen_write_ctx *ctx, u_int py, u_int fy, u_int nx,
 3580     const struct grid_cell *mgc, const struct grid_cell *cgc,
 3581     const struct grid_cell *mkgc)
 3582 {
 3583     struct window_copy_mode_data    *data = wme->data;
 3584     struct grid         *gd = data->backing->grid;
 3585     struct grid_cell         gc;
 3586     u_int                fx;
 3587 
 3588     screen_write_cursormove(ctx, 0, py, 0);
 3589     for (fx = 0; fx < nx; fx++) {
 3590         grid_get_cell(gd, fx, fy, &gc);
 3591         if (fx + gc.data.width <= nx) {
 3592             window_copy_update_style(wme, fx, fy, &gc, mgc, cgc,
 3593                 mkgc);
 3594             screen_write_cell(ctx, &gc);
 3595         }
 3596     }
 3597 }
 3598 
 3599 static void
 3600 window_copy_write_line(struct window_mode_entry *wme,
 3601     struct screen_write_ctx *ctx, u_int py)
 3602 {
 3603     struct window_pane      *wp = wme->wp;
 3604     struct window_copy_mode_data    *data = wme->data;
 3605     struct screen           *s = &data->screen;
 3606     struct options          *oo = wp->window->options;
 3607     struct grid_cell         gc, mgc, cgc, mkgc;
 3608     char                 hdr[512];
 3609     size_t               size = 0;
 3610     u_int                hsize = screen_hsize(data->backing);
 3611 
 3612     style_apply(&gc, oo, "mode-style", NULL);
 3613     gc.flags |= GRID_FLAG_NOPALETTE;
 3614     style_apply(&mgc, oo, "copy-mode-match-style", NULL);
 3615     mgc.flags |= GRID_FLAG_NOPALETTE;
 3616     style_apply(&cgc, oo, "copy-mode-current-match-style", NULL);
 3617     cgc.flags |= GRID_FLAG_NOPALETTE;
 3618     style_apply(&mkgc, oo, "copy-mode-mark-style", NULL);
 3619     mkgc.flags |= GRID_FLAG_NOPALETTE;
 3620 
 3621     if (py == 0 && s->rupper < s->rlower && !data->hide_position) {
 3622         if (data->searchmark == NULL) {
 3623             if (data->timeout) {
 3624                 size = xsnprintf(hdr, sizeof hdr,
 3625                     "(timed out) [%u/%u]", data->oy, hsize);
 3626             } else {
 3627                 size = xsnprintf(hdr, sizeof hdr,
 3628                     "[%u/%u]", data->oy, hsize);
 3629             }
 3630         } else {
 3631             if (data->searchcount == -1) {
 3632                 size = xsnprintf(hdr, sizeof hdr,
 3633                     "[%u/%u]", data->oy, hsize);
 3634             } else {
 3635                 size = xsnprintf(hdr, sizeof hdr,
 3636                     "(%d%s results) [%u/%u]", data->searchcount,
 3637                     data->searchmore ? "+" : "", data->oy,
 3638                     hsize);
 3639             }
 3640         }
 3641         if (size > screen_size_x(s))
 3642             size = screen_size_x(s);
 3643         screen_write_cursormove(ctx, screen_size_x(s) - size, 0, 0);
 3644         screen_write_puts(ctx, &gc, "%s", hdr);
 3645     } else
 3646         size = 0;
 3647 
 3648     if (size < screen_size_x(s)) {
 3649         window_copy_write_one(wme, ctx, py, hsize - data->oy + py,
 3650             screen_size_x(s) - size, &mgc, &cgc, &mkgc);
 3651     }
 3652 
 3653     if (py == data->cy && data->cx == screen_size_x(s)) {
 3654         screen_write_cursormove(ctx, screen_size_x(s) - 1, py, 0);
 3655         screen_write_putc(ctx, &grid_default_cell, '$');
 3656     }
 3657 }
 3658 
 3659 static void
 3660 window_copy_write_lines(struct window_mode_entry *wme,
 3661     struct screen_write_ctx *ctx, u_int py, u_int ny)
 3662 {
 3663     u_int   yy;
 3664 
 3665     for (yy = py; yy < py + ny; yy++)
 3666         window_copy_write_line(wme, ctx, py);
 3667 }
 3668 
 3669 static void
 3670 window_copy_redraw_selection(struct window_mode_entry *wme, u_int old_y)
 3671 {
 3672     struct window_copy_mode_data    *data = wme->data;
 3673     struct grid         *gd = data->backing->grid;
 3674     u_int                new_y, start, end;
 3675 
 3676     new_y = data->cy;
 3677     if (old_y <= new_y) {
 3678         start = old_y;
 3679         end = new_y;
 3680     } else {
 3681         start = new_y;
 3682         end = old_y;
 3683     }
 3684 
 3685     /*
 3686      * In word selection mode the first word on the line below the cursor
 3687      * might be selected, so add this line to the redraw area.
 3688      */
 3689     if (data->selflag == SEL_WORD) {
 3690         /* Last grid line in data coordinates. */
 3691         if (end < gd->sy + data->oy - 1)
 3692             end++;
 3693     }
 3694     window_copy_redraw_lines(wme, start, end - start + 1);
 3695 }
 3696 
 3697 static void
 3698 window_copy_redraw_lines(struct window_mode_entry *wme, u_int py, u_int ny)
 3699 {
 3700     struct window_pane      *wp = wme->wp;
 3701     struct window_copy_mode_data    *data = wme->data;
 3702     struct screen_write_ctx      ctx;
 3703     u_int                i;
 3704 
 3705     screen_write_start_pane(&ctx, wp, NULL);
 3706     for (i = py; i < py + ny; i++)
 3707         window_copy_write_line(wme, &ctx, i);
 3708     screen_write_cursormove(&ctx, data->cx, data->cy, 0);
 3709     screen_write_stop(&ctx);
 3710 }
 3711 
 3712 static void
 3713 window_copy_redraw_screen(struct window_mode_entry *wme)
 3714 {
 3715     struct window_copy_mode_data    *data = wme->data;
 3716 
 3717     window_copy_redraw_lines(wme, 0, screen_size_y(&data->screen));
 3718 }
 3719 
 3720 static void
 3721 window_copy_synchronize_cursor_end(struct window_mode_entry *wme, int begin,
 3722     int no_reset)
 3723 {
 3724     struct window_copy_mode_data    *data = wme->data;
 3725     u_int                xx, yy;
 3726 
 3727     xx = data->cx;
 3728     yy = screen_hsize(data->backing) + data->cy - data->oy;
 3729     switch (data->selflag) {
 3730     case SEL_WORD:
 3731         if (no_reset)
 3732             break;
 3733         begin = 0;
 3734         if (data->dy > yy || (data->dy == yy && data->dx > xx)) {
 3735             /* Right to left selection. */
 3736             window_copy_cursor_previous_word_pos(wme, data->ws, 0,
 3737                 &xx, &yy);
 3738             begin = 1;
 3739 
 3740             /* Reset the end. */
 3741             data->endselx = data->endselrx;
 3742             data->endsely = data->endselry;
 3743         } else {
 3744             /* Left to right selection. */
 3745             if (xx >= window_copy_find_length(wme, yy) ||
 3746                 !window_copy_in_set(wme, xx + 1, yy, data->ws))
 3747                 window_copy_cursor_next_word_end_pos(wme,
 3748                     data->ws, &xx, &yy);
 3749 
 3750             /* Reset the start. */
 3751             data->selx = data->selrx;
 3752             data->sely = data->selry;
 3753         }
 3754         break;
 3755     case SEL_LINE:
 3756         if (no_reset)
 3757             break;
 3758         begin = 0;
 3759         if (data->dy > yy) {
 3760             /* Right to left selection. */
 3761             xx = 0;
 3762             begin = 1;
 3763 
 3764             /* Reset the end. */
 3765             data->endselx = data->endselrx;
 3766             data->endsely = data->endselry;
 3767         } else {
 3768             /* Left to right selection. */
 3769             if (yy < data->endselry)
 3770                 yy = data->endselry;
 3771             xx = window_copy_find_length(wme, yy);
 3772 
 3773             /* Reset the start. */
 3774             data->selx = data->selrx;
 3775             data->sely = data->selry;
 3776         }
 3777         break;
 3778     case SEL_CHAR:
 3779         break;
 3780     }
 3781     if (begin) {
 3782         data->selx = xx;
 3783         data->sely = yy;
 3784     } else {
 3785         data->endselx = xx;
 3786         data->endsely = yy;
 3787     }
 3788 }
 3789 
 3790 static void
 3791 window_copy_synchronize_cursor(struct window_mode_entry *wme, int no_reset)
 3792 {
 3793     struct window_copy_mode_data    *data = wme->data;
 3794 
 3795     switch (data->cursordrag) {
 3796     case CURSORDRAG_ENDSEL:
 3797         window_copy_synchronize_cursor_end(wme, 0, no_reset);
 3798         break;
 3799     case CURSORDRAG_SEL:
 3800         window_copy_synchronize_cursor_end(wme, 1, no_reset);
 3801         break;
 3802     case CURSORDRAG_NONE:
 3803         break;
 3804     }
 3805 }
 3806 
 3807 static void
 3808 window_copy_update_cursor(struct window_mode_entry *wme, u_int cx, u_int cy)
 3809 {
 3810     struct window_pane      *wp = wme->wp;
 3811     struct window_copy_mode_data    *data = wme->data;
 3812     struct screen           *s = &data->screen;
 3813     struct screen_write_ctx      ctx;
 3814     u_int                old_cx, old_cy;
 3815 
 3816     old_cx = data->cx; old_cy = data->cy;
 3817     data->cx = cx; data->cy = cy;
 3818     if (old_cx == screen_size_x(s))
 3819         window_copy_redraw_lines(wme, old_cy, 1);
 3820     if (data->cx == screen_size_x(s))
 3821         window_copy_redraw_lines(wme, data->cy, 1);
 3822     else {
 3823         screen_write_start_pane(&ctx, wp, NULL);
 3824         screen_write_cursormove(&ctx, data->cx, data->cy, 0);
 3825         screen_write_stop(&ctx);
 3826     }
 3827 }
 3828 
 3829 static void
 3830 window_copy_start_selection(struct window_mode_entry *wme)
 3831 {
 3832     struct window_copy_mode_data    *data = wme->data;
 3833 
 3834     data->selx = data->cx;
 3835     data->sely = screen_hsize(data->backing) + data->cy - data->oy;
 3836 
 3837     data->endselx = data->selx;
 3838     data->endsely = data->sely;
 3839 
 3840     data->cursordrag = CURSORDRAG_ENDSEL;
 3841 
 3842     window_copy_set_selection(wme, 1, 0);
 3843 }
 3844 
 3845 static int
 3846 window_copy_adjust_selection(struct window_mode_entry *wme, u_int *selx,
 3847     u_int *sely)
 3848 {
 3849     struct window_copy_mode_data    *data = wme->data;
 3850     struct screen           *s = &data->screen;
 3851     u_int                sx, sy, ty;
 3852     int              relpos;
 3853 
 3854     sx = *selx;
 3855     sy = *sely;
 3856 
 3857     ty = screen_hsize(data->backing) - data->oy;
 3858     if (sy < ty) {
 3859         relpos = WINDOW_COPY_REL_POS_ABOVE;
 3860         if (!data->rectflag)
 3861             sx = 0;
 3862         sy = 0;
 3863     } else if (sy > ty + screen_size_y(s) - 1) {
 3864         relpos = WINDOW_COPY_REL_POS_BELOW;
 3865         if (!data->rectflag)
 3866             sx = screen_size_x(s) - 1;
 3867         sy = screen_size_y(s) - 1;
 3868     } else {
 3869         relpos = WINDOW_COPY_REL_POS_ON_SCREEN;
 3870         sy -= ty;
 3871     }
 3872 
 3873     *selx = sx;
 3874     *sely = sy;
 3875     return (relpos);
 3876 }
 3877 
 3878 static int
 3879 window_copy_update_selection(struct window_mode_entry *wme, int may_redraw,
 3880     int no_reset)
 3881 {
 3882     struct window_copy_mode_data    *data = wme->data;
 3883     struct screen           *s = &data->screen;
 3884 
 3885     if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
 3886         return (0);
 3887     return (window_copy_set_selection(wme, may_redraw, no_reset));
 3888 }
 3889 
 3890 static int
 3891 window_copy_set_selection(struct window_mode_entry *wme, int may_redraw,
 3892     int no_reset)
 3893 {
 3894     struct window_pane      *wp = wme->wp;
 3895     struct window_copy_mode_data    *data = wme->data;
 3896     struct screen           *s = &data->screen;
 3897     struct options          *oo = wp->window->options;
 3898     struct grid_cell         gc;
 3899     u_int                sx, sy, cy, endsx, endsy;
 3900     int              startrelpos, endrelpos;
 3901 
 3902     window_copy_synchronize_cursor(wme, no_reset);
 3903 
 3904     /* Adjust the selection. */
 3905     sx = data->selx;
 3906     sy = data->sely;
 3907     startrelpos = window_copy_adjust_selection(wme, &sx, &sy);
 3908 
 3909     /* Adjust the end of selection. */
 3910     endsx = data->endselx;
 3911     endsy = data->endsely;
 3912     endrelpos = window_copy_adjust_selection(wme, &endsx, &endsy);
 3913 
 3914     /* Selection is outside of the current screen */
 3915     if (startrelpos == endrelpos &&
 3916         startrelpos != WINDOW_COPY_REL_POS_ON_SCREEN) {
 3917         screen_hide_selection(s);
 3918         return (0);
 3919     }
 3920 
 3921     /* Set colours and selection. */
 3922     style_apply(&gc, oo, "mode-style", NULL);
 3923     gc.flags |= GRID_FLAG_NOPALETTE;
 3924     screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag,
 3925         data->modekeys, &gc);
 3926 
 3927     if (data->rectflag && may_redraw) {
 3928         /*
 3929          * Can't rely on the caller to redraw the right lines for
 3930          * rectangle selection - find the highest line and the number
 3931          * of lines, and redraw just past that in both directions
 3932          */
 3933         cy = data->cy;
 3934         if (data->cursordrag == CURSORDRAG_ENDSEL) {
 3935             if (sy < cy)
 3936                 window_copy_redraw_lines(wme, sy, cy - sy + 1);
 3937             else
 3938                 window_copy_redraw_lines(wme, cy, sy - cy + 1);
 3939         } else {
 3940             if (endsy < cy) {
 3941                 window_copy_redraw_lines(wme, endsy,
 3942                     cy - endsy + 1);
 3943             } else {
 3944                 window_copy_redraw_lines(wme, cy,
 3945                     endsy - cy + 1);
 3946             }
 3947         }
 3948     }
 3949 
 3950     return (1);
 3951 }
 3952 
 3953 static void *
 3954 window_copy_get_selection(struct window_mode_entry *wme, size_t *len)
 3955 {
 3956     struct window_pane      *wp = wme->wp;
 3957     struct window_copy_mode_data    *data = wme->data;
 3958     struct screen           *s = &data->screen;
 3959     char                *buf;
 3960     size_t               off;
 3961     u_int                i, xx, yy, sx, sy, ex, ey, ey_last;
 3962     u_int                firstsx, lastex, restex, restsx, selx;
 3963     int              keys;
 3964 
 3965     if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE) {
 3966         buf = window_copy_match_at_cursor(data);
 3967         if (buf != NULL)
 3968             *len = strlen(buf);
 3969         else
 3970             *len = 0;
 3971         return (buf);
 3972     }
 3973 
 3974     buf = xmalloc(1);
 3975     off = 0;
 3976 
 3977     *buf = '\0';
 3978 
 3979     /*
 3980      * The selection extends from selx,sely to (adjusted) cx,cy on
 3981      * the base screen.
 3982      */
 3983 
 3984     /* Find start and end. */
 3985     xx = data->endselx;
 3986     yy = data->endsely;
 3987     if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
 3988         sx = xx; sy = yy;
 3989         ex = data->selx; ey = data->sely;
 3990     } else {
 3991         sx = data->selx; sy = data->sely;
 3992         ex = xx; ey = yy;
 3993     }
 3994 
 3995     /* Trim ex to end of line. */
 3996     ey_last = window_copy_find_length(wme, ey);
 3997     if (ex > ey_last)
 3998         ex = ey_last;
 3999 
 4000     /*
 4001      * Deal with rectangle-copy if necessary; four situations: start of
 4002      * first line (firstsx), end of last line (lastex), start (restsx) and
 4003      * end (restex) of all other lines.
 4004      */
 4005     xx = screen_size_x(s);
 4006 
 4007     /*
 4008      * Behave according to mode-keys. If it is emacs, copy like emacs,
 4009      * keeping the top-left-most character, and dropping the
 4010      * bottom-right-most, regardless of copy direction. If it is vi, also
 4011      * keep bottom-right-most character.
 4012      */
 4013     keys = options_get_number(wp->window->options, "mode-keys");
 4014     if (data->rectflag) {
 4015         /*
 4016          * Need to ignore the column with the cursor in it, which for
 4017          * rectangular copy means knowing which side the cursor is on.
 4018          */
 4019         if (data->cursordrag == CURSORDRAG_ENDSEL)
 4020             selx = data->selx;
 4021         else
 4022             selx = data->endselx;
 4023         if (selx < data->cx) {
 4024             /* Selection start is on the left. */
 4025             if (keys == MODEKEY_EMACS) {
 4026                 lastex = data->cx;
 4027                 restex = data->cx;
 4028             }
 4029             else {
 4030                 lastex = data->cx + 1;
 4031                 restex = data->cx + 1;
 4032             }
 4033             firstsx = selx;
 4034             restsx = selx;
 4035         } else {
 4036             /* Cursor is on the left. */
 4037             lastex = selx + 1;
 4038             restex = selx + 1;
 4039             firstsx = data->cx;
 4040             restsx = data->cx;
 4041         }
 4042     } else {
 4043         if (keys == MODEKEY_EMACS)
 4044             lastex = ex;
 4045         else
 4046             lastex = ex + 1;
 4047         restex = xx;
 4048         firstsx = sx;
 4049         restsx = 0;
 4050     }
 4051 
 4052     /* Copy the lines. */
 4053     for (i = sy; i <= ey; i++) {
 4054         window_copy_copy_line(wme, &buf, &off, i,
 4055             (i == sy ? firstsx : restsx),
 4056             (i == ey ? lastex : restex));
 4057     }
 4058 
 4059     /* Don't bother if no data. */
 4060     if (off == 0) {
 4061         free(buf);
 4062         *len = 0;
 4063         return (NULL);
 4064     }
 4065      /* Remove final \n (unless at end in vi mode). */
 4066     if (keys == MODEKEY_EMACS || lastex <= ey_last) {
 4067         if (~grid_get_line(data->backing->grid, ey)->flags &
 4068             GRID_LINE_WRAPPED || lastex != ey_last)
 4069         off -= 1;
 4070     }
 4071     *len = off;
 4072     return (buf);
 4073 }
 4074 
 4075 static void
 4076 window_copy_copy_buffer(struct window_mode_entry *wme, const char *prefix,
 4077     void *buf, size_t len)
 4078 {
 4079     struct window_pane  *wp = wme->wp;
 4080     struct screen_write_ctx  ctx;
 4081 
 4082     if (options_get_number(global_options, "set-clipboard") != 0) {
 4083         screen_write_start_pane(&ctx, wp, NULL);
 4084         screen_write_setselection(&ctx, buf, len);
 4085         screen_write_stop(&ctx);
 4086         notify_pane("pane-set-clipboard", wp);
 4087     }
 4088 
 4089     paste_add(prefix, buf, len);
 4090 }
 4091 
 4092 static void *
 4093 window_copy_pipe_run(struct window_mode_entry *wme, struct session *s,
 4094     const char *cmd, size_t *len)
 4095 {
 4096     void        *buf;
 4097     struct job  *job;
 4098 
 4099     buf = window_copy_get_selection(wme, len);
 4100     if (cmd == NULL || *cmd == '\0')
 4101         cmd = options_get_string(global_options, "copy-command");
 4102     if (cmd != NULL && *cmd != '\0') {
 4103         job = job_run(cmd, 0, NULL, s, NULL, NULL, NULL, NULL, NULL,
 4104             JOB_NOWAIT, -1, -1);
 4105         bufferevent_write(job_get_event(job), buf, *len);
 4106     }
 4107     return (buf);
 4108 }
 4109 
 4110 static void
 4111 window_copy_pipe(struct window_mode_entry *wme, struct session *s,
 4112     const char *cmd)
 4113 {
 4114     size_t  len;
 4115 
 4116     window_copy_pipe_run(wme, s, cmd, &len);
 4117 }
 4118 
 4119 static void
 4120 window_copy_copy_pipe(struct window_mode_entry *wme, struct session *s,
 4121     const char *prefix, const char *cmd)
 4122 {
 4123     void    *buf;
 4124     size_t   len;
 4125 
 4126     buf = window_copy_pipe_run(wme, s, cmd, &len);
 4127     if (buf != NULL)
 4128         window_copy_copy_buffer(wme, prefix, buf, len);
 4129 }
 4130 
 4131 static void
 4132 window_copy_copy_selection(struct window_mode_entry *wme, const char *prefix)
 4133 {
 4134     char    *buf;
 4135     size_t   len;
 4136 
 4137     buf = window_copy_get_selection(wme, &len);
 4138     if (buf != NULL)
 4139         window_copy_copy_buffer(wme, prefix, buf, len);
 4140 }
 4141 
 4142 static void
 4143 window_copy_append_selection(struct window_mode_entry *wme)
 4144 {
 4145     struct window_pane      *wp = wme->wp;
 4146     char                *buf;
 4147     struct paste_buffer     *pb;
 4148     const char          *bufdata, *bufname = NULL;
 4149     size_t               len, bufsize;
 4150     struct screen_write_ctx      ctx;
 4151 
 4152     buf = window_copy_get_selection(wme, &len);
 4153     if (buf == NULL)
 4154         return;
 4155 
 4156     if (options_get_number(global_options, "set-clipboard") != 0) {
 4157         screen_write_start_pane(&ctx, wp, NULL);
 4158         screen_write_setselection(&ctx, buf, len);
 4159         screen_write_stop(&ctx);
 4160         notify_pane("pane-set-clipboard", wp);
 4161     }
 4162 
 4163     pb = paste_get_top(&bufname);
 4164     if (pb != NULL) {
 4165         bufdata = paste_buffer_data(pb, &bufsize);
 4166         buf = xrealloc(buf, len + bufsize);
 4167         memmove(buf + bufsize, buf, len);
 4168         memcpy(buf, bufdata, bufsize);
 4169         len += bufsize;
 4170     }
 4171     if (paste_set(buf, len, bufname, NULL) != 0)
 4172         free(buf);
 4173 }
 4174 
 4175 static void
 4176 window_copy_copy_line(struct window_mode_entry *wme, char **buf, size_t *off,
 4177     u_int sy, u_int sx, u_int ex)
 4178 {
 4179     struct window_copy_mode_data    *data = wme->data;
 4180     struct grid         *gd = data->backing->grid;
 4181     struct grid_cell         gc;
 4182     struct grid_line        *gl;
 4183     struct utf8_data         ud;
 4184     u_int                i, xx, wrapped = 0;
 4185     const char          *s;
 4186 
 4187     if (sx > ex)
 4188         return;
 4189 
 4190     /*
 4191      * Work out if the line was wrapped at the screen edge and all of it is
 4192      * on screen.
 4193      */
 4194     gl = grid_get_line(gd, sy);
 4195     if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
 4196         wrapped = 1;
 4197 
 4198     /* If the line was wrapped, don't strip spaces (use the full length). */
 4199     if (wrapped)
 4200         xx = gl->cellsize;
 4201     else
 4202         xx = window_copy_find_length(wme, sy);
 4203     if (ex > xx)
 4204         ex = xx;
 4205     if (sx > xx)
 4206         sx = xx;
 4207 
 4208     if (sx < ex) {
 4209         for (i = sx; i < ex; i++) {
 4210             grid_get_cell(gd, i, sy, &gc);
 4211             if (gc.flags & GRID_FLAG_PADDING)
 4212                 continue;
 4213             utf8_copy(&ud, &gc.data);
 4214             if (ud.size == 1 && (gc.attr & GRID_ATTR_CHARSET)) {
 4215                 s = tty_acs_get(NULL, ud.data[0]);
 4216                 if (s != NULL && strlen(s) <= sizeof ud.data) {
 4217                     ud.size = strlen(s);
 4218                     memcpy(ud.data, s, ud.size);
 4219                 }
 4220             }
 4221 
 4222             *buf = xrealloc(*buf, (*off) + ud.size);
 4223             memcpy(*buf + *off, ud.data, ud.size);
 4224             *off += ud.size;
 4225         }
 4226     }
 4227 
 4228     /* Only add a newline if the line wasn't wrapped. */
 4229     if (!wrapped || ex != xx) {
 4230         *buf = xrealloc(*buf, (*off) + 1);
 4231         (*buf)[(*off)++] = '\n';
 4232     }
 4233 }
 4234 
 4235 static void
 4236 window_copy_clear_selection(struct window_mode_entry *wme)
 4237 {
 4238     struct window_copy_mode_data   *data = wme->data;
 4239     u_int               px, py;
 4240 
 4241     screen_clear_selection(&data->screen);
 4242 
 4243     data->cursordrag = CURSORDRAG_NONE;
 4244     data->lineflag = LINE_SEL_NONE;
 4245     data->selflag = SEL_CHAR;
 4246 
 4247     py = screen_hsize(data->backing) + data->cy - data->oy;
 4248     px = window_copy_find_length(wme, py);
 4249     if (data->cx > px)
 4250         window_copy_update_cursor(wme, px, data->cy);
 4251 }
 4252 
 4253 static int
 4254 window_copy_in_set(struct window_mode_entry *wme, u_int px, u_int py,
 4255     const char *set)
 4256 {
 4257     struct window_copy_mode_data    *data = wme->data;
 4258     struct grid_cell         gc;
 4259 
 4260     grid_get_cell(data->backing->grid, px, py, &gc);
 4261     if (gc.flags & GRID_FLAG_PADDING)
 4262         return (0);
 4263     return (utf8_cstrhas(set, &gc.data));
 4264 }
 4265 
 4266 static u_int
 4267 window_copy_find_length(struct window_mode_entry *wme, u_int py)
 4268 {
 4269     struct window_copy_mode_data    *data = wme->data;
 4270 
 4271     return (grid_line_length(data->backing->grid, py));
 4272 }
 4273 
 4274 static void
 4275 window_copy_cursor_start_of_line(struct window_mode_entry *wme)
 4276 {
 4277     struct window_copy_mode_data    *data = wme->data;
 4278     struct screen           *back_s = data->backing;
 4279     struct grid_reader       gr;
 4280     u_int                px, py, oldy, hsize;
 4281 
 4282     px = data->cx;
 4283     hsize = screen_hsize(back_s);
 4284     py = hsize + data->cy - data->oy;
 4285     oldy = data->cy;
 4286 
 4287     grid_reader_start(&gr, back_s->grid, px, py);
 4288     grid_reader_cursor_start_of_line(&gr, 1);
 4289     grid_reader_get_cursor(&gr, &px, &py);
 4290     window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
 4291 }
 4292 
 4293 static void
 4294 window_copy_cursor_back_to_indentation(struct window_mode_entry *wme)
 4295 {
 4296     struct window_copy_mode_data    *data = wme->data;
 4297     struct screen           *back_s = data->backing;
 4298     struct grid_reader       gr;
 4299     u_int                px, py, oldy, hsize;
 4300 
 4301     px = data->cx;
 4302     hsize = screen_hsize(back_s);
 4303     py = hsize + data->cy - data->oy;
 4304     oldy = data->cy;
 4305 
 4306     grid_reader_start(&gr, back_s->grid, px, py);
 4307     grid_reader_cursor_back_to_indentation(&gr);
 4308     grid_reader_get_cursor(&gr, &px, &py);
 4309     window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
 4310 }
 4311 
 4312 static void
 4313 window_copy_cursor_end_of_line(struct window_mode_entry *wme)
 4314 {
 4315     struct window_copy_mode_data    *data = wme->data;
 4316     struct screen           *back_s = data->backing;
 4317     struct grid_reader       gr;
 4318     u_int                px, py, oldy, hsize;
 4319 
 4320     px = data->cx;
 4321     hsize = screen_hsize(back_s);
 4322     py =  hsize + data->cy - data->oy;
 4323     oldy = data->cy;
 4324 
 4325     grid_reader_start(&gr, back_s->grid, px, py);
 4326     if (data->screen.sel != NULL && data->rectflag)
 4327         grid_reader_cursor_end_of_line(&gr, 1, 1);
 4328     else
 4329         grid_reader_cursor_end_of_line(&gr, 1, 0);
 4330     grid_reader_get_cursor(&gr, &px, &py);
 4331     window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
 4332         data->oy, oldy, px, py, 0);
 4333 }
 4334 
 4335 static void
 4336 window_copy_other_end(struct window_mode_entry *wme)
 4337 {
 4338     struct window_copy_mode_data    *data = wme->data;
 4339     struct screen           *s = &data->screen;
 4340     u_int                selx, sely, cy, yy, hsize;
 4341 
 4342     if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
 4343         return;
 4344 
 4345     if (data->lineflag == LINE_SEL_LEFT_RIGHT)
 4346         data->lineflag = LINE_SEL_RIGHT_LEFT;
 4347     else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
 4348         data->lineflag = LINE_SEL_LEFT_RIGHT;
 4349 
 4350     switch (data->cursordrag) {
 4351         case CURSORDRAG_NONE:
 4352         case CURSORDRAG_SEL:
 4353             data->cursordrag = CURSORDRAG_ENDSEL;
 4354             break;
 4355         case CURSORDRAG_ENDSEL:
 4356             data->cursordrag = CURSORDRAG_SEL;
 4357             break;
 4358     }
 4359 
 4360     selx = data->endselx;
 4361     sely = data->endsely;
 4362     if (data->cursordrag == CURSORDRAG_SEL) {
 4363         selx = data->selx;
 4364         sely = data->sely;
 4365     }
 4366 
 4367     cy = data->cy;
 4368     yy = screen_hsize(data->backing) + data->cy - data->oy;
 4369 
 4370     data->cx = selx;
 4371 
 4372     hsize = screen_hsize(data->backing);
 4373     if (sely < hsize - data->oy) { /* above */
 4374         data->oy = hsize - sely;
 4375         data->cy = 0;
 4376     } else if (sely > hsize - data->oy + screen_size_y(s)) { /* below */
 4377         data->oy = hsize - sely + screen_size_y(s) - 1;
 4378         data->cy = screen_size_y(s) - 1;
 4379     } else
 4380         data->cy = cy + sely - yy;
 4381 
 4382     window_copy_update_selection(wme, 1, 1);
 4383     window_copy_redraw_screen(wme);
 4384 }
 4385 
 4386 static void
 4387 window_copy_cursor_left(struct window_mode_entry *wme)
 4388 {
 4389     struct window_copy_mode_data    *data = wme->data;
 4390     struct screen           *back_s = data->backing;
 4391     struct grid_reader       gr;
 4392     u_int                px, py, oldy, hsize;
 4393 
 4394     px = data->cx;
 4395     hsize = screen_hsize(back_s);
 4396     py = hsize + data->cy - data->oy;
 4397     oldy = data->cy;
 4398 
 4399     grid_reader_start(&gr, back_s->grid, px, py);
 4400     grid_reader_cursor_left(&gr, 1);
 4401     grid_reader_get_cursor(&gr, &px, &py);
 4402     window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
 4403 }
 4404 
 4405 static void
 4406 window_copy_cursor_right(struct window_mode_entry *wme, int all)
 4407 {
 4408     struct window_copy_mode_data    *data = wme->data;
 4409     struct screen           *back_s = data->backing;
 4410     struct grid_reader       gr;
 4411     u_int                px, py, oldy, hsize;
 4412 
 4413     px = data->cx;
 4414     hsize = screen_hsize(back_s);
 4415     py = hsize + data->cy - data->oy;
 4416     oldy = data->cy;
 4417 
 4418     grid_reader_start(&gr, back_s->grid, px, py);
 4419     grid_reader_cursor_right(&gr, 1, all);
 4420     grid_reader_get_cursor(&gr, &px, &py);
 4421     window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
 4422         data->oy, oldy, px, py, 0);
 4423 }
 4424 
 4425 static void
 4426 window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only)
 4427 {
 4428     struct window_copy_mode_data    *data = wme->data;
 4429     struct screen           *s = &data->screen;
 4430     u_int                ox, oy, px, py;
 4431     int              norectsel;
 4432 
 4433     norectsel = data->screen.sel == NULL || !data->rectflag;
 4434     oy = screen_hsize(data->backing) + data->cy - data->oy;
 4435     ox = window_copy_find_length(wme, oy);
 4436     if (norectsel && data->cx != ox) {
 4437         data->lastcx = data->cx;
 4438         data->lastsx = ox;
 4439     }
 4440 
 4441     if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
 4442         window_copy_other_end(wme);
 4443 
 4444     if (scroll_only || data->cy == 0) {
 4445         if (norectsel)
 4446             data->cx = data->lastcx;
 4447         window_copy_scroll_down(wme, 1);
 4448         if (scroll_only) {
 4449             if (data->cy == screen_size_y(s) - 1)
 4450                 window_copy_redraw_lines(wme, data->cy, 1);
 4451             else
 4452                 window_copy_redraw_lines(wme, data->cy, 2);
 4453         }
 4454     } else {
 4455         if (norectsel) {
 4456             window_copy_update_cursor(wme, data->lastcx,
 4457                 data->cy - 1);
 4458         } else
 4459             window_copy_update_cursor(wme, data->cx, data->cy - 1);
 4460         if (window_copy_update_selection(wme, 1, 0)) {
 4461             if (data->cy == screen_size_y(s) - 1)
 4462                 window_copy_redraw_lines(wme, data->cy, 1);
 4463             else
 4464                 window_copy_redraw_lines(wme, data->cy, 2);
 4465         }
 4466     }
 4467 
 4468     if (norectsel) {
 4469         py = screen_hsize(data->backing) + data->cy - data->oy;
 4470         px = window_copy_find_length(wme, py);
 4471         if ((data->cx >= data->lastsx && data->cx != px) ||
 4472             data->cx > px)
 4473         {
 4474             window_copy_update_cursor(wme, px, data->cy);
 4475             if (window_copy_update_selection(wme, 1, 0))
 4476                 window_copy_redraw_lines(wme, data->cy, 1);
 4477         }
 4478     }
 4479 
 4480     if (data->lineflag == LINE_SEL_LEFT_RIGHT)
 4481     {
 4482         py = screen_hsize(data->backing) + data->cy - data->oy;
 4483         if (data->rectflag)
 4484             px = screen_size_x(data->backing);
 4485         else
 4486             px = window_copy_find_length(wme, py);
 4487         window_copy_update_cursor(wme, px, data->cy);
 4488         if (window_copy_update_selection(wme, 1, 0))
 4489             window_copy_redraw_lines(wme, data->cy, 1);
 4490     }
 4491     else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
 4492     {
 4493         window_copy_update_cursor(wme, 0, data->cy);
 4494         if (window_copy_update_selection(wme, 1, 0))
 4495             window_copy_redraw_lines(wme, data->cy, 1);
 4496     }
 4497 }
 4498 
 4499 static void
 4500 window_copy_cursor_down(struct window_mode_entry *wme, int scroll_only)
 4501 {
 4502     struct window_copy_mode_data    *data = wme->data;
 4503     struct screen           *s = &data->screen;
 4504     u_int                ox, oy, px, py;
 4505     int              norectsel;
 4506 
 4507     norectsel = data->screen.sel == NULL || !data->rectflag;
 4508     oy = screen_hsize(data->backing) + data->cy - data->oy;
 4509     ox = window_copy_find_length(wme, oy);
 4510     if (norectsel && data->cx != ox) {
 4511         data->lastcx = data->cx;
 4512         data->lastsx = ox;
 4513     }
 4514 
 4515     if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
 4516         window_copy_other_end(wme);
 4517 
 4518     if (scroll_only || data->cy == screen_size_y(s) - 1) {
 4519         if (norectsel)
 4520             data->cx = data->lastcx;
 4521         window_copy_scroll_up(wme, 1);
 4522         if (scroll_only && data->cy > 0)
 4523             window_copy_redraw_lines(wme, data->cy - 1, 2);
 4524     } else {
 4525         if (norectsel) {
 4526             window_copy_update_cursor(wme, data->lastcx,
 4527                 data->cy + 1);
 4528         } else
 4529             window_copy_update_cursor(wme, data->cx, data->cy + 1);
 4530         if (window_copy_update_selection(wme, 1, 0))
 4531             window_copy_redraw_lines(wme, data->cy - 1, 2);
 4532     }
 4533 
 4534     if (norectsel) {
 4535         py = screen_hsize(data->backing) + data->cy - data->oy;
 4536         px = window_copy_find_length(wme, py);
 4537         if ((data->cx >= data->lastsx && data->cx != px) ||
 4538             data->cx > px)
 4539         {
 4540             window_copy_update_cursor(wme, px, data->cy);
 4541             if (window_copy_update_selection(wme, 1, 0))
 4542                 window_copy_redraw_lines(wme, data->cy, 1);
 4543         }
 4544     }
 4545 
 4546     if (data->lineflag == LINE_SEL_LEFT_RIGHT)
 4547     {
 4548         py = screen_hsize(data->backing) + data->cy - data->oy;
 4549         if (data->rectflag)
 4550             px = screen_size_x(data->backing);
 4551         else
 4552             px = window_copy_find_length(wme, py);
 4553         window_copy_update_cursor(wme, px, data->cy);
 4554         if (window_copy_update_selection(wme, 1, 0))
 4555             window_copy_redraw_lines(wme, data->cy, 1);
 4556     }
 4557     else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
 4558     {
 4559         window_copy_update_cursor(wme, 0, data->cy);
 4560         if (window_copy_update_selection(wme, 1, 0))
 4561             window_copy_redraw_lines(wme, data->cy, 1);
 4562     }
 4563 }
 4564 
 4565 static void
 4566 window_copy_cursor_jump(struct window_mode_entry *wme)
 4567 {
 4568     struct window_copy_mode_data    *data = wme->data;
 4569     struct screen           *back_s = data->backing;
 4570     struct grid_reader       gr;
 4571     u_int                px, py, oldy, hsize;
 4572 
 4573     px = data->cx + 1;
 4574     hsize = screen_hsize(back_s);
 4575     py = hsize + data->cy - data->oy;
 4576     oldy = data->cy;
 4577 
 4578     grid_reader_start(&gr, back_s->grid, px, py);
 4579     if (grid_reader_cursor_jump(&gr, data->jumpchar)) {
 4580         grid_reader_get_cursor(&gr, &px, &py);
 4581         window_copy_acquire_cursor_down(wme, hsize,
 4582             screen_size_y(back_s), data->oy, oldy, px, py, 0);
 4583     }
 4584 }
 4585 
 4586 static void
 4587 window_copy_cursor_jump_back(struct window_mode_entry *wme)
 4588 {
 4589     struct window_copy_mode_data    *data = wme->data;
 4590     struct screen           *back_s = data->backing;
 4591     struct grid_reader       gr;
 4592     u_int                px, py, oldy, hsize;
 4593 
 4594     px = data->cx;
 4595     hsize = screen_hsize(back_s);
 4596     py = hsize + data->cy - data->oy;
 4597     oldy = data->cy;
 4598 
 4599     grid_reader_start(&gr, back_s->grid, px, py);
 4600     grid_reader_cursor_left(&gr, 0);
 4601     if (grid_reader_cursor_jump_back(&gr, data->jumpchar)) {
 4602         grid_reader_get_cursor(&gr, &px, &py);
 4603         window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px,
 4604             py);
 4605     }
 4606 }
 4607 
 4608 static void
 4609 window_copy_cursor_jump_to(struct window_mode_entry *wme)
 4610 {
 4611     struct window_copy_mode_data    *data = wme->data;
 4612     struct screen           *back_s = data->backing;
 4613     struct grid_reader       gr;
 4614     u_int                px, py, oldy, hsize;
 4615 
 4616     px = data->cx + 2;
 4617     hsize = screen_hsize(back_s);
 4618     py = hsize + data->cy - data->oy;
 4619     oldy = data->cy;
 4620 
 4621     grid_reader_start(&gr, back_s->grid, px, py);
 4622     if (grid_reader_cursor_jump(&gr, data->jumpchar)) {
 4623         grid_reader_cursor_left(&gr, 1);
 4624         grid_reader_get_cursor(&gr, &px, &py);
 4625         window_copy_acquire_cursor_down(wme, hsize,
 4626             screen_size_y(back_s), data->oy, oldy, px, py, 0);
 4627     }
 4628 }
 4629 
 4630 static void
 4631 window_copy_cursor_jump_to_back(struct window_mode_entry *wme)
 4632 {
 4633     struct window_copy_mode_data    *data = wme->data;
 4634     struct screen           *back_s = data->backing;
 4635     struct grid_reader       gr;
 4636     u_int                px, py, oldy, hsize;
 4637 
 4638     px = data->cx;
 4639     hsize = screen_hsize(back_s);
 4640     py = hsize + data->cy - data->oy;
 4641     oldy = data->cy;
 4642 
 4643     grid_reader_start(&gr, back_s->grid, px, py);
 4644     grid_reader_cursor_left(&gr, 0);
 4645     grid_reader_cursor_left(&gr, 0);
 4646     if (grid_reader_cursor_jump_back(&gr, data->jumpchar)) {
 4647         grid_reader_cursor_right(&gr, 1, 0);
 4648         grid_reader_get_cursor(&gr, &px, &py);
 4649         window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px,
 4650             py);
 4651     }
 4652 }
 4653 
 4654 static void
 4655 window_copy_cursor_next_word(struct window_mode_entry *wme,
 4656     const char *separators)
 4657 {
 4658     struct window_copy_mode_data    *data = wme->data;
 4659     struct screen           *back_s = data->backing;
 4660     struct grid_reader       gr;
 4661     u_int                px, py, oldy, hsize;
 4662 
 4663     px = data->cx;
 4664     hsize = screen_hsize(back_s);
 4665     py =  hsize + data->cy - data->oy;
 4666     oldy = data->cy;
 4667 
 4668     grid_reader_start(&gr, back_s->grid, px, py);
 4669     grid_reader_cursor_next_word(&gr, separators);
 4670     grid_reader_get_cursor(&gr, &px, &py);
 4671     window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
 4672         data->oy, oldy, px, py, 0);
 4673 }
 4674 
 4675 /* Compute the next place where a word ends. */
 4676 static void
 4677 window_copy_cursor_next_word_end_pos(struct window_mode_entry *wme,
 4678     const char *separators, u_int *ppx, u_int *ppy)
 4679 {
 4680     struct window_pane      *wp = wme->wp;
 4681     struct window_copy_mode_data    *data = wme->data;
 4682     struct options          *oo = wp->window->options;
 4683     struct screen           *back_s = data->backing;
 4684     struct grid_reader       gr;
 4685     u_int                px, py, hsize;
 4686     int              keys;
 4687 
 4688     px = data->cx;
 4689     hsize = screen_hsize(back_s);
 4690     py =  hsize + data->cy - data->oy;
 4691 
 4692     grid_reader_start(&gr, back_s->grid, px, py);
 4693     keys = options_get_number(oo, "mode-keys");
 4694     if (keys == MODEKEY_VI && !grid_reader_in_set(&gr, separators))
 4695         grid_reader_cursor_right(&gr, 0, 0);
 4696     grid_reader_cursor_next_word_end(&gr, separators);
 4697     if (keys == MODEKEY_VI)
 4698         grid_reader_cursor_left(&gr, 1);
 4699     grid_reader_get_cursor(&gr, &px, &py);
 4700     *ppx = px;
 4701     *ppy = py;
 4702 }
 4703 
 4704 /* Move to the next place where a word ends. */
 4705 static void
 4706 window_copy_cursor_next_word_end(struct window_mode_entry *wme,
 4707     const char *separators, int no_reset)
 4708 {
 4709     struct window_pane      *wp = wme->wp;
 4710     struct window_copy_mode_data    *data = wme->data;
 4711     struct options          *oo = wp->window->options;
 4712     struct screen           *back_s = data->backing;
 4713     struct grid_reader       gr;
 4714     u_int                px, py, oldy, hsize;
 4715     int              keys;
 4716 
 4717     px = data->cx;
 4718     hsize = screen_hsize(back_s);
 4719     py =  hsize + data->cy - data->oy;
 4720     oldy = data->cy;
 4721 
 4722     grid_reader_start(&gr, back_s->grid, px, py);
 4723     keys = options_get_number(oo, "mode-keys");
 4724     if (keys == MODEKEY_VI && !grid_reader_in_set(&gr, separators))
 4725         grid_reader_cursor_right(&gr, 0, 0);
 4726     grid_reader_cursor_next_word_end(&gr, separators);
 4727     if (keys == MODEKEY_VI)
 4728         grid_reader_cursor_left(&gr, 1);
 4729     grid_reader_get_cursor(&gr, &px, &py);
 4730     window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
 4731         data->oy, oldy, px, py, no_reset);
 4732 }
 4733 
 4734 /* Compute the previous place where a word begins. */
 4735 static void
 4736 window_copy_cursor_previous_word_pos(struct window_mode_entry *wme,
 4737     const char *separators, int already, u_int *ppx, u_int *ppy)
 4738 {
 4739     struct window_copy_mode_data    *data = wme->data;
 4740     struct screen           *back_s = data->backing;
 4741     struct grid_reader       gr;
 4742     u_int                px, py, hsize;
 4743 
 4744     px = data->cx;
 4745     hsize = screen_hsize(back_s);
 4746     py = hsize + data->cy - data->oy;
 4747 
 4748     grid_reader_start(&gr, back_s->grid, px, py);
 4749     grid_reader_cursor_previous_word(&gr, separators, already);
 4750     grid_reader_get_cursor(&gr, &px, &py);
 4751     *ppx = px;
 4752     *ppy = py;
 4753 }
 4754 
 4755 /* Move to the previous place where a word begins. */
 4756 static void
 4757 window_copy_cursor_previous_word(struct window_mode_entry *wme,
 4758     const char *separators, int already)
 4759 {
 4760     struct window_copy_mode_data    *data = wme->data;
 4761     struct screen           *back_s = data->backing;
 4762     struct grid_reader       gr;
 4763     u_int                px, py, oldy, hsize;
 4764 
 4765     px = data->cx;
 4766     hsize = screen_hsize(back_s);
 4767     py = hsize + data->cy - data->oy;
 4768     oldy = data->cy;
 4769 
 4770     grid_reader_start(&gr, back_s->grid, px, py);
 4771     grid_reader_cursor_previous_word(&gr, separators, already);
 4772     grid_reader_get_cursor(&gr, &px, &py);
 4773     window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
 4774 }
 4775 
 4776 static void
 4777 window_copy_scroll_up(struct window_mode_entry *wme, u_int ny)
 4778 {
 4779     struct window_pane      *wp = wme->wp;
 4780     struct window_copy_mode_data    *data = wme->data;
 4781     struct screen           *s = &data->screen;
 4782     struct screen_write_ctx      ctx;
 4783 
 4784     if (data->oy < ny)
 4785         ny = data->oy;
 4786     if (ny == 0)
 4787         return;
 4788     data->oy -= ny;
 4789 
 4790     if (data->searchmark != NULL && !data->timeout)
 4791         window_copy_search_marks(wme, NULL, data->searchregex, 1);
 4792     window_copy_update_selection(wme, 0, 0);
 4793 
 4794     screen_write_start_pane(&ctx, wp, NULL);
 4795     screen_write_cursormove(&ctx, 0, 0, 0);
 4796     screen_write_deleteline(&ctx, ny, 8);
 4797     window_copy_write_lines(wme, &ctx, screen_size_y(s) - ny, ny);
 4798     window_copy_write_line(wme, &ctx, 0);
 4799     if (screen_size_y(s) > 1)
 4800         window_copy_write_line(wme, &ctx, 1);
 4801     if (screen_size_y(s) > 3)
 4802         window_copy_write_line(wme, &ctx, screen_size_y(s) - 2);
 4803     if (s->sel != NULL && screen_size_y(s) > ny)
 4804         window_copy_write_line(wme, &ctx, screen_size_y(s) - ny - 1);
 4805     screen_write_cursormove(&ctx, data->cx, data->cy, 0);
 4806     screen_write_stop(&ctx);
 4807 }
 4808 
 4809 static void
 4810 window_copy_scroll_down(struct window_mode_entry *wme, u_int ny)
 4811 {
 4812     struct window_pane      *wp = wme->wp;
 4813     struct window_copy_mode_data    *data = wme->data;
 4814     struct screen           *s = &data->screen;
 4815     struct screen_write_ctx      ctx;
 4816 
 4817     if (ny > screen_hsize(data->backing))
 4818         return;
 4819 
 4820     if (data->oy > screen_hsize(data->backing) - ny)
 4821         ny = screen_hsize(data->backing) - data->oy;
 4822     if (ny == 0)
 4823         return;
 4824     data->oy += ny;
 4825 
 4826     if (data->searchmark != NULL && !data->timeout)
 4827         window_copy_search_marks(wme, NULL, data->searchregex, 1);
 4828     window_copy_update_selection(wme, 0, 0);
 4829 
 4830     screen_write_start_pane(&ctx, wp, NULL);
 4831     screen_write_cursormove(&ctx, 0, 0, 0);
 4832     screen_write_insertline(&ctx, ny, 8);
 4833     window_copy_write_lines(wme, &ctx, 0, ny);
 4834     if (s->sel != NULL && screen_size_y(s) > ny)
 4835         window_copy_write_line(wme, &ctx, ny);
 4836     else if (ny == 1) /* nuke position */
 4837         window_copy_write_line(wme, &ctx, 1);
 4838     screen_write_cursormove(&ctx, data->cx, data->cy, 0);
 4839     screen_write_stop(&ctx);
 4840 }
 4841 
 4842 static void
 4843 window_copy_rectangle_set(struct window_mode_entry *wme, int rectflag)
 4844 {
 4845     struct window_copy_mode_data    *data = wme->data;
 4846     u_int                px, py;
 4847 
 4848     data->rectflag = rectflag;
 4849 
 4850     py = screen_hsize(data->backing) + data->cy - data->oy;
 4851     px = window_copy_find_length(wme, py);
 4852     if (data->cx > px)
 4853         window_copy_update_cursor(wme, px, data->cy);
 4854 
 4855     window_copy_update_selection(wme, 1, 0);
 4856     window_copy_redraw_screen(wme);
 4857 }
 4858 
 4859 static void
 4860 window_copy_move_mouse(struct mouse_event *m)
 4861 {
 4862     struct window_pane      *wp;
 4863     struct window_mode_entry    *wme;
 4864     u_int                x, y;
 4865 
 4866     wp = cmd_mouse_pane(m, NULL, NULL);
 4867     if (wp == NULL)
 4868         return;
 4869     wme = TAILQ_FIRST(&wp->modes);
 4870     if (wme == NULL)
 4871         return;
 4872     if (wme->mode != &window_copy_mode && wme->mode != &window_view_mode)
 4873         return;
 4874 
 4875     if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
 4876         return;
 4877 
 4878     window_copy_update_cursor(wme, x, y);
 4879 }
 4880 
 4881 void
 4882 window_copy_start_drag(struct client *c, struct mouse_event *m)
 4883 {
 4884     struct window_pane      *wp;
 4885     struct window_mode_entry    *wme;
 4886     struct window_copy_mode_data    *data;
 4887     u_int                x, y, yg;
 4888 
 4889     if (c == NULL)
 4890         return;
 4891 
 4892     wp = cmd_mouse_pane(m, NULL, NULL);
 4893     if (wp == NULL)
 4894         return;
 4895     wme = TAILQ_FIRST(&wp->modes);
 4896     if (wme == NULL)
 4897         return;
 4898     if (wme->mode != &window_copy_mode && wme->mode != &window_view_mode)
 4899         return;
 4900 
 4901     if (cmd_mouse_at(wp, m, &x, &y, 1) != 0)
 4902         return;
 4903 
 4904     c->tty.mouse_drag_update = window_copy_drag_update;
 4905     c->tty.mouse_drag_release = window_copy_drag_release;
 4906 
 4907     data = wme->data;
 4908     yg = screen_hsize(data->backing) + y - data->oy;
 4909     if (x < data->selrx || x > data->endselrx || yg != data->selry)
 4910         data->selflag = SEL_CHAR;
 4911     switch (data->selflag) {
 4912     case SEL_WORD:
 4913         if (data->ws != NULL) {
 4914             window_copy_update_cursor(wme, x, y);
 4915             window_copy_cursor_previous_word_pos(wme, data->ws, 0,
 4916                 &x, &y);
 4917             y -= screen_hsize(data->backing) - data->oy;
 4918         }
 4919         window_copy_update_cursor(wme, x, y);
 4920         break;
 4921     case SEL_LINE:
 4922         window_copy_update_cursor(wme, 0, y);
 4923         break;
 4924     case SEL_CHAR:
 4925         window_copy_update_cursor(wme, x, y);
 4926         window_copy_start_selection(wme);
 4927         break;
 4928     }
 4929 
 4930     window_copy_redraw_screen(wme);
 4931     window_copy_drag_update(c, m);
 4932 }
 4933 
 4934 static void
 4935 window_copy_drag_update(struct client *c, struct mouse_event *m)
 4936 {
 4937     struct window_pane      *wp;
 4938     struct window_mode_entry    *wme;
 4939     struct window_copy_mode_data    *data;
 4940     u_int                x, y, old_cx, old_cy;
 4941     struct timeval           tv = {
 4942         .tv_usec = WINDOW_COPY_DRAG_REPEAT_TIME
 4943     };
 4944 
 4945     if (c == NULL)
 4946         return;
 4947 
 4948     wp = cmd_mouse_pane(m, NULL, NULL);
 4949     if (wp == NULL)
 4950         return;
 4951     wme = TAILQ_FIRST(&wp->modes);
 4952     if (wme == NULL)
 4953         return;
 4954     if (wme->mode != &window_copy_mode && wme->mode != &window_view_mode)
 4955         return;
 4956 
 4957     data = wme->data;
 4958     evtimer_del(&data->dragtimer);
 4959 
 4960     if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
 4961         return;
 4962     old_cx = data->cx;
 4963     old_cy = data->cy;
 4964 
 4965     window_copy_update_cursor(wme, x, y);
 4966     if (window_copy_update_selection(wme, 1, 0))
 4967         window_copy_redraw_selection(wme, old_cy);
 4968     if (old_cy != data->cy || old_cx == data->cx) {
 4969         if (y == 0) {
 4970             evtimer_add(&data->dragtimer, &tv);
 4971             window_copy_cursor_up(wme, 1);
 4972         } else if (y == screen_size_y(&data->screen) - 1) {
 4973             evtimer_add(&data->dragtimer, &tv);
 4974             window_copy_cursor_down(wme, 1);
 4975         }
 4976     }
 4977 }
 4978 
 4979 static void
 4980 window_copy_drag_release(struct client *c, struct mouse_event *m)
 4981 {
 4982     struct window_pane      *wp;
 4983     struct window_mode_entry    *wme;
 4984     struct window_copy_mode_data    *data;
 4985 
 4986     if (c == NULL)
 4987         return;
 4988 
 4989     wp = cmd_mouse_pane(m, NULL, NULL);
 4990     if (wp == NULL)
 4991         return;
 4992     wme = TAILQ_FIRST(&wp->modes);
 4993     if (wme == NULL)
 4994         return;
 4995     if (wme->mode != &window_copy_mode && wme->mode != &window_view_mode)
 4996         return;
 4997 
 4998     data = wme->data;
 4999     evtimer_del(&data->dragtimer);
 5000 }
 5001 
 5002 static void
 5003 window_copy_jump_to_mark(struct window_mode_entry *wme)
 5004 {
 5005     struct window_copy_mode_data    *data = wme->data;
 5006     u_int                tmx, tmy;
 5007 
 5008     tmx = data->cx;
 5009     tmy = screen_