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