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