xref: /openbsd/usr.bin/tmux/window-copy.c (revision 8529ddd3)
1 /* $OpenBSD: window-copy.c,v 1.130 2015/04/24 22:19:36 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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 struct screen *window_copy_init(struct window_pane *);
28 void	window_copy_free(struct window_pane *);
29 void	window_copy_resize(struct window_pane *, u_int, u_int);
30 void	window_copy_key(struct window_pane *, struct client *, struct session *,
31 	    int, struct mouse_event *);
32 int	window_copy_key_input(struct window_pane *, int);
33 int	window_copy_key_numeric_prefix(struct window_pane *, int);
34 
35 void	window_copy_redraw_selection(struct window_pane *, u_int);
36 void	window_copy_redraw_lines(struct window_pane *, u_int, u_int);
37 void	window_copy_redraw_screen(struct window_pane *);
38 void	window_copy_write_line(struct window_pane *, struct screen_write_ctx *,
39 	    u_int);
40 void	window_copy_write_lines(struct window_pane *,
41 	    struct screen_write_ctx *, u_int, u_int);
42 
43 void	window_copy_scroll_to(struct window_pane *, u_int, u_int);
44 int	window_copy_search_compare(struct grid *, u_int, u_int, struct grid *,
45 	    u_int, int);
46 int	window_copy_search_lr(struct grid *, struct grid *, u_int *, u_int,
47 	    u_int, u_int, int);
48 int	window_copy_search_rl(struct grid *, struct grid *, u_int *, u_int,
49 	    u_int, u_int, int);
50 void	window_copy_search_up(struct window_pane *, const char *);
51 void	window_copy_search_down(struct window_pane *, const char *);
52 void	window_copy_goto_line(struct window_pane *, const char *);
53 void	window_copy_update_cursor(struct window_pane *, u_int, u_int);
54 void	window_copy_start_selection(struct window_pane *);
55 int	window_copy_update_selection(struct window_pane *, int);
56 void   *window_copy_get_selection(struct window_pane *, size_t *);
57 void	window_copy_copy_buffer(struct window_pane *, const char *, void *,
58 	    size_t);
59 void	window_copy_copy_pipe(struct window_pane *, struct session *,
60 	    const char *, const char *);
61 void	window_copy_copy_selection(struct window_pane *, const char *);
62 void	window_copy_append_selection(struct window_pane *, const char *);
63 void	window_copy_clear_selection(struct window_pane *);
64 void	window_copy_copy_line(struct window_pane *, char **, size_t *, u_int,
65 	    u_int, u_int);
66 int	window_copy_in_set(struct window_pane *, u_int, u_int, const char *);
67 u_int	window_copy_find_length(struct window_pane *, u_int);
68 void	window_copy_cursor_start_of_line(struct window_pane *);
69 void	window_copy_cursor_back_to_indentation(struct window_pane *);
70 void	window_copy_cursor_end_of_line(struct window_pane *);
71 void	window_copy_other_end(struct window_pane *);
72 void	window_copy_cursor_left(struct window_pane *);
73 void	window_copy_cursor_right(struct window_pane *);
74 void	window_copy_cursor_up(struct window_pane *, int);
75 void	window_copy_cursor_down(struct window_pane *, int);
76 void	window_copy_cursor_jump(struct window_pane *);
77 void	window_copy_cursor_jump_back(struct window_pane *);
78 void	window_copy_cursor_jump_to(struct window_pane *, int);
79 void	window_copy_cursor_jump_to_back(struct window_pane *, int);
80 void	window_copy_cursor_next_word(struct window_pane *, const char *);
81 void	window_copy_cursor_next_word_end(struct window_pane *, const char *);
82 void	window_copy_cursor_previous_word(struct window_pane *, const char *);
83 void	window_copy_scroll_up(struct window_pane *, u_int);
84 void	window_copy_scroll_down(struct window_pane *, u_int);
85 void	window_copy_rectangle_toggle(struct window_pane *);
86 void	window_copy_drag_update(struct client *, struct mouse_event *);
87 void	window_copy_drag_release(struct client *, struct mouse_event *);
88 
89 const struct window_mode window_copy_mode = {
90 	window_copy_init,
91 	window_copy_free,
92 	window_copy_resize,
93 	window_copy_key,
94 	NULL,
95 };
96 
97 enum window_copy_input_type {
98 	WINDOW_COPY_OFF,
99 	WINDOW_COPY_NAMEDBUFFER,
100 	WINDOW_COPY_NUMERICPREFIX,
101 	WINDOW_COPY_SEARCHUP,
102 	WINDOW_COPY_SEARCHDOWN,
103 	WINDOW_COPY_JUMPFORWARD,
104 	WINDOW_COPY_JUMPBACK,
105 	WINDOW_COPY_JUMPTOFORWARD,
106 	WINDOW_COPY_JUMPTOBACK,
107 	WINDOW_COPY_GOTOLINE,
108 };
109 
110 /*
111  * Copy-mode's visible screen (the "screen" field) is filled from one of
112  * two sources: the original contents of the pane (used when we
113  * actually enter via the "copy-mode" command, to copy the contents of
114  * the current pane), or else a series of lines containing the output
115  * from an output-writing tmux command (such as any of the "show-*" or
116  * "list-*" commands).
117  *
118  * In either case, the full content of the copy-mode grid is pointed at
119  * by the "backing" field, and is copied into "screen" as needed (that
120  * is, when scrolling occurs). When copy-mode is backed by a pane,
121  * backing points directly at that pane's screen structure (&wp->base);
122  * when backed by a list of output-lines from a command, it points at
123  * a newly-allocated screen structure (which is deallocated when the
124  * mode ends).
125  */
126 struct window_copy_mode_data {
127 	struct screen		 screen;
128 
129 	struct screen		*backing;
130 	int			 backing_written; /* backing display started */
131 
132 	struct mode_key_data	 mdata;
133 
134 	u_int			 oy;
135 
136 	u_int			 selx;
137 	u_int			 sely;
138 
139 	u_int			 rectflag; /* are we in rectangle copy mode? */
140 
141 	u_int			 cx;
142 	u_int			 cy;
143 
144 	u_int			 lastcx; /* position in last line w/ content */
145 	u_int			 lastsx; /* size of last line w/ content */
146 
147 	enum window_copy_input_type inputtype;
148 	const char		*inputprompt;
149 	char			*inputstr;
150 	int			 inputexit;
151 
152 	int			 numprefix;
153 
154 	enum window_copy_input_type searchtype;
155 	char			*searchstr;
156 
157 	enum window_copy_input_type jumptype;
158 	char			 jumpchar;
159 };
160 
161 struct screen *
162 window_copy_init(struct window_pane *wp)
163 {
164 	struct window_copy_mode_data	*data;
165 	struct screen			*s;
166 	int				 keys;
167 
168 	wp->modedata = data = xmalloc(sizeof *data);
169 	data->oy = 0;
170 	data->cx = 0;
171 	data->cy = 0;
172 
173 	data->lastcx = 0;
174 	data->lastsx = 0;
175 
176 	data->backing_written = 0;
177 
178 	data->rectflag = 0;
179 
180 	data->inputtype = WINDOW_COPY_OFF;
181 	data->inputprompt = NULL;
182 	data->inputstr = xstrdup("");
183 	data->numprefix = -1;
184 
185 	data->searchtype = WINDOW_COPY_OFF;
186 	data->searchstr = NULL;
187 
188 	if (wp->fd != -1)
189 		bufferevent_disable(wp->event, EV_READ|EV_WRITE);
190 
191 	data->jumptype = WINDOW_COPY_OFF;
192 	data->jumpchar = '\0';
193 
194 	s = &data->screen;
195 	screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
196 
197 	keys = options_get_number(&wp->window->options, "mode-keys");
198 	if (keys == MODEKEY_EMACS)
199 		mode_key_init(&data->mdata, &mode_key_tree_emacs_copy);
200 	else
201 		mode_key_init(&data->mdata, &mode_key_tree_vi_copy);
202 	s->sel.modekeys = keys;
203 
204 	data->backing = NULL;
205 
206 	return (s);
207 }
208 
209 void
210 window_copy_init_from_pane(struct window_pane *wp)
211 {
212 	struct window_copy_mode_data	*data = wp->modedata;
213 	struct screen			*s = &data->screen;
214 	struct screen_write_ctx	 	 ctx;
215 	u_int				 i;
216 
217 	if (wp->mode != &window_copy_mode)
218 		fatalx("not in copy mode");
219 
220 	data->backing = &wp->base;
221 	data->cx = data->backing->cx;
222 	data->cy = data->backing->cy;
223 
224 	s->cx = data->cx;
225 	s->cy = data->cy;
226 
227 	screen_write_start(&ctx, NULL, s);
228 	for (i = 0; i < screen_size_y(s); i++)
229 		window_copy_write_line(wp, &ctx, i);
230 	screen_write_cursormove(&ctx, data->cx, data->cy);
231 	screen_write_stop(&ctx);
232 }
233 
234 void
235 window_copy_init_for_output(struct window_pane *wp)
236 {
237 	struct window_copy_mode_data	*data = wp->modedata;
238 
239 	data->backing = xmalloc(sizeof *data->backing);
240 	screen_init(data->backing, screen_size_x(&wp->base),
241 	    screen_size_y(&wp->base), UINT_MAX);
242 }
243 
244 void
245 window_copy_free(struct window_pane *wp)
246 {
247 	struct window_copy_mode_data	*data = wp->modedata;
248 
249 	if (wp->fd != -1)
250 		bufferevent_enable(wp->event, EV_READ|EV_WRITE);
251 
252 	free(data->searchstr);
253 	free(data->inputstr);
254 
255 	if (data->backing != &wp->base) {
256 		screen_free(data->backing);
257 		free(data->backing);
258 	}
259 	screen_free(&data->screen);
260 
261 	free(data);
262 }
263 
264 void
265 window_copy_add(struct window_pane *wp, const char *fmt, ...)
266 {
267 	va_list	ap;
268 
269 	va_start(ap, fmt);
270 	window_copy_vadd(wp, fmt, ap);
271 	va_end(ap);
272 }
273 
274 void
275 window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap)
276 {
277 	struct window_copy_mode_data	*data = wp->modedata;
278 	struct screen			*backing = data->backing;
279 	struct screen_write_ctx	 	 back_ctx, ctx;
280 	struct grid_cell		 gc;
281 	int				 utf8flag;
282 	u_int				 old_hsize, old_cy;
283 
284 	if (backing == &wp->base)
285 		return;
286 
287 	utf8flag = options_get_number(&wp->window->options, "utf8");
288 	memcpy(&gc, &grid_default_cell, sizeof gc);
289 
290 	old_hsize = screen_hsize(data->backing);
291 	screen_write_start(&back_ctx, NULL, backing);
292 	if (data->backing_written) {
293 		/*
294 		 * On the second or later line, do a CRLF before writing
295 		 * (so it's on a new line).
296 		 */
297 		screen_write_carriagereturn(&back_ctx);
298 		screen_write_linefeed(&back_ctx, 0);
299 	} else
300 		data->backing_written = 1;
301 	old_cy = backing->cy;
302 	screen_write_vnputs(&back_ctx, 0, &gc, utf8flag, fmt, ap);
303 	screen_write_stop(&back_ctx);
304 
305 	data->oy += screen_hsize(data->backing) - old_hsize;
306 
307 	screen_write_start(&ctx, wp, &data->screen);
308 
309 	/*
310 	 * If the history has changed, draw the top line.
311 	 * (If there's any history at all, it has changed.)
312 	 */
313 	if (screen_hsize(data->backing))
314 		window_copy_redraw_lines(wp, 0, 1);
315 
316 	/* Write the new lines. */
317 	window_copy_redraw_lines(wp, old_cy, backing->cy - old_cy + 1);
318 
319 	screen_write_stop(&ctx);
320 }
321 
322 void
323 window_copy_pageup(struct window_pane *wp)
324 {
325 	struct window_copy_mode_data	*data = wp->modedata;
326 	struct screen			*s = &data->screen;
327 	u_int				 n;
328 
329 	n = 1;
330 	if (screen_size_y(s) > 2)
331 		n = screen_size_y(s) - 2;
332 	if (data->oy + n > screen_hsize(data->backing))
333 		data->oy = screen_hsize(data->backing);
334 	else
335 		data->oy += n;
336 	window_copy_update_selection(wp, 1);
337 	window_copy_redraw_screen(wp);
338 }
339 
340 void
341 window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
342 {
343 	struct window_copy_mode_data	*data = wp->modedata;
344 	struct screen			*s = &data->screen;
345 	struct screen_write_ctx	 	 ctx;
346 
347 	screen_resize(s, sx, sy, 1);
348 	if (data->backing != &wp->base)
349 		screen_resize(data->backing, sx, sy, 1);
350 
351 	if (data->cy > sy - 1)
352 		data->cy = sy - 1;
353 	if (data->cx > sx)
354 		data->cx = sx;
355 	if (data->oy > screen_hsize(data->backing))
356 		data->oy = screen_hsize(data->backing);
357 
358 	window_copy_clear_selection(wp);
359 
360 	screen_write_start(&ctx, NULL, s);
361 	window_copy_write_lines(wp, &ctx, 0, screen_size_y(s) - 1);
362 	screen_write_stop(&ctx);
363 
364 	window_copy_redraw_screen(wp);
365 }
366 
367 void
368 window_copy_key(struct window_pane *wp, struct client *c, struct session *sess,
369     int key, struct mouse_event *m)
370 {
371 	const char			*word_separators;
372 	struct window_copy_mode_data	*data = wp->modedata;
373 	struct screen			*s = &data->screen;
374 	u_int				 n, np;
375 	int				 keys;
376 	enum mode_key_cmd		 cmd;
377 	const char			*arg, *ss;
378 
379 	np = 1;
380 	if (data->numprefix > 0)
381 		np = data->numprefix;
382 
383 	if (data->inputtype == WINDOW_COPY_JUMPFORWARD ||
384 	    data->inputtype == WINDOW_COPY_JUMPBACK ||
385 	    data->inputtype == WINDOW_COPY_JUMPTOFORWARD ||
386 	    data->inputtype == WINDOW_COPY_JUMPTOBACK) {
387 		/* Ignore keys with modifiers. */
388 		if ((key & KEYC_MASK_MOD) == 0) {
389 			data->jumpchar = key;
390 			if (data->inputtype == WINDOW_COPY_JUMPFORWARD) {
391 				for (; np != 0; np--)
392 					window_copy_cursor_jump(wp);
393 			}
394 			if (data->inputtype == WINDOW_COPY_JUMPBACK) {
395 				for (; np != 0; np--)
396 					window_copy_cursor_jump_back(wp);
397 			}
398 			if (data->inputtype == WINDOW_COPY_JUMPTOFORWARD) {
399 				for (; np != 0; np--)
400 					window_copy_cursor_jump_to(wp, 0);
401 			}
402 			if (data->inputtype == WINDOW_COPY_JUMPTOBACK) {
403 				for (; np != 0; np--)
404 					window_copy_cursor_jump_to_back(wp, 0);
405 			}
406 		}
407 		data->jumptype = data->inputtype;
408 		data->inputtype = WINDOW_COPY_OFF;
409 		window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
410 		return;
411 	} else if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) {
412 		if (window_copy_key_numeric_prefix(wp, key) == 0)
413 			return;
414 		data->inputtype = WINDOW_COPY_OFF;
415 		window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
416 	} else if (data->inputtype != WINDOW_COPY_OFF) {
417 		if (window_copy_key_input(wp, key) != 0)
418 			goto input_off;
419 		return;
420 	}
421 
422 	cmd = mode_key_lookup(&data->mdata, key, &arg);
423 	switch (cmd) {
424 	case MODEKEYCOPY_APPENDSELECTION:
425 		if (sess != NULL) {
426 			window_copy_append_selection(wp, NULL);
427 			if (arg == NULL) {
428 				window_pane_reset_mode(wp);
429 				return;
430 			}
431 			window_copy_clear_selection(wp);
432 			window_copy_redraw_screen(wp);
433 		}
434 		break;
435 	case MODEKEYCOPY_CANCEL:
436 		window_pane_reset_mode(wp);
437 		return;
438 	case MODEKEYCOPY_OTHEREND:
439 		if (np % 2)
440 			window_copy_other_end(wp);
441 		break;
442 	case MODEKEYCOPY_LEFT:
443 		for (; np != 0; np--)
444 			window_copy_cursor_left(wp);
445 		break;
446 	case MODEKEYCOPY_RIGHT:
447 		for (; np != 0; np--)
448 			window_copy_cursor_right(wp);
449 		break;
450 	case MODEKEYCOPY_UP:
451 		for (; np != 0; np--)
452 			window_copy_cursor_up(wp, 0);
453 		break;
454 	case MODEKEYCOPY_DOWN:
455 		for (; np != 0; np--)
456 			window_copy_cursor_down(wp, 0);
457 		break;
458 	case MODEKEYCOPY_SCROLLUP:
459 		for (; np != 0; np--)
460 			window_copy_cursor_up(wp, 1);
461 		break;
462 	case MODEKEYCOPY_SCROLLDOWN:
463 		for (; np != 0; np--)
464 			window_copy_cursor_down(wp, 1);
465 		break;
466 	case MODEKEYCOPY_PREVIOUSPAGE:
467 		for (; np != 0; np--)
468 			window_copy_pageup(wp);
469 		break;
470 	case MODEKEYCOPY_NEXTPAGE:
471 		n = 1;
472 		if (screen_size_y(s) > 2)
473 			n = screen_size_y(s) - 2;
474 		for (; np != 0; np--) {
475 			if (data->oy < n)
476 				data->oy = 0;
477 			else
478 				data->oy -= n;
479 		}
480 		window_copy_update_selection(wp, 1);
481 		window_copy_redraw_screen(wp);
482 		break;
483 	case MODEKEYCOPY_HALFPAGEUP:
484 		n = screen_size_y(s) / 2;
485 		for (; np != 0; np--) {
486 			if (data->oy + n > screen_hsize(data->backing))
487 				data->oy = screen_hsize(data->backing);
488 			else
489 				data->oy += n;
490 		}
491 		window_copy_update_selection(wp, 1);
492 		window_copy_redraw_screen(wp);
493 		break;
494 	case MODEKEYCOPY_HALFPAGEDOWN:
495 		n = screen_size_y(s) / 2;
496 		for (; np != 0; np--) {
497 			if (data->oy < n)
498 				data->oy = 0;
499 			else
500 				data->oy -= n;
501 		}
502 		window_copy_update_selection(wp, 1);
503 		window_copy_redraw_screen(wp);
504 		break;
505 	case MODEKEYCOPY_TOPLINE:
506 		data->cx = 0;
507 		data->cy = 0;
508 		window_copy_update_selection(wp, 1);
509 		window_copy_redraw_screen(wp);
510 		break;
511 	case MODEKEYCOPY_MIDDLELINE:
512 		data->cx = 0;
513 		data->cy = (screen_size_y(s) - 1) / 2;
514 		window_copy_update_selection(wp, 1);
515 		window_copy_redraw_screen(wp);
516 		break;
517 	case MODEKEYCOPY_BOTTOMLINE:
518 		data->cx = 0;
519 		data->cy = screen_size_y(s) - 1;
520 		window_copy_update_selection(wp, 1);
521 		window_copy_redraw_screen(wp);
522 		break;
523 	case MODEKEYCOPY_HISTORYTOP:
524 		data->cx = 0;
525 		data->cy = 0;
526 		data->oy = screen_hsize(data->backing);
527 		window_copy_update_selection(wp, 1);
528 		window_copy_redraw_screen(wp);
529 		break;
530 	case MODEKEYCOPY_HISTORYBOTTOM:
531 		data->cx = 0;
532 		data->cy = screen_size_y(s) - 1;
533 		data->oy = 0;
534 		window_copy_update_selection(wp, 1);
535 		window_copy_redraw_screen(wp);
536 		break;
537 	case MODEKEYCOPY_STARTSELECTION:
538 		if (KEYC_IS_MOUSE(key)) {
539 			if (c != NULL)
540 				window_copy_start_drag(c, m);
541 		} else {
542 			s->sel.lineflag = LINE_SEL_NONE;
543 			window_copy_start_selection(wp);
544 			window_copy_redraw_screen(wp);
545 		}
546 		break;
547 	case MODEKEYCOPY_SELECTLINE:
548 		s->sel.lineflag = LINE_SEL_LEFT_RIGHT;
549 		data->rectflag = 0;
550 		/* FALLTHROUGH */
551 	case MODEKEYCOPY_COPYLINE:
552 		window_copy_cursor_start_of_line(wp);
553 		/* FALLTHROUGH */
554 	case MODEKEYCOPY_COPYENDOFLINE:
555 		window_copy_start_selection(wp);
556 		for (; np > 1; np--)
557 			window_copy_cursor_down(wp, 0);
558 		window_copy_cursor_end_of_line(wp);
559 		window_copy_redraw_screen(wp);
560 
561 		/* If a copy command then copy the selection and exit. */
562 		if (sess != NULL &&
563 		    (cmd == MODEKEYCOPY_COPYLINE ||
564 		    cmd == MODEKEYCOPY_COPYENDOFLINE)) {
565 			window_copy_copy_selection(wp, NULL);
566 			window_pane_reset_mode(wp);
567 			return;
568 		}
569 		break;
570 	case MODEKEYCOPY_CLEARSELECTION:
571 		window_copy_clear_selection(wp);
572 		window_copy_redraw_screen(wp);
573 		break;
574 	case MODEKEYCOPY_COPYPIPE:
575 		if (sess != NULL) {
576 			window_copy_copy_pipe(wp, sess, NULL, arg);
577 			window_pane_reset_mode(wp);
578 			return;
579 		}
580 		break;
581 	case MODEKEYCOPY_COPYSELECTION:
582 		if (sess != NULL) {
583 			window_copy_copy_selection(wp, NULL);
584 			if (arg == NULL) {
585 				window_pane_reset_mode(wp);
586 				return;
587 			}
588 			window_copy_clear_selection(wp);
589 			window_copy_redraw_screen(wp);
590 		}
591 		break;
592 	case MODEKEYCOPY_STARTOFLINE:
593 		window_copy_cursor_start_of_line(wp);
594 		break;
595 	case MODEKEYCOPY_BACKTOINDENTATION:
596 		window_copy_cursor_back_to_indentation(wp);
597 		break;
598 	case MODEKEYCOPY_ENDOFLINE:
599 		window_copy_cursor_end_of_line(wp);
600 		break;
601 	case MODEKEYCOPY_NEXTSPACE:
602 		for (; np != 0; np--)
603 			window_copy_cursor_next_word(wp, " ");
604 		break;
605 	case MODEKEYCOPY_NEXTSPACEEND:
606 		for (; np != 0; np--)
607 			window_copy_cursor_next_word_end(wp, " ");
608 		break;
609 	case MODEKEYCOPY_NEXTWORD:
610 		word_separators =
611 		    options_get_string(&sess->options, "word-separators");
612 		for (; np != 0; np--)
613 			window_copy_cursor_next_word(wp, word_separators);
614 		break;
615 	case MODEKEYCOPY_NEXTWORDEND:
616 		word_separators =
617 		    options_get_string(&sess->options, "word-separators");
618 		for (; np != 0; np--)
619 			window_copy_cursor_next_word_end(wp, word_separators);
620 		break;
621 	case MODEKEYCOPY_PREVIOUSSPACE:
622 		for (; np != 0; np--)
623 			window_copy_cursor_previous_word(wp, " ");
624 		break;
625 	case MODEKEYCOPY_PREVIOUSWORD:
626 		word_separators =
627 		    options_get_string(&sess->options, "word-separators");
628 		for (; np != 0; np--)
629 			window_copy_cursor_previous_word(wp, word_separators);
630 		break;
631 	case MODEKEYCOPY_JUMP:
632 		data->inputtype = WINDOW_COPY_JUMPFORWARD;
633 		data->inputprompt = "Jump Forward";
634 		*data->inputstr = '\0';
635 		window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
636 		return; /* skip numprefix reset */
637 	case MODEKEYCOPY_JUMPAGAIN:
638 		if (data->jumptype == WINDOW_COPY_JUMPFORWARD) {
639 			for (; np != 0; np--)
640 				window_copy_cursor_jump(wp);
641 		} else if (data->jumptype == WINDOW_COPY_JUMPBACK) {
642 			for (; np != 0; np--)
643 				window_copy_cursor_jump_back(wp);
644 		} else if (data->jumptype == WINDOW_COPY_JUMPTOFORWARD) {
645 			for (; np != 0; np--)
646 				window_copy_cursor_jump_to(wp, 1);
647 		} else if (data->jumptype == WINDOW_COPY_JUMPTOBACK) {
648 			for (; np != 0; np--)
649 				window_copy_cursor_jump_to_back(wp, 1);
650 		}
651 		break;
652 	case MODEKEYCOPY_JUMPREVERSE:
653 		if (data->jumptype == WINDOW_COPY_JUMPFORWARD) {
654 			for (; np != 0; np--)
655 				window_copy_cursor_jump_back(wp);
656 		} else if (data->jumptype == WINDOW_COPY_JUMPBACK) {
657 			for (; np != 0; np--)
658 				window_copy_cursor_jump(wp);
659 		} else if (data->jumptype == WINDOW_COPY_JUMPTOFORWARD) {
660 			for (; np != 0; np--)
661 				window_copy_cursor_jump_to_back(wp, 1);
662 		} else if (data->jumptype == WINDOW_COPY_JUMPTOBACK) {
663 			for (; np != 0; np--)
664 				window_copy_cursor_jump_to(wp, 1);
665 		}
666 		break;
667 	case MODEKEYCOPY_JUMPBACK:
668 		data->inputtype = WINDOW_COPY_JUMPBACK;
669 		data->inputprompt = "Jump Back";
670 		*data->inputstr = '\0';
671 		window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
672 		return; /* skip numprefix reset */
673 	case MODEKEYCOPY_JUMPTO:
674 		data->inputtype = WINDOW_COPY_JUMPTOFORWARD;
675 		data->inputprompt = "Jump To";
676 		*data->inputstr = '\0';
677 		window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
678 		return; /* skip numprefix reset */
679 	case MODEKEYCOPY_JUMPTOBACK:
680 		data->inputtype = WINDOW_COPY_JUMPTOBACK;
681 		data->inputprompt = "Jump To Back";
682 		*data->inputstr = '\0';
683 		window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
684 		return; /* skip numprefix reset */
685 	case MODEKEYCOPY_SEARCHUP:
686 		data->inputtype = WINDOW_COPY_SEARCHUP;
687 		data->inputprompt = "Search Up";
688 		goto input_on;
689 	case MODEKEYCOPY_SEARCHDOWN:
690 		data->inputtype = WINDOW_COPY_SEARCHDOWN;
691 		data->inputprompt = "Search Down";
692 		goto input_on;
693 	case MODEKEYCOPY_SEARCHAGAIN:
694 	case MODEKEYCOPY_SEARCHREVERSE:
695 		switch (data->searchtype) {
696 		case WINDOW_COPY_OFF:
697 		case WINDOW_COPY_GOTOLINE:
698 		case WINDOW_COPY_JUMPFORWARD:
699 		case WINDOW_COPY_JUMPBACK:
700 		case WINDOW_COPY_JUMPTOFORWARD:
701 		case WINDOW_COPY_JUMPTOBACK:
702 		case WINDOW_COPY_NAMEDBUFFER:
703 		case WINDOW_COPY_NUMERICPREFIX:
704 			break;
705 		case WINDOW_COPY_SEARCHUP:
706 			ss = data->searchstr;
707 			if (cmd == MODEKEYCOPY_SEARCHAGAIN) {
708 				for (; np != 0; np--)
709 					window_copy_search_up(wp, ss);
710 			} else {
711 				for (; np != 0; np--)
712 					window_copy_search_down(wp, ss);
713 			}
714 			break;
715 		case WINDOW_COPY_SEARCHDOWN:
716 			ss = data->searchstr;
717 			if (cmd == MODEKEYCOPY_SEARCHAGAIN) {
718 				for (; np != 0; np--)
719 					window_copy_search_down(wp, ss);
720 			} else {
721 				for (; np != 0; np--)
722 					window_copy_search_up(wp, ss);
723 			}
724 			break;
725 		}
726 		break;
727 	case MODEKEYCOPY_GOTOLINE:
728 		data->inputtype = WINDOW_COPY_GOTOLINE;
729 		data->inputprompt = "Goto Line";
730 		*data->inputstr = '\0';
731 		goto input_on;
732 	case MODEKEYCOPY_STARTNAMEDBUFFER:
733 		data->inputtype = WINDOW_COPY_NAMEDBUFFER;
734 		data->inputexit = (arg == NULL);
735 		data->inputprompt = "Buffer";
736 		*data->inputstr = '\0';
737 		goto input_on;
738 	case MODEKEYCOPY_STARTNUMBERPREFIX:
739 		key &= KEYC_MASK_KEY;
740 		if (key >= '0' && key <= '9') {
741 			data->inputtype = WINDOW_COPY_NUMERICPREFIX;
742 			data->numprefix = 0;
743 			window_copy_key_numeric_prefix(wp, key);
744 			return;
745 		}
746 		break;
747 	case MODEKEYCOPY_RECTANGLETOGGLE:
748 		s->sel.lineflag = LINE_SEL_NONE;
749 		window_copy_rectangle_toggle(wp);
750 		break;
751 	default:
752 		break;
753 	}
754 
755 	data->numprefix = -1;
756 	return;
757 
758 input_on:
759 	keys = options_get_number(&wp->window->options, "mode-keys");
760 	if (keys == MODEKEY_EMACS)
761 		mode_key_init(&data->mdata, &mode_key_tree_emacs_edit);
762 	else
763 		mode_key_init(&data->mdata, &mode_key_tree_vi_edit);
764 
765 	window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
766 	return;
767 
768 input_off:
769 	keys = options_get_number(&wp->window->options, "mode-keys");
770 	if (keys == MODEKEY_EMACS)
771 		mode_key_init(&data->mdata, &mode_key_tree_emacs_copy);
772 	else
773 		mode_key_init(&data->mdata, &mode_key_tree_vi_copy);
774 
775 	data->inputtype = WINDOW_COPY_OFF;
776 	data->inputprompt = NULL;
777 
778 	window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
779 }
780 
781 int
782 window_copy_key_input(struct window_pane *wp, int key)
783 {
784 	struct window_copy_mode_data	*data = wp->modedata;
785 	struct screen			*s = &data->screen;
786 	size_t				 inputlen, n;
787 	int				 np;
788 	struct paste_buffer		*pb;
789 	u_char				 ch;
790 
791 	switch (mode_key_lookup(&data->mdata, key, NULL)) {
792 	case MODEKEYEDIT_CANCEL:
793 		data->numprefix = -1;
794 		return (-1);
795 	case MODEKEYEDIT_BACKSPACE:
796 		inputlen = strlen(data->inputstr);
797 		if (inputlen > 0)
798 			data->inputstr[inputlen - 1] = '\0';
799 		break;
800 	case MODEKEYEDIT_DELETELINE:
801 		*data->inputstr = '\0';
802 		break;
803 	case MODEKEYEDIT_PASTE:
804 		if ((pb = paste_get_top()) == NULL)
805 			break;
806 		for (n = 0; n < pb->size; n++) {
807 			ch = (u_char) pb->data[n];
808 			if (ch < 32 || ch == 127)
809 				break;
810 		}
811 		inputlen = strlen(data->inputstr);
812 
813 		data->inputstr = xrealloc(data->inputstr, inputlen + n + 1);
814 		memcpy(data->inputstr + inputlen, pb->data, n);
815 		data->inputstr[inputlen + n] = '\0';
816 		break;
817 	case MODEKEYEDIT_ENTER:
818 		np = data->numprefix;
819 		if (np <= 0)
820 			np = 1;
821 
822 		switch (data->inputtype) {
823 		case WINDOW_COPY_OFF:
824 		case WINDOW_COPY_JUMPFORWARD:
825 		case WINDOW_COPY_JUMPBACK:
826 		case WINDOW_COPY_JUMPTOFORWARD:
827 		case WINDOW_COPY_JUMPTOBACK:
828 		case WINDOW_COPY_NUMERICPREFIX:
829 			break;
830 		case WINDOW_COPY_SEARCHUP:
831 			for (; np != 0; np--)
832 				window_copy_search_up(wp, data->inputstr);
833 			data->searchtype = data->inputtype;
834 			data->searchstr = xstrdup(data->inputstr);
835 			break;
836 		case WINDOW_COPY_SEARCHDOWN:
837 			for (; np != 0; np--)
838 				window_copy_search_down(wp, data->inputstr);
839 			data->searchtype = data->inputtype;
840 			data->searchstr = xstrdup(data->inputstr);
841 			break;
842 		case WINDOW_COPY_NAMEDBUFFER:
843 			window_copy_copy_selection(wp, data->inputstr);
844 			*data->inputstr = '\0';
845 			if (data->inputexit) {
846 				window_pane_reset_mode(wp);
847 				return (0);
848 			}
849 			window_copy_clear_selection(wp);
850 			window_copy_redraw_screen(wp);
851 			break;
852 		case WINDOW_COPY_GOTOLINE:
853 			window_copy_goto_line(wp, data->inputstr);
854 			*data->inputstr = '\0';
855 			break;
856 		}
857 		data->numprefix = -1;
858 		return (1);
859 	case MODEKEY_OTHER:
860 		if (key < 32 || key > 126)
861 			break;
862 		inputlen = strlen(data->inputstr) + 2;
863 
864 		data->inputstr = xrealloc(data->inputstr, inputlen);
865 		data->inputstr[inputlen - 2] = key;
866 		data->inputstr[inputlen - 1] = '\0';
867 		break;
868 	default:
869 		break;
870 	}
871 
872 	window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
873 	return (0);
874 }
875 
876 int
877 window_copy_key_numeric_prefix(struct window_pane *wp, int key)
878 {
879 	struct window_copy_mode_data	*data = wp->modedata;
880 	struct screen			*s = &data->screen;
881 
882 	key &= KEYC_MASK_KEY;
883 	if (key < '0' || key > '9')
884 		return (1);
885 
886 	if (data->numprefix >= 100) 	/* no more than three digits */
887 		return (0);
888 	data->numprefix = data->numprefix * 10 + key - '0';
889 
890 	window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
891 	return (0);
892 }
893 
894 void
895 window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py)
896 {
897 	struct window_copy_mode_data	*data = wp->modedata;
898 	struct grid			*gd = data->backing->grid;
899 	u_int				 offset, gap;
900 
901 	data->cx = px;
902 
903 	gap = gd->sy / 4;
904 	if (py < gd->sy) {
905 		offset = 0;
906 		data->cy = py;
907 	} else if (py > gd->hsize + gd->sy - gap) {
908 		offset = gd->hsize;
909 		data->cy = py - gd->hsize;
910 	} else {
911 		offset = py + gap - gd->sy;
912 		data->cy = py - offset;
913 	}
914 	data->oy = gd->hsize - offset;
915 
916 	window_copy_update_selection(wp, 1);
917 	window_copy_redraw_screen(wp);
918 }
919 
920 int
921 window_copy_search_compare(struct grid *gd, u_int px, u_int py,
922     struct grid *sgd, u_int spx, int cis)
923 {
924 	const struct grid_cell	*gc, *sgc;
925 	struct utf8_data	 ud, sud;
926 
927 	gc = grid_peek_cell(gd, px, py);
928 	grid_cell_get(gc, &ud);
929 	sgc = grid_peek_cell(sgd, spx, 0);
930 	grid_cell_get(sgc, &sud);
931 
932 	if (ud.size != sud.size || ud.width != sud.width)
933 		return (0);
934 
935 	if (cis && ud.size == 1)
936 		return (tolower(ud.data[0]) == sud.data[0]);
937 
938 	return (memcmp(ud.data, sud.data, ud.size) == 0);
939 }
940 
941 int
942 window_copy_search_lr(struct grid *gd,
943     struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
944 {
945 	u_int	ax, bx, px;
946 	int	matched;
947 
948 	for (ax = first; ax < last; ax++) {
949 		if (ax + sgd->sx >= gd->sx)
950 			break;
951 		for (bx = 0; bx < sgd->sx; bx++) {
952 			px = ax + bx;
953 			matched = window_copy_search_compare(gd, px, py, sgd,
954 			    bx, cis);
955 			if (!matched)
956 				break;
957 		}
958 		if (bx == sgd->sx) {
959 			*ppx = ax;
960 			return (1);
961 		}
962 	}
963 	return (0);
964 }
965 
966 int
967 window_copy_search_rl(struct grid *gd,
968     struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
969 {
970 	u_int	ax, bx, px;
971 	int	matched;
972 
973 	for (ax = last + 1; ax > first; ax--) {
974 		if (gd->sx - (ax - 1) < sgd->sx)
975 			continue;
976 		for (bx = 0; bx < sgd->sx; bx++) {
977 			px = ax - 1 + bx;
978 			matched = window_copy_search_compare(gd, px, py, sgd,
979 			    bx, cis);
980 			if (!matched)
981 				break;
982 		}
983 		if (bx == sgd->sx) {
984 			*ppx = ax - 1;
985 			return (1);
986 		}
987 	}
988 	return (0);
989 }
990 
991 void
992 window_copy_search_up(struct window_pane *wp, const char *searchstr)
993 {
994 	struct window_copy_mode_data	*data = wp->modedata;
995 	struct screen			*s = data->backing, ss;
996 	struct screen_write_ctx		 ctx;
997 	struct grid			*gd = s->grid, *sgd;
998 	struct grid_cell	 	 gc;
999 	size_t				 searchlen;
1000 	u_int				 i, last, fx, fy, px;
1001 	int				 utf8flag, n, wrapped, wrapflag, cis;
1002 	const char			*ptr;
1003 
1004 	if (*searchstr == '\0')
1005 		return;
1006 	utf8flag = options_get_number(&wp->window->options, "utf8");
1007 	wrapflag = options_get_number(&wp->window->options, "wrap-search");
1008 	searchlen = screen_write_strlen(utf8flag, "%s", searchstr);
1009 
1010 	screen_init(&ss, searchlen, 1, 0);
1011 	screen_write_start(&ctx, NULL, &ss);
1012 	memcpy(&gc, &grid_default_cell, sizeof gc);
1013 	screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr);
1014 	screen_write_stop(&ctx);
1015 
1016 	fx = data->cx;
1017 	fy = gd->hsize - data->oy + data->cy;
1018 
1019 	if (fx == 0) {
1020 		if (fy == 0)
1021 			return;
1022 		fx = gd->sx - 1;
1023 		fy--;
1024 	} else
1025 		fx--;
1026 	n = wrapped = 0;
1027 
1028 	cis = 1;
1029 	for (ptr = searchstr; *ptr != '\0'; ptr++) {
1030 		if (*ptr != tolower((u_char)*ptr)) {
1031 			cis = 0;
1032 			break;
1033 		}
1034 	}
1035 
1036 retry:
1037 	sgd = ss.grid;
1038 	for (i = fy + 1; i > 0; i--) {
1039 		last = screen_size_x(s);
1040 		if (i == fy + 1)
1041 			last = fx;
1042 		n = window_copy_search_rl(gd, sgd, &px, i - 1, 0, last, cis);
1043 		if (n) {
1044 			window_copy_scroll_to(wp, px, i - 1);
1045 			break;
1046 		}
1047 	}
1048 	if (wrapflag && !n && !wrapped) {
1049 		fx = gd->sx - 1;
1050 		fy = gd->hsize + gd->sy - 1;
1051 		wrapped = 1;
1052 		goto retry;
1053 	}
1054 
1055 	screen_free(&ss);
1056 }
1057 
1058 void
1059 window_copy_search_down(struct window_pane *wp, const char *searchstr)
1060 {
1061 	struct window_copy_mode_data	*data = wp->modedata;
1062 	struct screen			*s = data->backing, ss;
1063 	struct screen_write_ctx		 ctx;
1064 	struct grid			*gd = s->grid, *sgd;
1065 	struct grid_cell	 	 gc;
1066 	size_t				 searchlen;
1067 	u_int				 i, first, fx, fy, px;
1068 	int				 utf8flag, n, wrapped, wrapflag, cis;
1069 	const char			*ptr;
1070 
1071 	if (*searchstr == '\0')
1072 		return;
1073 	utf8flag = options_get_number(&wp->window->options, "utf8");
1074 	wrapflag = options_get_number(&wp->window->options, "wrap-search");
1075 	searchlen = screen_write_strlen(utf8flag, "%s", searchstr);
1076 
1077 	screen_init(&ss, searchlen, 1, 0);
1078 	screen_write_start(&ctx, NULL, &ss);
1079 	memcpy(&gc, &grid_default_cell, sizeof gc);
1080 	screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr);
1081 	screen_write_stop(&ctx);
1082 
1083 	fx = data->cx;
1084 	fy = gd->hsize - data->oy + data->cy;
1085 
1086 	if (fx == gd->sx - 1) {
1087 		if (fy == gd->hsize + gd->sy)
1088 			return;
1089 		fx = 0;
1090 		fy++;
1091 	} else
1092 		fx++;
1093 	n = wrapped = 0;
1094 
1095 	cis = 1;
1096 	for (ptr = searchstr; *ptr != '\0'; ptr++) {
1097 		if (*ptr != tolower((u_char)*ptr)) {
1098 			cis = 0;
1099 			break;
1100 		}
1101 	}
1102 
1103 retry:
1104 	sgd = ss.grid;
1105 	for (i = fy + 1; i < gd->hsize + gd->sy + 1; i++) {
1106 		first = 0;
1107 		if (i == fy + 1)
1108 			first = fx;
1109 		n = window_copy_search_lr(gd, sgd, &px, i - 1, first, gd->sx,
1110 		    cis);
1111 		if (n) {
1112 			window_copy_scroll_to(wp, px, i - 1);
1113 			break;
1114 		}
1115 	}
1116 	if (wrapflag && !n && !wrapped) {
1117 		fx = 0;
1118 		fy = 0;
1119 		wrapped = 1;
1120 		goto retry;
1121 	}
1122 
1123 	screen_free(&ss);
1124 }
1125 
1126 void
1127 window_copy_goto_line(struct window_pane *wp, const char *linestr)
1128 {
1129 	struct window_copy_mode_data	*data = wp->modedata;
1130 	const char			*errstr;
1131 	u_int				 lineno;
1132 
1133 	lineno = strtonum(linestr, 0, screen_hsize(data->backing), &errstr);
1134 	if (errstr != NULL)
1135 		return;
1136 
1137 	data->oy = lineno;
1138 	window_copy_update_selection(wp, 1);
1139 	window_copy_redraw_screen(wp);
1140 }
1141 
1142 void
1143 window_copy_write_line(struct window_pane *wp, struct screen_write_ctx *ctx,
1144     u_int py)
1145 {
1146 	struct window_copy_mode_data	*data = wp->modedata;
1147 	struct screen			*s = &data->screen;
1148 	struct options			*oo = &wp->window->options;
1149 	struct grid_cell		 gc;
1150 	char				 hdr[512];
1151 	size_t				 last, xoff = 0, size = 0, limit;
1152 
1153 	style_apply(&gc, oo, "mode-style");
1154 
1155 	last = screen_size_y(s) - 1;
1156 	if (py == 0) {
1157 		size = xsnprintf(hdr, sizeof hdr,
1158 		    "[%u/%u]", data->oy, screen_hsize(data->backing));
1159 		if (size > screen_size_x(s))
1160 			size = screen_size_x(s);
1161 		screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
1162 		screen_write_puts(ctx, &gc, "%s", hdr);
1163 	} else if (py == last && data->inputtype != WINDOW_COPY_OFF) {
1164 		limit = sizeof hdr;
1165 		if (limit > screen_size_x(s) + 1)
1166 			limit = screen_size_x(s) + 1;
1167 		if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) {
1168 			xoff = size = xsnprintf(hdr, limit,
1169 			    "Repeat: %d", data->numprefix);
1170 		} else {
1171 			xoff = size = xsnprintf(hdr, limit,
1172 			    "%s: %s", data->inputprompt, data->inputstr);
1173 		}
1174 		screen_write_cursormove(ctx, 0, last);
1175 		screen_write_puts(ctx, &gc, "%s", hdr);
1176 	} else
1177 		size = 0;
1178 
1179 	if (size < screen_size_x(s)) {
1180 		screen_write_cursormove(ctx, xoff, py);
1181 		screen_write_copy(ctx, data->backing, xoff,
1182 		    (screen_hsize(data->backing) - data->oy) + py,
1183 		    screen_size_x(s) - size, 1);
1184 	}
1185 
1186 	if (py == data->cy && data->cx == screen_size_x(s)) {
1187 		memcpy(&gc, &grid_default_cell, sizeof gc);
1188 		screen_write_cursormove(ctx, screen_size_x(s) - 1, py);
1189 		screen_write_putc(ctx, &gc, '$');
1190 	}
1191 }
1192 
1193 void
1194 window_copy_write_lines(struct window_pane *wp, struct screen_write_ctx *ctx,
1195     u_int py, u_int ny)
1196 {
1197 	u_int	yy;
1198 
1199 	for (yy = py; yy < py + ny; yy++)
1200 		window_copy_write_line(wp, ctx, py);
1201 }
1202 
1203 void
1204 window_copy_redraw_selection(struct window_pane *wp, u_int old_y)
1205 {
1206 	struct window_copy_mode_data	*data = wp->modedata;
1207 	u_int				 new_y, start, end;
1208 
1209 	new_y = data->cy;
1210 	if (old_y <= new_y) {
1211 		start = old_y;
1212 		end = new_y;
1213 	} else {
1214 		start = new_y;
1215 		end = old_y;
1216 	}
1217 	window_copy_redraw_lines(wp, start, end - start + 1);
1218 }
1219 
1220 void
1221 window_copy_redraw_lines(struct window_pane *wp, u_int py, u_int ny)
1222 {
1223 	struct window_copy_mode_data	*data = wp->modedata;
1224 	struct screen_write_ctx	 	 ctx;
1225 	u_int				 i;
1226 
1227 	screen_write_start(&ctx, wp, NULL);
1228 	for (i = py; i < py + ny; i++)
1229 		window_copy_write_line(wp, &ctx, i);
1230 	screen_write_cursormove(&ctx, data->cx, data->cy);
1231 	screen_write_stop(&ctx);
1232 }
1233 
1234 void
1235 window_copy_redraw_screen(struct window_pane *wp)
1236 {
1237 	struct window_copy_mode_data	*data = wp->modedata;
1238 
1239 	window_copy_redraw_lines(wp, 0, screen_size_y(&data->screen));
1240 }
1241 
1242 void
1243 window_copy_update_cursor(struct window_pane *wp, u_int cx, u_int cy)
1244 {
1245 	struct window_copy_mode_data	*data = wp->modedata;
1246 	struct screen			*s = &data->screen;
1247 	struct screen_write_ctx		 ctx;
1248 	u_int				 old_cx, old_cy;
1249 
1250 	old_cx = data->cx; old_cy = data->cy;
1251 	data->cx = cx; data->cy = cy;
1252 	if (old_cx == screen_size_x(s))
1253 		window_copy_redraw_lines(wp, old_cy, 1);
1254 	if (data->cx == screen_size_x(s))
1255 		window_copy_redraw_lines(wp, data->cy, 1);
1256 	else {
1257 		screen_write_start(&ctx, wp, NULL);
1258 		screen_write_cursormove(&ctx, data->cx, data->cy);
1259 		screen_write_stop(&ctx);
1260 	}
1261 }
1262 
1263 void
1264 window_copy_start_selection(struct window_pane *wp)
1265 {
1266 	struct window_copy_mode_data	*data = wp->modedata;
1267 	struct screen			*s = &data->screen;
1268 
1269 	data->selx = data->cx;
1270 	data->sely = screen_hsize(data->backing) + data->cy - data->oy;
1271 
1272 	s->sel.flag = 1;
1273 	window_copy_update_selection(wp, 1);
1274 }
1275 
1276 int
1277 window_copy_update_selection(struct window_pane *wp, int may_redraw)
1278 {
1279 	struct window_copy_mode_data	*data = wp->modedata;
1280 	struct screen			*s = &data->screen;
1281 	struct options			*oo = &wp->window->options;
1282 	struct grid_cell		 gc;
1283 	u_int				 sx, sy, ty, cy;
1284 
1285 	if (!s->sel.flag && s->sel.lineflag == LINE_SEL_NONE)
1286 		return (0);
1287 
1288 	/* Set colours. */
1289 	style_apply(&gc, oo, "mode-style");
1290 
1291 	/* Find top of screen. */
1292 	ty = screen_hsize(data->backing) - data->oy;
1293 
1294 	/* Adjust the selection. */
1295 	sx = data->selx;
1296 	sy = data->sely;
1297 	if (sy < ty) {					/* above screen */
1298 		if (!data->rectflag)
1299 			sx = 0;
1300 		sy = 0;
1301 	} else if (sy > ty + screen_size_y(s) - 1) {	/* below screen */
1302 		if (!data->rectflag)
1303 			sx = screen_size_x(s) - 1;
1304 		sy = screen_size_y(s) - 1;
1305 	} else
1306 		sy -= ty;
1307 	sy = screen_hsize(s) + sy;
1308 
1309 	screen_set_selection(s,
1310 	    sx, sy, data->cx, screen_hsize(s) + data->cy, data->rectflag, &gc);
1311 
1312 	if (data->rectflag && may_redraw) {
1313 		/*
1314 		 * Can't rely on the caller to redraw the right lines for
1315 		 * rectangle selection - find the highest line and the number
1316 		 * of lines, and redraw just past that in both directions
1317 		 */
1318 		cy = data->cy;
1319 		if (sy < cy)
1320 			window_copy_redraw_lines(wp, sy, cy - sy + 1);
1321 		else
1322 			window_copy_redraw_lines(wp, cy, sy - cy + 1);
1323 	}
1324 
1325 	return (1);
1326 }
1327 
1328 void *
1329 window_copy_get_selection(struct window_pane *wp, size_t *len)
1330 {
1331 	struct window_copy_mode_data	*data = wp->modedata;
1332 	struct screen			*s = &data->screen;
1333 	char				*buf;
1334 	size_t				 off;
1335 	u_int				 i, xx, yy, sx, sy, ex, ey, ey_last;
1336 	u_int				 firstsx, lastex, restex, restsx;
1337 	int				 keys;
1338 
1339 	if (!s->sel.flag && s->sel.lineflag == LINE_SEL_NONE)
1340 		return (NULL);
1341 
1342 	buf = xmalloc(1);
1343 	off = 0;
1344 
1345 	*buf = '\0';
1346 
1347 	/*
1348 	 * The selection extends from selx,sely to (adjusted) cx,cy on
1349 	 * the base screen.
1350 	 */
1351 
1352 	/* Find start and end. */
1353 	xx = data->cx;
1354 	yy = screen_hsize(data->backing) + data->cy - data->oy;
1355 	if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
1356 		sx = xx; sy = yy;
1357 		ex = data->selx; ey = data->sely;
1358 	} else {
1359 		sx = data->selx; sy = data->sely;
1360 		ex = xx; ey = yy;
1361 	}
1362 
1363 	/* Trim ex to end of line. */
1364 	ey_last = window_copy_find_length(wp, ey);
1365 	if (ex > ey_last)
1366 		ex = ey_last;
1367 
1368 	/*
1369 	 * Deal with rectangle-copy if necessary; four situations: start of
1370 	 * first line (firstsx), end of last line (lastex), start (restsx) and
1371 	 * end (restex) of all other lines.
1372 	 */
1373 	xx = screen_size_x(s);
1374 
1375 	/*
1376 	 * Behave according to mode-keys. If it is emacs, copy like emacs,
1377 	 * keeping the top-left-most character, and dropping the
1378 	 * bottom-right-most, regardless of copy direction. If it is vi, also
1379 	 * keep bottom-right-most character.
1380 	 */
1381 	keys = options_get_number(&wp->window->options, "mode-keys");
1382 	if (data->rectflag) {
1383 		/*
1384 		 * Need to ignore the column with the cursor in it, which for
1385 		 * rectangular copy means knowing which side the cursor is on.
1386 		 */
1387 		if (data->selx < data->cx) {
1388 			/* Selection start is on the left. */
1389 			if (keys == MODEKEY_EMACS) {
1390 				lastex = data->cx;
1391 				restex = data->cx;
1392 			}
1393 			else {
1394 				lastex = data->cx + 1;
1395 				restex = data->cx + 1;
1396 			}
1397 			firstsx = data->selx;
1398 			restsx = data->selx;
1399 		} else {
1400 			/* Cursor is on the left. */
1401 			lastex = data->selx + 1;
1402 			restex = data->selx + 1;
1403 			firstsx = data->cx;
1404 			restsx = data->cx;
1405 		}
1406 	} else {
1407 		if (keys == MODEKEY_EMACS)
1408 			lastex = ex;
1409 		else
1410 			lastex = ex + 1;
1411 		restex = xx;
1412 		firstsx = sx;
1413 		restsx = 0;
1414 	}
1415 
1416 	/* Copy the lines. */
1417 	for (i = sy; i <= ey; i++) {
1418 		window_copy_copy_line(wp, &buf, &off, i,
1419 		    (i == sy ? firstsx : restsx),
1420 		    (i == ey ? lastex : restex));
1421 	}
1422 
1423 	/* Don't bother if no data. */
1424 	if (off == 0) {
1425 		free(buf);
1426 		return (NULL);
1427 	}
1428 	if (keys == MODEKEY_EMACS || lastex <= ey_last)
1429 		off -= 1; /* remove final \n (unless at end in vi mode) */
1430 	*len = off;
1431 	return (buf);
1432 }
1433 
1434 void
1435 window_copy_copy_buffer(struct window_pane *wp, const char *bufname, void *buf,
1436     size_t len)
1437 {
1438 	struct screen_write_ctx	ctx;
1439 
1440 	if (options_get_number(&global_options, "set-clipboard")) {
1441 		screen_write_start(&ctx, wp, NULL);
1442 		screen_write_setselection(&ctx, buf, len);
1443 		screen_write_stop(&ctx);
1444 	}
1445 
1446 	if (paste_set(buf, len, bufname, NULL) != 0)
1447 		free(buf);
1448 }
1449 
1450 void
1451 window_copy_copy_pipe(struct window_pane *wp, struct session *sess,
1452     const char *bufname, const char *arg)
1453 {
1454 	void			*buf;
1455 	size_t			 len;
1456 	struct job		*job;
1457 	struct format_tree	*ft;
1458 	char			*expanded;
1459 
1460 	buf = window_copy_get_selection(wp, &len);
1461 	if (buf == NULL)
1462 		return;
1463 
1464 	ft = format_create();
1465 	format_defaults(ft, NULL, sess, NULL, wp);
1466 	expanded = format_expand(ft, arg);
1467 
1468 	job = job_run(expanded, sess, -1, NULL, NULL, NULL);
1469 	bufferevent_write(job->event, buf, len);
1470 
1471 	free(expanded);
1472 	format_free(ft);
1473 
1474 	window_copy_copy_buffer(wp, bufname, buf, len);
1475 }
1476 
1477 void
1478 window_copy_copy_selection(struct window_pane *wp, const char *bufname)
1479 {
1480 	void	*buf;
1481 	size_t	 len;
1482 
1483 	buf = window_copy_get_selection(wp, &len);
1484 	if (buf == NULL)
1485 		return;
1486 
1487 	window_copy_copy_buffer(wp, bufname, buf, len);
1488 }
1489 
1490 void
1491 window_copy_append_selection(struct window_pane *wp, const char *bufname)
1492 {
1493 	char				*buf;
1494 	struct paste_buffer		*pb;
1495 	size_t				 len;
1496 	struct screen_write_ctx		 ctx;
1497 
1498 	buf = window_copy_get_selection(wp, &len);
1499 	if (buf == NULL)
1500 		return;
1501 
1502 	if (options_get_number(&global_options, "set-clipboard")) {
1503 		screen_write_start(&ctx, wp, NULL);
1504 		screen_write_setselection(&ctx, buf, len);
1505 		screen_write_stop(&ctx);
1506 	}
1507 
1508 	if (bufname == NULL || *bufname == '\0') {
1509 		pb = paste_get_top();
1510 		if (pb != NULL)
1511 			bufname = pb->name;
1512 	} else
1513 		pb = paste_get_name(bufname);
1514 	if (pb != NULL) {
1515 		buf = xrealloc(buf, len + pb->size);
1516 		memmove(buf + pb->size, buf, len);
1517 		memcpy(buf, pb->data, pb->size);
1518 		len += pb->size;
1519 	}
1520 	if (paste_set(buf, len, bufname, NULL) != 0)
1521 		free(buf);
1522 }
1523 
1524 void
1525 window_copy_copy_line(struct window_pane *wp,
1526     char **buf, size_t *off, u_int sy, u_int sx, u_int ex)
1527 {
1528 	struct window_copy_mode_data	*data = wp->modedata;
1529 	struct grid			*gd = data->backing->grid;
1530 	const struct grid_cell		*gc;
1531 	struct grid_line		*gl;
1532 	struct utf8_data		 ud;
1533 	u_int				 i, xx, wrapped = 0;
1534 	const char			*s;
1535 
1536 	if (sx > ex)
1537 		return;
1538 
1539 	/*
1540 	 * Work out if the line was wrapped at the screen edge and all of it is
1541 	 * on screen.
1542 	 */
1543 	gl = &gd->linedata[sy];
1544 	if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
1545 		wrapped = 1;
1546 
1547 	/* If the line was wrapped, don't strip spaces (use the full length). */
1548 	if (wrapped)
1549 		xx = gl->cellsize;
1550 	else
1551 		xx = window_copy_find_length(wp, sy);
1552 	if (ex > xx)
1553 		ex = xx;
1554 	if (sx > xx)
1555 		sx = xx;
1556 
1557 	if (sx < ex) {
1558 		for (i = sx; i < ex; i++) {
1559 			gc = grid_peek_cell(gd, i, sy);
1560 			if (gc->flags & GRID_FLAG_PADDING)
1561 				continue;
1562 			grid_cell_get(gc, &ud);
1563 			if (ud.size == 1 && (gc->attr & GRID_ATTR_CHARSET)) {
1564 				s = tty_acs_get(NULL, ud.data[0]);
1565 				if (s != NULL && strlen(s) <= sizeof ud.data) {
1566 					ud.size = strlen(s);
1567 					memcpy(ud.data, s, ud.size);
1568 				}
1569 			}
1570 
1571 			*buf = xrealloc(*buf, (*off) + ud.size);
1572 			memcpy(*buf + *off, ud.data, ud.size);
1573 			*off += ud.size;
1574 		}
1575 	}
1576 
1577 	/* Only add a newline if the line wasn't wrapped. */
1578 	if (!wrapped || ex != xx) {
1579 		*buf = xrealloc(*buf, (*off) + 1);
1580 		(*buf)[(*off)++] = '\n';
1581 	}
1582 }
1583 
1584 void
1585 window_copy_clear_selection(struct window_pane *wp)
1586 {
1587 	struct window_copy_mode_data   *data = wp->modedata;
1588 	u_int				px, py;
1589 
1590 	screen_clear_selection(&data->screen);
1591 
1592 	py = screen_hsize(data->backing) + data->cy - data->oy;
1593 	px = window_copy_find_length(wp, py);
1594 	if (data->cx > px)
1595 		window_copy_update_cursor(wp, px, data->cy);
1596 }
1597 
1598 int
1599 window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set)
1600 {
1601 	struct window_copy_mode_data	*data = wp->modedata;
1602 	const struct grid_cell		*gc;
1603 	struct utf8_data		 ud;
1604 
1605 	gc = grid_peek_cell(data->backing->grid, px, py);
1606 	grid_cell_get(gc, &ud);
1607 	if (ud.size != 1 || gc->flags & GRID_FLAG_PADDING)
1608 		return (0);
1609 	if (*ud.data == 0x00 || *ud.data == 0x7f)
1610 		return (0);
1611 	return (strchr(set, *ud.data) != NULL);
1612 }
1613 
1614 u_int
1615 window_copy_find_length(struct window_pane *wp, u_int py)
1616 {
1617 	struct window_copy_mode_data	*data = wp->modedata;
1618 	struct screen			*s = data->backing;
1619 	const struct grid_cell		*gc;
1620 	struct utf8_data		 ud;
1621 	u_int				 px;
1622 
1623 	/*
1624 	 * If the pane has been resized, its grid can contain old overlong
1625 	 * lines. grid_peek_cell does not allow accessing cells beyond the
1626 	 * width of the grid, and screen_write_copy treats them as spaces, so
1627 	 * ignore them here too.
1628 	 */
1629 	px = s->grid->linedata[py].cellsize;
1630 	if (px > screen_size_x(s))
1631 		px = screen_size_x(s);
1632 	while (px > 0) {
1633 		gc = grid_peek_cell(s->grid, px - 1, py);
1634 		grid_cell_get(gc, &ud);
1635 		if (ud.size != 1 || *ud.data != ' ')
1636 			break;
1637 		px--;
1638 	}
1639 	return (px);
1640 }
1641 
1642 void
1643 window_copy_cursor_start_of_line(struct window_pane *wp)
1644 {
1645 	struct window_copy_mode_data	*data = wp->modedata;
1646 	struct screen			*back_s = data->backing;
1647 	struct screen			*s = &data->screen;
1648 	struct grid			*gd = back_s->grid;
1649 	u_int				 py;
1650 
1651 	if (data->cx == 0 && s->sel.lineflag == LINE_SEL_NONE) {
1652 		py = screen_hsize(back_s) + data->cy - data->oy;
1653 		while (py > 0 &&
1654 		    gd->linedata[py-1].flags & GRID_LINE_WRAPPED) {
1655 			window_copy_cursor_up(wp, 0);
1656 			py = screen_hsize(back_s) + data->cy - data->oy;
1657 		}
1658 	}
1659 	window_copy_update_cursor(wp, 0, data->cy);
1660 	if (window_copy_update_selection(wp, 1))
1661 		window_copy_redraw_lines(wp, data->cy, 1);
1662 }
1663 
1664 void
1665 window_copy_cursor_back_to_indentation(struct window_pane *wp)
1666 {
1667 	struct window_copy_mode_data	*data = wp->modedata;
1668 	u_int				 px, py, xx;
1669 	const struct grid_cell		*gc;
1670 	struct utf8_data		 ud;
1671 
1672 	px = 0;
1673 	py = screen_hsize(data->backing) + data->cy - data->oy;
1674 	xx = window_copy_find_length(wp, py);
1675 
1676 	while (px < xx) {
1677 		gc = grid_peek_cell(data->backing->grid, px, py);
1678 		grid_cell_get(gc, &ud);
1679 		if (ud.size != 1 || *ud.data != ' ')
1680 			break;
1681 		px++;
1682 	}
1683 
1684 	window_copy_update_cursor(wp, px, data->cy);
1685 	if (window_copy_update_selection(wp, 1))
1686 		window_copy_redraw_lines(wp, data->cy, 1);
1687 }
1688 
1689 void
1690 window_copy_cursor_end_of_line(struct window_pane *wp)
1691 {
1692 	struct window_copy_mode_data	*data = wp->modedata;
1693 	struct screen			*back_s = data->backing;
1694 	struct screen			*s = &data->screen;
1695 	struct grid			*gd = back_s->grid;
1696 	u_int				 px, py;
1697 
1698 	py = screen_hsize(back_s) + data->cy - data->oy;
1699 	px = window_copy_find_length(wp, py);
1700 
1701 	if (data->cx == px && s->sel.lineflag == LINE_SEL_NONE) {
1702 		if (data->screen.sel.flag && data->rectflag)
1703 			px = screen_size_x(back_s);
1704 		if (gd->linedata[py].flags & GRID_LINE_WRAPPED) {
1705 			while (py < gd->sy + gd->hsize &&
1706 			    gd->linedata[py].flags & GRID_LINE_WRAPPED) {
1707 				window_copy_cursor_down(wp, 0);
1708 				py = screen_hsize(back_s)
1709 				     + data->cy - data->oy;
1710 			}
1711 			px = window_copy_find_length(wp, py);
1712 		}
1713 	}
1714 	window_copy_update_cursor(wp, px, data->cy);
1715 
1716 	if (window_copy_update_selection(wp, 1))
1717 		window_copy_redraw_lines(wp, data->cy, 1);
1718 }
1719 
1720 void
1721 window_copy_other_end(struct window_pane *wp)
1722 {
1723 	struct window_copy_mode_data	*data = wp->modedata;
1724 	struct screen			*s = &data->screen;
1725 	u_int				 selx, sely, cx, cy, yy, hsize;
1726 
1727 	if (!s->sel.flag && s->sel.lineflag == LINE_SEL_NONE)
1728 		return;
1729 
1730 	if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT)
1731 		s->sel.lineflag = LINE_SEL_RIGHT_LEFT;
1732 	else if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT)
1733 		s->sel.lineflag = LINE_SEL_LEFT_RIGHT;
1734 
1735 	selx = data->selx;
1736 	sely = data->sely;
1737 	cx = data->cx;
1738 	cy = data->cy;
1739 	yy = screen_hsize(data->backing) + data->cy - data->oy;
1740 
1741 	data->selx = cx;
1742 	data->sely = yy;
1743 	data->cx = selx;
1744 
1745 	hsize = screen_hsize(data->backing);
1746 	if (sely < hsize - data->oy) {
1747 		data->oy = hsize - sely;
1748 		data->cy = 0;
1749 	} else if (sely > hsize - data->oy + screen_size_y(s)) {
1750 		data->oy = hsize - sely + screen_size_y(s) - 1;
1751 		data->cy = screen_size_y(s) - 1;
1752 	} else
1753 		data->cy = cy + sely - yy;
1754 
1755 	window_copy_redraw_screen(wp);
1756 }
1757 
1758 void
1759 window_copy_cursor_left(struct window_pane *wp)
1760 {
1761 	struct window_copy_mode_data	*data = wp->modedata;
1762 
1763 	if (data->cx == 0) {
1764 		window_copy_cursor_up(wp, 0);
1765 		window_copy_cursor_end_of_line(wp);
1766 	} else {
1767 		window_copy_update_cursor(wp, data->cx - 1, data->cy);
1768 		if (window_copy_update_selection(wp, 1))
1769 			window_copy_redraw_lines(wp, data->cy, 1);
1770 	}
1771 }
1772 
1773 void
1774 window_copy_cursor_right(struct window_pane *wp)
1775 {
1776 	struct window_copy_mode_data	*data = wp->modedata;
1777 	u_int				 px, py;
1778 
1779 	if (data->screen.sel.flag && data->rectflag)
1780 		px = screen_size_x(&data->screen);
1781 	else {
1782 		py = screen_hsize(data->backing) + data->cy - data->oy;
1783 		px = window_copy_find_length(wp, py);
1784 	}
1785 
1786 	if (data->cx >= px) {
1787 		window_copy_cursor_start_of_line(wp);
1788 		window_copy_cursor_down(wp, 0);
1789 	} else {
1790 		window_copy_update_cursor(wp, data->cx + 1, data->cy);
1791 		if (window_copy_update_selection(wp, 1))
1792 			window_copy_redraw_lines(wp, data->cy, 1);
1793 	}
1794 }
1795 
1796 void
1797 window_copy_cursor_up(struct window_pane *wp, int scroll_only)
1798 {
1799 	struct window_copy_mode_data	*data = wp->modedata;
1800 	struct screen			*s = &data->screen;
1801 	u_int				 ox, oy, px, py;
1802 
1803 	oy = screen_hsize(data->backing) + data->cy - data->oy;
1804 	ox = window_copy_find_length(wp, oy);
1805 	if (data->cx != ox) {
1806 		data->lastcx = data->cx;
1807 		data->lastsx = ox;
1808 	}
1809 
1810 	if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
1811 		window_copy_other_end(wp);
1812 
1813 	data->cx = data->lastcx;
1814 	if (scroll_only || data->cy == 0) {
1815 		window_copy_scroll_down(wp, 1);
1816 		if (scroll_only) {
1817 			if (data->cy == screen_size_y(s) - 1)
1818 				window_copy_redraw_lines(wp, data->cy, 1);
1819 			else
1820 				window_copy_redraw_lines(wp, data->cy, 2);
1821 		}
1822 	} else {
1823 		window_copy_update_cursor(wp, data->cx, data->cy - 1);
1824 		if (window_copy_update_selection(wp, 1)) {
1825 			if (data->cy == screen_size_y(s) - 1)
1826 				window_copy_redraw_lines(wp, data->cy, 1);
1827 			else
1828 				window_copy_redraw_lines(wp, data->cy, 2);
1829 		}
1830 	}
1831 
1832 	if (!data->screen.sel.flag || !data->rectflag) {
1833 		py = screen_hsize(data->backing) + data->cy - data->oy;
1834 		px = window_copy_find_length(wp, py);
1835 		if ((data->cx >= data->lastsx && data->cx != px) ||
1836 		    data->cx > px)
1837 			window_copy_cursor_end_of_line(wp);
1838 	}
1839 
1840 	if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT)
1841 		window_copy_cursor_end_of_line(wp);
1842 	else if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT)
1843 		window_copy_cursor_start_of_line(wp);
1844 }
1845 
1846 void
1847 window_copy_cursor_down(struct window_pane *wp, int scroll_only)
1848 {
1849 	struct window_copy_mode_data	*data = wp->modedata;
1850 	struct screen			*s = &data->screen;
1851 	u_int				 ox, oy, px, py;
1852 
1853 	oy = screen_hsize(data->backing) + data->cy - data->oy;
1854 	ox = window_copy_find_length(wp, oy);
1855 	if (data->cx != ox) {
1856 		data->lastcx = data->cx;
1857 		data->lastsx = ox;
1858 	}
1859 
1860 	if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT && oy == data->sely)
1861 		window_copy_other_end(wp);
1862 
1863 	data->cx = data->lastcx;
1864 	if (scroll_only || data->cy == screen_size_y(s) - 1) {
1865 		window_copy_scroll_up(wp, 1);
1866 		if (scroll_only && data->cy > 0)
1867 			window_copy_redraw_lines(wp, data->cy - 1, 2);
1868 	} else {
1869 		window_copy_update_cursor(wp, data->cx, data->cy + 1);
1870 		if (window_copy_update_selection(wp, 1))
1871 			window_copy_redraw_lines(wp, data->cy - 1, 2);
1872 	}
1873 
1874 	if (!data->screen.sel.flag || !data->rectflag) {
1875 		py = screen_hsize(data->backing) + data->cy - data->oy;
1876 		px = window_copy_find_length(wp, py);
1877 		if ((data->cx >= data->lastsx && data->cx != px) ||
1878 		    data->cx > px)
1879 			window_copy_cursor_end_of_line(wp);
1880 	}
1881 
1882 	if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT)
1883 		window_copy_cursor_end_of_line(wp);
1884 	else if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT)
1885 		window_copy_cursor_start_of_line(wp);
1886 }
1887 
1888 void
1889 window_copy_cursor_jump(struct window_pane *wp)
1890 {
1891 	struct window_copy_mode_data	*data = wp->modedata;
1892 	struct screen			*back_s = data->backing;
1893 	const struct grid_cell		*gc;
1894 	struct utf8_data		 ud;
1895 	u_int				 px, py, xx;
1896 
1897 	px = data->cx + 1;
1898 	py = screen_hsize(back_s) + data->cy - data->oy;
1899 	xx = window_copy_find_length(wp, py);
1900 
1901 	while (px < xx) {
1902 		gc = grid_peek_cell(back_s->grid, px, py);
1903 		grid_cell_get(gc, &ud);
1904 		if (!(gc->flags & GRID_FLAG_PADDING) &&
1905 		    ud.size == 1 && *ud.data == data->jumpchar) {
1906 			window_copy_update_cursor(wp, px, data->cy);
1907 			if (window_copy_update_selection(wp, 1))
1908 				window_copy_redraw_lines(wp, data->cy, 1);
1909 			return;
1910 		}
1911 		px++;
1912 	}
1913 }
1914 
1915 void
1916 window_copy_cursor_jump_back(struct window_pane *wp)
1917 {
1918 	struct window_copy_mode_data	*data = wp->modedata;
1919 	struct screen			*back_s = data->backing;
1920 	const struct grid_cell		*gc;
1921 	struct utf8_data		 ud;
1922 	u_int				 px, py;
1923 
1924 	px = data->cx;
1925 	py = screen_hsize(back_s) + data->cy - data->oy;
1926 
1927 	if (px > 0)
1928 		px--;
1929 
1930 	for (;;) {
1931 		gc = grid_peek_cell(back_s->grid, px, py);
1932 		grid_cell_get(gc, &ud);
1933 		if (!(gc->flags & GRID_FLAG_PADDING) &&
1934 		    ud.size == 1 && *ud.data == data->jumpchar) {
1935 			window_copy_update_cursor(wp, px, data->cy);
1936 			if (window_copy_update_selection(wp, 1))
1937 				window_copy_redraw_lines(wp, data->cy, 1);
1938 			return;
1939 		}
1940 		if (px == 0)
1941 			break;
1942 		px--;
1943 	}
1944 }
1945 
1946 void
1947 window_copy_cursor_jump_to(struct window_pane *wp, int jump_again)
1948 {
1949 	struct window_copy_mode_data	*data = wp->modedata;
1950 	struct screen			*back_s = data->backing;
1951 	const struct grid_cell		*gc;
1952 	struct utf8_data		 ud;
1953 	u_int				 px, py, xx;
1954 
1955 	px = data->cx + 1 + jump_again;
1956 	py = screen_hsize(back_s) + data->cy - data->oy;
1957 	xx = window_copy_find_length(wp, py);
1958 
1959 	while (px < xx) {
1960 		gc = grid_peek_cell(back_s->grid, px, py);
1961 		grid_cell_get(gc, &ud);
1962 		if (!(gc->flags & GRID_FLAG_PADDING) &&
1963 		    ud.size == 1 && *ud.data == data->jumpchar) {
1964 			window_copy_update_cursor(wp, px - 1, data->cy);
1965 			if (window_copy_update_selection(wp, 1))
1966 				window_copy_redraw_lines(wp, data->cy, 1);
1967 			return;
1968 		}
1969 		px++;
1970 	}
1971 }
1972 
1973 void
1974 window_copy_cursor_jump_to_back(struct window_pane *wp, int jump_again)
1975 {
1976 	struct window_copy_mode_data	*data = wp->modedata;
1977 	struct screen			*back_s = data->backing;
1978 	const struct grid_cell		*gc;
1979 	struct utf8_data		 ud;
1980 	u_int				 px, py;
1981 
1982 	px = data->cx;
1983 	py = screen_hsize(back_s) + data->cy - data->oy;
1984 
1985 	if (px > 0)
1986 		px--;
1987 
1988 	if (jump_again && px > 0)
1989 		px--;
1990 
1991 	for (;;) {
1992 		gc = grid_peek_cell(back_s->grid, px, py);
1993 		grid_cell_get(gc, &ud);
1994 		if (!(gc->flags & GRID_FLAG_PADDING) &&
1995 		    ud.size == 1 && *ud.data == data->jumpchar) {
1996 			window_copy_update_cursor(wp, px + 1, data->cy);
1997 			if (window_copy_update_selection(wp, 1))
1998 				window_copy_redraw_lines(wp, data->cy, 1);
1999 			return;
2000 		}
2001 		if (px == 0)
2002 			break;
2003 		px--;
2004 	}
2005 }
2006 
2007 void
2008 window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
2009 {
2010 	struct window_copy_mode_data	*data = wp->modedata;
2011 	struct screen			*back_s = data->backing;
2012 	u_int				 px, py, xx, yy;
2013 	int				 expected = 0;
2014 
2015 	px = data->cx;
2016 	py = screen_hsize(back_s) + data->cy - data->oy;
2017 	xx = window_copy_find_length(wp, py);
2018 	yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
2019 
2020 	/*
2021 	 * First skip past any nonword characters and then any word characters.
2022 	 *
2023 	 * expected is initially set to 0 for the former and then 1 for the
2024 	 * latter.
2025 	 */
2026 	do {
2027 		while (px > xx ||
2028 		    window_copy_in_set(wp, px, py, separators) == expected) {
2029 			/* Move down if we're past the end of the line. */
2030 			if (px > xx) {
2031 				if (py == yy)
2032 					return;
2033 				window_copy_cursor_down(wp, 0);
2034 				px = 0;
2035 
2036 				py = screen_hsize(back_s) + data->cy - data->oy;
2037 				xx = window_copy_find_length(wp, py);
2038 			} else
2039 				px++;
2040 		}
2041 		expected = !expected;
2042 	} while (expected == 1);
2043 
2044 	window_copy_update_cursor(wp, px, data->cy);
2045 	if (window_copy_update_selection(wp, 1))
2046 		window_copy_redraw_lines(wp, data->cy, 1);
2047 }
2048 
2049 void
2050 window_copy_cursor_next_word_end(struct window_pane *wp,
2051     const char *separators)
2052 {
2053 	struct window_copy_mode_data	*data = wp->modedata;
2054 	struct options			*oo = &wp->window->options;
2055 	struct screen			*back_s = data->backing;
2056 	u_int				 px, py, xx, yy;
2057 	int				 keys, expected = 1;
2058 
2059 	px = data->cx;
2060 	py = screen_hsize(back_s) + data->cy - data->oy;
2061 	xx = window_copy_find_length(wp, py);
2062 	yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
2063 
2064 	keys = options_get_number(oo, "mode-keys");
2065 	if (keys == MODEKEY_VI && !window_copy_in_set(wp, px, py, separators))
2066 		px++;
2067 
2068 	/*
2069 	 * First skip past any word characters, then any nonword characters.
2070 	 *
2071 	 * expected is initially set to 1 for the former and then 0 for the
2072 	 * latter.
2073 	 */
2074 	do {
2075 		while (px > xx ||
2076 		    window_copy_in_set(wp, px, py, separators) == expected) {
2077 			/* Move down if we're past the end of the line. */
2078 			if (px > xx) {
2079 				if (py == yy)
2080 					return;
2081 				window_copy_cursor_down(wp, 0);
2082 				px = 0;
2083 
2084 				py = screen_hsize(back_s) + data->cy - data->oy;
2085 				xx = window_copy_find_length(wp, py);
2086 			} else
2087 				px++;
2088 		}
2089 		expected = !expected;
2090 	} while (expected == 0);
2091 
2092 	if (keys == MODEKEY_VI && px != 0)
2093 		px--;
2094 
2095 	window_copy_update_cursor(wp, px, data->cy);
2096 	if (window_copy_update_selection(wp, 1))
2097 		window_copy_redraw_lines(wp, data->cy, 1);
2098 }
2099 
2100 /* Move to the previous place where a word begins. */
2101 void
2102 window_copy_cursor_previous_word(struct window_pane *wp,
2103     const char *separators)
2104 {
2105 	struct window_copy_mode_data	*data = wp->modedata;
2106 	u_int				 px, py;
2107 
2108 	px = data->cx;
2109 	py = screen_hsize(data->backing) + data->cy - data->oy;
2110 
2111 	/* Move back to the previous word character. */
2112 	for (;;) {
2113 		if (px > 0) {
2114 			px--;
2115 			if (!window_copy_in_set(wp, px, py, separators))
2116 				break;
2117 		} else {
2118 			if (data->cy == 0 &&
2119 			    (screen_hsize(data->backing) == 0 ||
2120 			    data->oy >= screen_hsize(data->backing) - 1))
2121 				goto out;
2122 			window_copy_cursor_up(wp, 0);
2123 
2124 			py = screen_hsize(data->backing) + data->cy - data->oy;
2125 			px = window_copy_find_length(wp, py);
2126 		}
2127 	}
2128 
2129 	/* Move back to the beginning of this word. */
2130 	while (px > 0 && !window_copy_in_set(wp, px - 1, py, separators))
2131 		px--;
2132 
2133 out:
2134 	window_copy_update_cursor(wp, px, data->cy);
2135 	if (window_copy_update_selection(wp, 1))
2136 		window_copy_redraw_lines(wp, data->cy, 1);
2137 }
2138 
2139 void
2140 window_copy_scroll_up(struct window_pane *wp, u_int ny)
2141 {
2142 	struct window_copy_mode_data	*data = wp->modedata;
2143 	struct screen			*s = &data->screen;
2144 	struct screen_write_ctx		 ctx;
2145 
2146 	if (data->oy < ny)
2147 		ny = data->oy;
2148 	if (ny == 0)
2149 		return;
2150 	data->oy -= ny;
2151 
2152 	window_copy_update_selection(wp, 0);
2153 
2154 	screen_write_start(&ctx, wp, NULL);
2155 	screen_write_cursormove(&ctx, 0, 0);
2156 	screen_write_deleteline(&ctx, ny);
2157 	window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, ny);
2158 	window_copy_write_line(wp, &ctx, 0);
2159 	if (screen_size_y(s) > 1)
2160 		window_copy_write_line(wp, &ctx, 1);
2161 	if (screen_size_y(s) > 3)
2162 		window_copy_write_line(wp, &ctx, screen_size_y(s) - 2);
2163 	if (s->sel.flag && screen_size_y(s) > ny)
2164 		window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1);
2165 	screen_write_cursormove(&ctx, data->cx, data->cy);
2166 	screen_write_stop(&ctx);
2167 }
2168 
2169 void
2170 window_copy_scroll_down(struct window_pane *wp, u_int ny)
2171 {
2172 	struct window_copy_mode_data	*data = wp->modedata;
2173 	struct screen			*s = &data->screen;
2174 	struct screen_write_ctx		 ctx;
2175 
2176 	if (ny > screen_hsize(data->backing))
2177 		return;
2178 
2179 	if (data->oy > screen_hsize(data->backing) - ny)
2180 		ny = screen_hsize(data->backing) - data->oy;
2181 	if (ny == 0)
2182 		return;
2183 	data->oy += ny;
2184 
2185 	window_copy_update_selection(wp, 0);
2186 
2187 	screen_write_start(&ctx, wp, NULL);
2188 	screen_write_cursormove(&ctx, 0, 0);
2189 	screen_write_insertline(&ctx, ny);
2190 	window_copy_write_lines(wp, &ctx, 0, ny);
2191 	if (s->sel.flag && screen_size_y(s) > ny)
2192 		window_copy_write_line(wp, &ctx, ny);
2193 	else if (ny == 1) /* nuke position */
2194 		window_copy_write_line(wp, &ctx, 1);
2195 	screen_write_cursormove(&ctx, data->cx, data->cy);
2196 	screen_write_stop(&ctx);
2197 }
2198 
2199 void
2200 window_copy_rectangle_toggle(struct window_pane *wp)
2201 {
2202 	struct window_copy_mode_data	*data = wp->modedata;
2203 	u_int				 px, py;
2204 
2205 	data->rectflag = !data->rectflag;
2206 
2207 	py = screen_hsize(data->backing) + data->cy - data->oy;
2208 	px = window_copy_find_length(wp, py);
2209 	if (data->cx > px)
2210 		window_copy_update_cursor(wp, px, data->cy);
2211 
2212 	window_copy_update_selection(wp, 1);
2213 	window_copy_redraw_screen(wp);
2214 }
2215 
2216 void
2217 window_copy_start_drag(struct client *c, unused struct mouse_event *m)
2218 {
2219 	struct window_pane	*wp;
2220 	u_int			 x, y;
2221 
2222 	wp = cmd_mouse_pane(m, NULL, NULL);
2223 	if (wp == NULL || wp->mode != &window_copy_mode)
2224 		return;
2225 
2226 	if (cmd_mouse_at(wp, m, &x, &y, 1) != 0)
2227 		return;
2228 
2229 	c->tty.mouse_drag_update = window_copy_drag_update;
2230 	c->tty.mouse_drag_release = window_copy_drag_release;
2231 
2232 	window_copy_update_cursor(wp, x, y);
2233 	window_copy_start_selection(wp);
2234 	window_copy_redraw_screen(wp);
2235 }
2236 
2237 void
2238 window_copy_drag_update(unused struct client *c, struct mouse_event *m)
2239 {
2240 	struct window_pane		*wp;
2241 	struct window_copy_mode_data	*data;
2242 	u_int				 x, y, old_cy;
2243 
2244 	wp = cmd_mouse_pane(m, NULL, NULL);
2245 	if (wp == NULL || wp->mode != &window_copy_mode)
2246 		return;
2247 	data = wp->modedata;
2248 
2249 	if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
2250 		return;
2251 	old_cy = data->cy;
2252 
2253 	window_copy_update_cursor(wp, x, y);
2254 	if (window_copy_update_selection(wp, 1))
2255 		window_copy_redraw_selection(wp, old_cy);
2256 }
2257 
2258 void
2259 window_copy_drag_release(unused struct client *c, struct mouse_event *m)
2260 {
2261 	struct window_pane	*wp;
2262 
2263 	wp = cmd_mouse_pane(m, NULL, NULL);
2264 	if (wp == NULL || wp->mode != &window_copy_mode)
2265 		return;
2266 
2267 	window_copy_copy_selection(wp, NULL);
2268 	window_pane_reset_mode(wp);
2269 }
2270