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