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