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