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