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