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