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