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