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