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