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