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