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