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