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