Annotation of src/usr.bin/tmux/window-copy.c, Revision 1.56
1.56 ! nicm 1: /* $OpenBSD: window-copy.c,v 1.55 2010/04/28 18:19:16 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.21 nicm 21: #include <stdlib.h>
1.1 nicm 22: #include <string.h>
23:
24: #include "tmux.h"
25:
26: struct screen *window_copy_init(struct window_pane *);
27: void window_copy_free(struct window_pane *);
28: void window_copy_resize(struct window_pane *, u_int, u_int);
1.56 ! nicm 29: void window_copy_key(struct window_pane *, struct session *, int);
1.21 nicm 30: int window_copy_key_input(struct window_pane *, int);
1.50 nicm 31: int window_copy_key_numeric_prefix(struct window_pane *, int);
1.1 nicm 32: void window_copy_mouse(
1.56 ! nicm 33: struct window_pane *, struct session *, struct mouse_event *);
1.1 nicm 34:
35: void window_copy_redraw_lines(struct window_pane *, u_int, u_int);
36: void window_copy_redraw_screen(struct window_pane *);
37: void window_copy_write_line(
1.35 nicm 38: struct window_pane *, struct screen_write_ctx *, u_int);
1.1 nicm 39: void window_copy_write_lines(
1.35 nicm 40: struct window_pane *, struct screen_write_ctx *, u_int, u_int);
1.1 nicm 41:
1.21 nicm 42: void window_copy_scroll_to(struct window_pane *, u_int, u_int);
43: int window_copy_search_compare(
44: struct grid *, u_int, u_int, struct grid *, u_int);
45: int window_copy_search_lr(
46: struct grid *, struct grid *, u_int *, u_int, u_int, u_int);
47: int window_copy_search_rl(
48: struct grid *, struct grid *, u_int *, u_int, u_int, u_int);
49: void window_copy_search_up(struct window_pane *, const char *);
50: void window_copy_search_down(struct window_pane *, const char *);
51: void window_copy_goto_line(struct window_pane *, const char *);
1.18 nicm 52: void window_copy_update_cursor(struct window_pane *, u_int, u_int);
1.1 nicm 53: void window_copy_start_selection(struct window_pane *);
54: int window_copy_update_selection(struct window_pane *);
1.56 ! nicm 55: void window_copy_copy_selection(struct window_pane *, struct session *);
1.47 nicm 56: void window_copy_clear_selection(struct window_pane *);
1.1 nicm 57: void window_copy_copy_line(
58: struct window_pane *, char **, size_t *, u_int, u_int, u_int);
1.41 nicm 59: int window_copy_in_set(struct window_pane *, u_int, u_int, const char *);
1.1 nicm 60: u_int window_copy_find_length(struct window_pane *, u_int);
61: void window_copy_cursor_start_of_line(struct window_pane *);
1.6 nicm 62: void window_copy_cursor_back_to_indentation(struct window_pane *);
1.1 nicm 63: void window_copy_cursor_end_of_line(struct window_pane *);
64: void window_copy_cursor_left(struct window_pane *);
65: void window_copy_cursor_right(struct window_pane *);
1.28 nicm 66: void window_copy_cursor_up(struct window_pane *, int);
67: void window_copy_cursor_down(struct window_pane *, int);
1.52 nicm 68: void window_copy_cursor_jump(struct window_pane *);
69: void window_copy_cursor_jump_back(struct window_pane *);
1.41 nicm 70: void window_copy_cursor_next_word(struct window_pane *, const char *);
71: void window_copy_cursor_next_word_end(struct window_pane *, const char *);
72: void window_copy_cursor_previous_word(struct window_pane *, const char *);
1.1 nicm 73: void window_copy_scroll_up(struct window_pane *, u_int);
74: void window_copy_scroll_down(struct window_pane *, u_int);
1.42 nicm 75: void window_copy_rectangle_toggle(struct window_pane *);
1.1 nicm 76:
77: const struct window_mode window_copy_mode = {
78: window_copy_init,
79: window_copy_free,
80: window_copy_resize,
81: window_copy_key,
82: window_copy_mouse,
83: NULL,
84: };
85:
1.21 nicm 86: enum window_copy_input_type {
87: WINDOW_COPY_OFF,
1.50 nicm 88: WINDOW_COPY_NUMERICPREFIX,
1.21 nicm 89: WINDOW_COPY_SEARCHUP,
90: WINDOW_COPY_SEARCHDOWN,
1.52 nicm 91: WINDOW_COPY_JUMPFORWARD,
92: WINDOW_COPY_JUMPBACK,
1.21 nicm 93: WINDOW_COPY_GOTOLINE,
94: };
95:
1.54 nicm 96: /*
97: * Copy-mode's visible screen (the "screen" field) is filled from one of
98: * two sources: the original contents of the pane (used when we
99: * actually enter via the "copy-mode" command, to copy the contents of
100: * the current pane), or else a series of lines containing the output
101: * from an output-writing tmux command (such as any of the "show-*" or
102: * "list-*" commands).
103: *
104: * In either case, the full content of the copy-mode grid is pointed at
105: * by the "backing" field, and is copied into "screen" as needed (that
106: * is, when scrolling occurs). When copy-mode is backed by a pane,
107: * backing points directly at that pane's screen structure (&wp->base);
108: * when backed by a list of output-lines from a command, it points at
109: * a newly-allocated screen structure (which is deallocated when the
110: * mode ends).
111: */
1.1 nicm 112: struct window_copy_mode_data {
113: struct screen screen;
114:
1.54 nicm 115: struct screen *backing;
116: int backing_written; /* backing display has started */
117:
1.21 nicm 118: struct mode_key_data mdata;
119:
120: u_int oy;
121:
122: u_int selx;
123: u_int sely;
1.1 nicm 124:
1.42 nicm 125: u_int rectflag; /* are we in rectangle copy mode? */
126:
1.21 nicm 127: u_int cx;
128: u_int cy;
1.1 nicm 129:
1.25 nicm 130: u_int lastcx; /* position in last line with content */
131: u_int lastsx; /* size of last line with content */
132:
1.21 nicm 133: enum window_copy_input_type inputtype;
134: const char *inputprompt;
135: char *inputstr;
1.1 nicm 136:
1.50 nicm 137: u_int numprefix;
138:
1.21 nicm 139: enum window_copy_input_type searchtype;
140: char *searchstr;
1.52 nicm 141:
142: enum window_copy_input_type jumptype;
143: char jumpchar;
1.1 nicm 144: };
145:
146: struct screen *
147: window_copy_init(struct window_pane *wp)
148: {
149: struct window_copy_mode_data *data;
150: struct screen *s;
1.10 nicm 151: int keys;
1.1 nicm 152:
153: wp->modedata = data = xmalloc(sizeof *data);
154: data->oy = 0;
1.54 nicm 155: data->cx = 0;
156: data->cy = 0;
1.1 nicm 157:
1.25 nicm 158: data->lastcx = 0;
159: data->lastsx = 0;
160:
1.54 nicm 161: data->backing_written = 0;
162:
1.42 nicm 163: data->rectflag = 0;
164:
1.21 nicm 165: data->inputtype = WINDOW_COPY_OFF;
166: data->inputprompt = NULL;
167: data->inputstr = xstrdup("");
1.50 nicm 168: data->numprefix = 0;
1.21 nicm 169:
170: data->searchtype = WINDOW_COPY_OFF;
171: data->searchstr = NULL;
172:
1.46 nicm 173: wp->flags |= PANE_FREEZE;
174: bufferevent_disable(wp->event, EV_READ|EV_WRITE);
175:
1.52 nicm 176: data->jumptype = WINDOW_COPY_OFF;
177: data->jumpchar = '\0';
178:
1.1 nicm 179: s = &data->screen;
180: screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
1.13 nicm 181: if (options_get_number(&wp->window->options, "mode-mouse"))
182: s->mode |= MODE_MOUSE;
1.1 nicm 183:
1.10 nicm 184: keys = options_get_number(&wp->window->options, "mode-keys");
185: if (keys == MODEKEY_EMACS)
1.12 nicm 186: mode_key_init(&data->mdata, &mode_key_tree_emacs_copy);
1.10 nicm 187: else
1.12 nicm 188: mode_key_init(&data->mdata, &mode_key_tree_vi_copy);
1.1 nicm 189:
1.54 nicm 190: data->backing = NULL;
191:
192: return (s);
193: }
194:
195: void
196: window_copy_init_from_pane(struct window_pane *wp)
197: {
198: struct window_copy_mode_data *data = wp->modedata;
199: struct screen *s = &data->screen;
200: struct screen_write_ctx ctx;
201: u_int i;
202:
203: if (wp->mode != &window_copy_mode)
204: fatalx("not in copy mode");
205:
206: data->backing = &wp->base;
207: data->cx = data->backing->cx;
208: data->cy = data->backing->cy;
209:
1.1 nicm 210: s->cx = data->cx;
211: s->cy = data->cy;
212:
213: screen_write_start(&ctx, NULL, s);
214: for (i = 0; i < screen_size_y(s); i++)
215: window_copy_write_line(wp, &ctx, i);
216: screen_write_cursormove(&ctx, data->cx, data->cy);
217: screen_write_stop(&ctx);
1.54 nicm 218: }
1.1 nicm 219:
1.54 nicm 220: void
221: window_copy_init_for_output(struct window_pane *wp)
222: {
223: struct window_copy_mode_data *data = wp->modedata;
224:
225: data->backing = xmalloc(sizeof *data->backing);
226: screen_init(data->backing, screen_size_x(&wp->base),
227: screen_size_y(&wp->base), UINT_MAX);
228: data->backing->mode &= ~MODE_WRAP;
1.1 nicm 229: }
230:
231: void
232: window_copy_free(struct window_pane *wp)
233: {
234: struct window_copy_mode_data *data = wp->modedata;
1.46 nicm 235:
236: wp->flags &= ~PANE_FREEZE;
237: bufferevent_enable(wp->event, EV_READ|EV_WRITE);
1.1 nicm 238:
1.21 nicm 239: if (data->searchstr != NULL)
240: xfree(data->searchstr);
241: xfree(data->inputstr);
242:
1.54 nicm 243: if (data->backing != &wp->base) {
244: screen_free(data->backing);
245: xfree(data->backing);
246: }
1.1 nicm 247: screen_free(&data->screen);
1.21 nicm 248:
1.1 nicm 249: xfree(data);
250: }
251:
252: void
1.54 nicm 253: window_copy_add(struct window_pane *wp, const char *fmt, ...)
254: {
255: va_list ap;
256:
257: va_start(ap, fmt);
258: window_copy_vadd(wp, fmt, ap);
259: va_end(ap);
260: }
261:
262: void
263: window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap)
264: {
265: struct window_copy_mode_data *data = wp->modedata;
266: struct screen *backing = data->backing;
267: struct screen_write_ctx back_ctx, ctx;
268: struct grid_cell gc;
269: int utf8flag;
270: u_int old_hsize;
271:
272: if (backing == &wp->base)
273: return;
274:
275: utf8flag = options_get_number(&wp->window->options, "utf8");
276: memcpy(&gc, &grid_default_cell, sizeof gc);
277:
278: old_hsize = screen_hsize(data->backing);
279: screen_write_start(&back_ctx, NULL, backing);
280: if (data->backing_written) {
281: /*
282: * On the second or later line, do a CRLF before writing
283: * (so it's on a new line).
284: */
285: screen_write_carriagereturn(&back_ctx);
286: screen_write_linefeed(&back_ctx, 0);
287: } else
288: data->backing_written = 1;
289: screen_write_vnputs(&back_ctx, 0, &gc, utf8flag, fmt, ap);
290: screen_write_stop(&back_ctx);
291:
292: data->oy += screen_hsize(data->backing) - old_hsize;
293:
294: screen_write_start(&ctx, wp, &data->screen);
295:
296: /*
297: * If the history has changed, draw the top line.
298: * (If there's any history at all, it has changed.)
299: */
300: if (screen_hsize(data->backing))
301: window_copy_redraw_lines(wp, 0, 1);
302:
303: /* Write the line, if it's visible. */
304: if (backing->cy + data->oy < screen_size_y(backing))
305: window_copy_redraw_lines(wp, backing->cy, 1);
306:
307: screen_write_stop(&ctx);
308: }
309:
310: void
1.1 nicm 311: window_copy_pageup(struct window_pane *wp)
312: {
313: struct window_copy_mode_data *data = wp->modedata;
314: struct screen *s = &data->screen;
1.19 nicm 315: u_int n;
1.1 nicm 316:
1.19 nicm 317: n = 1;
318: if (screen_size_y(s) > 2)
319: n = screen_size_y(s) - 2;
1.54 nicm 320: if (data->oy + n > screen_hsize(data->backing))
321: data->oy = screen_hsize(data->backing);
1.1 nicm 322: else
1.19 nicm 323: data->oy += n;
1.1 nicm 324: window_copy_update_selection(wp);
325: window_copy_redraw_screen(wp);
326: }
327:
328: void
329: window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
330: {
331: struct window_copy_mode_data *data = wp->modedata;
332: struct screen *s = &data->screen;
333: struct screen_write_ctx ctx;
334:
335: screen_resize(s, sx, sy);
1.54 nicm 336: if (data->backing != &wp->base)
337: screen_resize(data->backing, sx, sy);
1.35 nicm 338:
1.18 nicm 339: if (data->cy > sy - 1)
340: data->cy = sy - 1;
341: if (data->cx > sx)
342: data->cx = sx;
343:
1.47 nicm 344: window_copy_clear_selection(wp);
1.18 nicm 345:
1.1 nicm 346: screen_write_start(&ctx, NULL, s);
347: window_copy_write_lines(wp, &ctx, 0, screen_size_y(s) - 1);
348: screen_write_stop(&ctx);
1.18 nicm 349:
1.17 nicm 350: window_copy_redraw_screen(wp);
1.1 nicm 351: }
352:
353: void
1.56 ! nicm 354: window_copy_key(struct window_pane *wp, struct session *sess, int key)
1.1 nicm 355: {
1.48 nicm 356: const char *word_separators;
1.1 nicm 357: struct window_copy_mode_data *data = wp->modedata;
358: struct screen *s = &data->screen;
1.50 nicm 359: u_int n, np;
1.21 nicm 360: int keys;
1.43 nicm 361: enum mode_key_cmd cmd;
1.21 nicm 362:
1.50 nicm 363: np = data->numprefix;
364: if (np == 0)
365: np = 1;
366:
1.52 nicm 367: if (data->inputtype == WINDOW_COPY_JUMPFORWARD
368: || data->inputtype == WINDOW_COPY_JUMPBACK) {
369: /* Ignore keys with modifiers. */
370: if ((key & 0xff00) == 0) {
371: data->jumpchar = key;
372: if (data->inputtype == WINDOW_COPY_JUMPFORWARD) {
373: for (; np != 0; np--)
374: window_copy_cursor_jump(wp);
375: } else {
376: for (; np != 0; np--)
377: window_copy_cursor_jump_back(wp);
378: }
379: }
380: data->jumptype = data->inputtype;
381: data->inputtype = WINDOW_COPY_OFF;
382: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
383: return;
384: } if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) {
1.50 nicm 385: if (window_copy_key_numeric_prefix(wp, key) == 0)
386: return;
387: data->inputtype = WINDOW_COPY_OFF;
388: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
389: } else if (data->inputtype != WINDOW_COPY_OFF) {
1.21 nicm 390: if (window_copy_key_input(wp, key) != 0)
391: goto input_off;
392: return;
393: }
1.1 nicm 394:
1.43 nicm 395: cmd = mode_key_lookup(&data->mdata, key);
396: switch (cmd) {
1.11 nicm 397: case MODEKEYCOPY_CANCEL:
1.51 nicm 398: window_pane_reset_mode(wp);
399: return;
1.10 nicm 400: case MODEKEYCOPY_LEFT:
1.50 nicm 401: for (; np != 0; np--)
402: window_copy_cursor_left(wp);
403: break;
1.10 nicm 404: case MODEKEYCOPY_RIGHT:
1.50 nicm 405: for (; np != 0; np--)
406: window_copy_cursor_right(wp);
407: break;
1.10 nicm 408: case MODEKEYCOPY_UP:
1.50 nicm 409: for (; np != 0; np--)
410: window_copy_cursor_up(wp, 0);
411: break;
1.10 nicm 412: case MODEKEYCOPY_DOWN:
1.50 nicm 413: for (; np != 0; np--)
414: window_copy_cursor_down(wp, 0);
415: break;
1.28 nicm 416: case MODEKEYCOPY_SCROLLUP:
1.50 nicm 417: for (; np != 0; np--)
418: window_copy_cursor_up(wp, 1);
1.28 nicm 419: break;
420: case MODEKEYCOPY_SCROLLDOWN:
1.50 nicm 421: for (; np != 0; np--)
422: window_copy_cursor_down(wp, 1);
1.28 nicm 423: break;
1.10 nicm 424: case MODEKEYCOPY_PREVIOUSPAGE:
1.50 nicm 425: for (; np != 0; np--)
426: window_copy_pageup(wp);
1.1 nicm 427: break;
1.10 nicm 428: case MODEKEYCOPY_NEXTPAGE:
1.19 nicm 429: n = 1;
430: if (screen_size_y(s) > 2)
431: n = screen_size_y(s) - 2;
1.50 nicm 432: for (; np != 0; np--) {
433: if (data->oy < n)
434: data->oy = 0;
435: else
436: data->oy -= n;
437: }
1.20 nicm 438: window_copy_update_selection(wp);
439: window_copy_redraw_screen(wp);
440: break;
441: case MODEKEYCOPY_HALFPAGEUP:
442: n = screen_size_y(s) / 2;
1.50 nicm 443: for (; np != 0; np--) {
1.54 nicm 444: if (data->oy + n > screen_hsize(data->backing))
445: data->oy = screen_hsize(data->backing);
1.50 nicm 446: else
447: data->oy += n;
448: }
1.20 nicm 449: window_copy_update_selection(wp);
450: window_copy_redraw_screen(wp);
451: break;
452: case MODEKEYCOPY_HALFPAGEDOWN:
453: n = screen_size_y(s) / 2;
1.50 nicm 454: for (; np != 0; np--) {
455: if (data->oy < n)
456: data->oy = 0;
457: else
458: data->oy -= n;
459: }
1.30 nicm 460: window_copy_update_selection(wp);
461: window_copy_redraw_screen(wp);
462: break;
463: case MODEKEYCOPY_TOPLINE:
464: data->cx = 0;
465: data->cy = 0;
466: window_copy_update_selection(wp);
467: window_copy_redraw_screen(wp);
468: break;
469: case MODEKEYCOPY_MIDDLELINE:
470: data->cx = 0;
471: data->cy = (screen_size_y(s) - 1) / 2;
472: window_copy_update_selection(wp);
473: window_copy_redraw_screen(wp);
474: break;
475: case MODEKEYCOPY_BOTTOMLINE:
476: data->cx = 0;
477: data->cy = screen_size_y(s) - 1;
1.37 nicm 478: window_copy_update_selection(wp);
479: window_copy_redraw_screen(wp);
480: break;
481: case MODEKEYCOPY_HISTORYTOP:
482: data->cx = 0;
483: data->cy = 0;
1.54 nicm 484: data->oy = screen_hsize(data->backing);
1.37 nicm 485: window_copy_update_selection(wp);
486: window_copy_redraw_screen(wp);
487: break;
488: case MODEKEYCOPY_HISTORYBOTTOM:
489: data->cx = 0;
490: data->cy = screen_size_y(s) - 1;
491: data->oy = 0;
1.1 nicm 492: window_copy_update_selection(wp);
493: window_copy_redraw_screen(wp);
494: break;
1.10 nicm 495: case MODEKEYCOPY_STARTSELECTION:
1.35 nicm 496: window_copy_start_selection(wp);
1.7 nicm 497: window_copy_redraw_screen(wp);
1.1 nicm 498: break;
1.10 nicm 499: case MODEKEYCOPY_CLEARSELECTION:
1.47 nicm 500: window_copy_clear_selection(wp);
1.1 nicm 501: window_copy_redraw_screen(wp);
502: break;
1.10 nicm 503: case MODEKEYCOPY_COPYSELECTION:
1.56 ! nicm 504: if (sess != NULL) {
! 505: window_copy_copy_selection(wp, sess);
1.1 nicm 506: window_pane_reset_mode(wp);
1.51 nicm 507: return;
1.1 nicm 508: }
509: break;
1.10 nicm 510: case MODEKEYCOPY_STARTOFLINE:
1.1 nicm 511: window_copy_cursor_start_of_line(wp);
512: break;
1.10 nicm 513: case MODEKEYCOPY_BACKTOINDENTATION:
1.6 nicm 514: window_copy_cursor_back_to_indentation(wp);
515: break;
1.10 nicm 516: case MODEKEYCOPY_ENDOFLINE:
1.1 nicm 517: window_copy_cursor_end_of_line(wp);
518: break;
1.41 nicm 519: case MODEKEYCOPY_NEXTSPACE:
1.50 nicm 520: for (; np != 0; np--)
521: window_copy_cursor_next_word(wp, " ");
1.41 nicm 522: break;
523: case MODEKEYCOPY_NEXTSPACEEND:
1.50 nicm 524: for (; np != 0; np--)
525: window_copy_cursor_next_word_end(wp, " ");
1.41 nicm 526: break;
1.10 nicm 527: case MODEKEYCOPY_NEXTWORD:
1.48 nicm 528: word_separators =
529: options_get_string(&wp->window->options, "word-separators");
1.50 nicm 530: for (; np != 0; np--)
531: window_copy_cursor_next_word(wp, word_separators);
1.1 nicm 532: break;
1.40 nicm 533: case MODEKEYCOPY_NEXTWORDEND:
1.48 nicm 534: word_separators =
535: options_get_string(&wp->window->options, "word-separators");
1.50 nicm 536: for (; np != 0; np--)
537: window_copy_cursor_next_word_end(wp, word_separators);
1.41 nicm 538: break;
539: case MODEKEYCOPY_PREVIOUSSPACE:
1.50 nicm 540: for (; np != 0; np--)
541: window_copy_cursor_previous_word(wp, " ");
1.40 nicm 542: break;
1.10 nicm 543: case MODEKEYCOPY_PREVIOUSWORD:
1.48 nicm 544: word_separators =
545: options_get_string(&wp->window->options, "word-separators");
1.50 nicm 546: for (; np != 0; np--)
547: window_copy_cursor_previous_word(wp, word_separators);
1.1 nicm 548: break;
1.52 nicm 549: case MODEKEYCOPY_JUMP:
550: data->inputtype = WINDOW_COPY_JUMPFORWARD;
551: data->inputprompt = "Jump Forward";
552: *data->inputstr = '\0';
553: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
554: return; /* skip numprefix reset */
555: case MODEKEYCOPY_JUMPAGAIN:
556: if (data->jumptype == WINDOW_COPY_JUMPFORWARD) {
557: for (; np != 0; np--)
558: window_copy_cursor_jump(wp);
559: } else if (data->jumptype == WINDOW_COPY_JUMPBACK) {
560: for (; np != 0; np--)
561: window_copy_cursor_jump_back(wp);
562: }
563: break;
564: case MODEKEYCOPY_JUMPREVERSE:
565: if (data->jumptype == WINDOW_COPY_JUMPFORWARD) {
566: for (; np != 0; np--)
567: window_copy_cursor_jump_back(wp);
568: } else if (data->jumptype == WINDOW_COPY_JUMPBACK) {
569: for (; np != 0; np--)
570: window_copy_cursor_jump(wp);
571: }
572: break;
573: case MODEKEYCOPY_JUMPBACK:
574: data->inputtype = WINDOW_COPY_JUMPBACK;
575: data->inputprompt = "Jump Back";
576: *data->inputstr = '\0';
577: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
578: return; /* skip numprefix reset */
1.21 nicm 579: case MODEKEYCOPY_SEARCHUP:
580: data->inputtype = WINDOW_COPY_SEARCHUP;
581: data->inputprompt = "Search Up";
582: goto input_on;
583: case MODEKEYCOPY_SEARCHDOWN:
584: data->inputtype = WINDOW_COPY_SEARCHDOWN;
585: data->inputprompt = "Search Down";
586: goto input_on;
587: case MODEKEYCOPY_SEARCHAGAIN:
1.43 nicm 588: case MODEKEYCOPY_SEARCHREVERSE:
1.21 nicm 589: switch (data->searchtype) {
590: case WINDOW_COPY_OFF:
591: case WINDOW_COPY_GOTOLINE:
1.52 nicm 592: case WINDOW_COPY_JUMPFORWARD:
593: case WINDOW_COPY_JUMPBACK:
1.50 nicm 594: case WINDOW_COPY_NUMERICPREFIX:
1.21 nicm 595: break;
596: case WINDOW_COPY_SEARCHUP:
1.50 nicm 597: if (cmd == MODEKEYCOPY_SEARCHAGAIN) {
598: for (; np != 0; np--) {
599: window_copy_search_up(
600: wp, data->searchstr);
601: }
602: } else {
603: for (; np != 0; np--) {
604: window_copy_search_down(
605: wp, data->searchstr);
606: }
607: }
1.21 nicm 608: break;
609: case WINDOW_COPY_SEARCHDOWN:
1.50 nicm 610: if (cmd == MODEKEYCOPY_SEARCHAGAIN) {
611: for (; np != 0; np--) {
612: window_copy_search_down(
613: wp, data->searchstr);
614: }
615: } else {
616: for (; np != 0; np--) {
617: window_copy_search_up(
618: wp, data->searchstr);
619: }
620: }
1.21 nicm 621: break;
622: }
623: break;
624: case MODEKEYCOPY_GOTOLINE:
625: data->inputtype = WINDOW_COPY_GOTOLINE;
626: data->inputprompt = "Goto Line";
627: *data->inputstr = '\0';
628: goto input_on;
1.50 nicm 629: case MODEKEYCOPY_STARTNUMBERPREFIX:
630: key &= 0xff;
631: if (key >= '0' && key <= '9') {
632: data->inputtype = WINDOW_COPY_NUMERICPREFIX;
633: data->numprefix = 0;
634: window_copy_key_numeric_prefix(wp, key);
635: return;
636: }
637: break;
1.42 nicm 638: case MODEKEYCOPY_RECTANGLETOGGLE:
639: window_copy_rectangle_toggle(wp);
1.50 nicm 640: break;
1.21 nicm 641: default:
642: break;
643: }
644:
1.50 nicm 645: data->numprefix = 0;
1.21 nicm 646: return;
647:
648: input_on:
649: keys = options_get_number(&wp->window->options, "mode-keys");
650: if (keys == MODEKEY_EMACS)
651: mode_key_init(&data->mdata, &mode_key_tree_emacs_edit);
652: else
653: mode_key_init(&data->mdata, &mode_key_tree_vi_edit);
654:
655: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
656: return;
657:
658: input_off:
659: keys = options_get_number(&wp->window->options, "mode-keys");
660: if (keys == MODEKEY_EMACS)
661: mode_key_init(&data->mdata, &mode_key_tree_emacs_copy);
662: else
663: mode_key_init(&data->mdata, &mode_key_tree_vi_copy);
664:
665: data->inputtype = WINDOW_COPY_OFF;
666: data->inputprompt = NULL;
667:
668: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
669: }
670:
671: int
672: window_copy_key_input(struct window_pane *wp, int key)
673: {
674: struct window_copy_mode_data *data = wp->modedata;
675: struct screen *s = &data->screen;
676: size_t inputlen;
1.50 nicm 677: u_int np;
1.21 nicm 678:
679: switch (mode_key_lookup(&data->mdata, key)) {
680: case MODEKEYEDIT_CANCEL:
1.50 nicm 681: data->numprefix = 0;
1.21 nicm 682: return (-1);
683: case MODEKEYEDIT_BACKSPACE:
684: inputlen = strlen(data->inputstr);
685: if (inputlen > 0)
686: data->inputstr[inputlen - 1] = '\0';
1.22 nicm 687: break;
688: case MODEKEYEDIT_DELETELINE:
689: *data->inputstr = '\0';
1.21 nicm 690: break;
691: case MODEKEYEDIT_ENTER:
1.50 nicm 692: np = data->numprefix;
693: if (np == 0)
694: np = 1;
695:
1.21 nicm 696: switch (data->inputtype) {
697: case WINDOW_COPY_OFF:
1.52 nicm 698: case WINDOW_COPY_JUMPFORWARD:
699: case WINDOW_COPY_JUMPBACK:
1.50 nicm 700: case WINDOW_COPY_NUMERICPREFIX:
1.21 nicm 701: break;
702: case WINDOW_COPY_SEARCHUP:
1.50 nicm 703: for (; np != 0; np--)
704: window_copy_search_up(wp, data->inputstr);
1.21 nicm 705: data->searchtype = data->inputtype;
706: data->searchstr = xstrdup(data->inputstr);
707: break;
708: case WINDOW_COPY_SEARCHDOWN:
1.50 nicm 709: for (; np != 0; np--)
710: window_copy_search_down(wp, data->inputstr);
1.21 nicm 711: data->searchtype = data->inputtype;
712: data->searchstr = xstrdup(data->inputstr);
713: break;
714: case WINDOW_COPY_GOTOLINE:
715: window_copy_goto_line(wp, data->inputstr);
716: *data->inputstr = '\0';
717: break;
718: }
1.50 nicm 719: data->numprefix = 0;
1.21 nicm 720: return (1);
721: case MODEKEY_OTHER:
722: if (key < 32 || key > 126)
723: break;
724: inputlen = strlen(data->inputstr) + 2;
1.35 nicm 725:
1.21 nicm 726: data->inputstr = xrealloc(data->inputstr, 1, inputlen);
727: data->inputstr[inputlen - 2] = key;
728: data->inputstr[inputlen - 1] = '\0';
729: break;
1.1 nicm 730: default:
731: break;
732: }
1.21 nicm 733:
734: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
735: return (0);
1.1 nicm 736: }
737:
1.50 nicm 738: int
739: window_copy_key_numeric_prefix(struct window_pane *wp, int key)
740: {
741: struct window_copy_mode_data *data = wp->modedata;
742: struct screen *s = &data->screen;
743:
744: key &= 0xff;
745: if (key < '0' || key > '9')
746: return 1;
747:
748: if (data->numprefix >= 100) /* no more than three digits */
749: return 0;
750: data->numprefix = data->numprefix * 10 + key - '0';
751:
752: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
753: return 0;
754: }
755:
1.34 nicm 756: /* ARGSUSED */
1.1 nicm 757: void
1.29 nicm 758: window_copy_mouse(
1.56 ! nicm 759: struct window_pane *wp, unused struct session *sess, struct mouse_event *m)
1.1 nicm 760: {
761: struct window_copy_mode_data *data = wp->modedata;
762: struct screen *s = &data->screen;
763:
1.29 nicm 764: if ((m->b & 3) == 3)
1.1 nicm 765: return;
1.29 nicm 766: if (m->x >= screen_size_x(s))
1.1 nicm 767: return;
1.29 nicm 768: if (m->y >= screen_size_y(s))
1.1 nicm 769: return;
770:
1.29 nicm 771: window_copy_update_cursor(wp, m->x, m->y);
1.1 nicm 772: if (window_copy_update_selection(wp))
1.35 nicm 773: window_copy_redraw_screen(wp);
1.1 nicm 774: }
775:
776: void
1.21 nicm 777: window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py)
778: {
779: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 780: struct grid *gd = data->backing->grid;
1.21 nicm 781: u_int offset, gap;
782:
783: data->cx = px;
784:
785: gap = gd->sy / 4;
786: if (py < gd->sy) {
787: offset = 0;
788: data->cy = py;
789: } else if (py > gd->hsize + gd->sy - gap) {
790: offset = gd->hsize;
791: data->cy = py - gd->hsize;
792: } else {
793: offset = py + gap - gd->sy;
794: data->cy = py - offset;
795: }
1.35 nicm 796: data->oy = gd->hsize - offset;
1.21 nicm 797:
1.38 nicm 798: window_copy_update_selection(wp);
1.21 nicm 799: window_copy_redraw_screen(wp);
800: }
801:
802: int
803: window_copy_search_compare(
804: struct grid *gd, u_int px, u_int py, struct grid *sgd, u_int spx)
805: {
806: const struct grid_cell *gc, *sgc;
807: const struct grid_utf8 *gu, *sgu;
808:
809: gc = grid_peek_cell(gd, px, py);
810: sgc = grid_peek_cell(sgd, spx, 0);
1.35 nicm 811:
1.21 nicm 812: if ((gc->flags & GRID_FLAG_UTF8) != (sgc->flags & GRID_FLAG_UTF8))
813: return (0);
814:
815: if (gc->flags & GRID_FLAG_UTF8) {
816: gu = grid_peek_utf8(gd, px, py);
817: sgu = grid_peek_utf8(sgd, spx, 0);
1.32 nicm 818: if (grid_utf8_compare(gu, sgu))
1.21 nicm 819: return (1);
820: } else {
821: if (gc->data == sgc->data)
822: return (1);
823: }
824: return (0);
825: }
826:
827: int
828: window_copy_search_lr(struct grid *gd,
829: struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last)
830: {
831: u_int ax, bx, px;
832:
833: for (ax = first; ax < last; ax++) {
834: if (ax + sgd->sx >= gd->sx)
835: break;
836: for (bx = 0; bx < sgd->sx; bx++) {
837: px = ax + bx;
838: if (!window_copy_search_compare(gd, px, py, sgd, bx))
839: break;
840: }
841: if (bx == sgd->sx) {
842: *ppx = ax;
843: return (1);
844: }
845: }
846: return (0);
847: }
848:
849: int
850: window_copy_search_rl(struct grid *gd,
851: struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last)
852: {
853: u_int ax, bx, px;
854:
855: for (ax = last + 1; ax > first; ax--) {
1.24 nicm 856: if (gd->sx - (ax - 1) < sgd->sx)
857: continue;
1.21 nicm 858: for (bx = 0; bx < sgd->sx; bx++) {
859: px = ax - 1 + bx;
860: if (!window_copy_search_compare(gd, px, py, sgd, bx))
861: break;
862: }
863: if (bx == sgd->sx) {
864: *ppx = ax - 1;
865: return (1);
866: }
867: }
868: return (0);
869: }
870:
871: void
872: window_copy_search_up(struct window_pane *wp, const char *searchstr)
873: {
874: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 875: struct screen *s = data->backing, ss;
1.21 nicm 876: struct screen_write_ctx ctx;
877: struct grid *gd = s->grid, *sgd;
878: struct grid_cell gc;
879: size_t searchlen;
880: u_int i, last, fx, fy, px;
881: int utf8flag, n, wrapped;
882:
883: if (*searchstr == '\0')
884: return;
885: utf8flag = options_get_number(&wp->window->options, "utf8");
886: searchlen = screen_write_strlen(utf8flag, "%s", searchstr);
887:
888: screen_init(&ss, searchlen, 1, 0);
889: screen_write_start(&ctx, NULL, &ss);
890: memcpy(&gc, &grid_default_cell, sizeof gc);
891: screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr);
892: screen_write_stop(&ctx);
893:
894: fx = data->cx;
895: fy = gd->hsize - data->oy + data->cy;
896:
897: if (fx == 0) {
898: if (fy == 0)
899: return;
900: fx = gd->sx - 1;
901: fy--;
902: } else
903: fx--;
904: n = wrapped = 0;
905:
906: retry:
907: sgd = ss.grid;
908: for (i = fy + 1; i > 0; i--) {
909: last = screen_size_x(s);
910: if (i == fy + 1)
911: last = fx;
912: n = window_copy_search_rl(gd, sgd, &px, i - 1, 0, last);
913: if (n) {
914: window_copy_scroll_to(wp, px, i - 1);
915: break;
916: }
917: }
918: if (!n && !wrapped) {
919: fx = gd->sx - 1;
920: fy = gd->hsize + gd->sy - 1;
921: wrapped = 1;
922: goto retry;
923: }
924:
925: screen_free(&ss);
926: }
927:
928: void
929: window_copy_search_down(struct window_pane *wp, const char *searchstr)
930: {
931: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 932: struct screen *s = data->backing, ss;
1.21 nicm 933: struct screen_write_ctx ctx;
934: struct grid *gd = s->grid, *sgd;
935: struct grid_cell gc;
936: size_t searchlen;
937: u_int i, first, fx, fy, px;
938: int utf8flag, n, wrapped;
939:
940: if (*searchstr == '\0')
941: return;
942: utf8flag = options_get_number(&wp->window->options, "utf8");
943: searchlen = screen_write_strlen(utf8flag, "%s", searchstr);
944:
945: screen_init(&ss, searchlen, 1, 0);
946: screen_write_start(&ctx, NULL, &ss);
947: memcpy(&gc, &grid_default_cell, sizeof gc);
948: screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr);
949: screen_write_stop(&ctx);
950:
951: fx = data->cx;
952: fy = gd->hsize - data->oy + data->cy;
953:
954: if (fx == gd->sx - 1) {
955: if (fy == gd->hsize + gd->sy)
956: return;
957: fx = 0;
958: fy++;
959: } else
960: fx++;
961: n = wrapped = 0;
962:
963: retry:
964: sgd = ss.grid;
965: for (i = fy + 1; i < gd->hsize + gd->sy; i++) {
966: first = 0;
967: if (i == fy + 1)
968: first = fx;
969: n = window_copy_search_lr(gd, sgd, &px, i - 1, first, gd->sx);
970: if (n) {
971: window_copy_scroll_to(wp, px, i - 1);
972: break;
973: }
974: }
975: if (!n && !wrapped) {
976: fx = 0;
977: fy = 0;
978: wrapped = 1;
979: goto retry;
980: }
981:
982: screen_free(&ss);
983: }
984:
985: void
986: window_copy_goto_line(struct window_pane *wp, const char *linestr)
987: {
988: struct window_copy_mode_data *data = wp->modedata;
989: const char *errstr;
990: u_int lineno;
991:
1.54 nicm 992: lineno = strtonum(linestr, 0, screen_hsize(data->backing), &errstr);
1.21 nicm 993: if (errstr != NULL)
994: return;
1.35 nicm 995:
1.21 nicm 996: data->oy = lineno;
1.38 nicm 997: window_copy_update_selection(wp);
1.21 nicm 998: window_copy_redraw_screen(wp);
999: }
1000:
1001: void
1.18 nicm 1002: window_copy_write_line(
1003: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
1.1 nicm 1004: {
1005: struct window_copy_mode_data *data = wp->modedata;
1006: struct screen *s = &data->screen;
1.27 nicm 1007: struct options *oo = &wp->window->options;
1.1 nicm 1008: struct grid_cell gc;
1009: char hdr[32];
1.21 nicm 1010: size_t last, xoff = 0, size = 0;
1011:
1012: memcpy(&gc, &grid_default_cell, sizeof gc);
1.27 nicm 1013: colour_set_fg(&gc, options_get_number(oo, "mode-fg"));
1014: colour_set_bg(&gc, options_get_number(oo, "mode-bg"));
1015: gc.attr |= options_get_number(oo, "mode-attr");
1.1 nicm 1016:
1.21 nicm 1017: last = screen_size_y(s) - 1;
1.1 nicm 1018: if (py == 0) {
1019: size = xsnprintf(hdr, sizeof hdr,
1.54 nicm 1020: "[%u/%u]", data->oy, screen_hsize(data->backing));
1.1 nicm 1021: screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
1022: screen_write_puts(ctx, &gc, "%s", hdr);
1.21 nicm 1023: } else if (py == last && data->inputtype != WINDOW_COPY_OFF) {
1.50 nicm 1024: if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) {
1025: xoff = size = xsnprintf(hdr, sizeof hdr,
1026: "Repeat: %u", data->numprefix);
1027: } else {
1028: xoff = size = xsnprintf(hdr, sizeof hdr,
1029: "%s: %s", data->inputprompt, data->inputstr);
1030: }
1.21 nicm 1031: screen_write_cursormove(ctx, 0, last);
1032: screen_write_puts(ctx, &gc, "%s", hdr);
1.1 nicm 1033: } else
1034: size = 0;
1035:
1.21 nicm 1036: screen_write_cursormove(ctx, xoff, py);
1.54 nicm 1037: screen_write_copy(ctx, data->backing, xoff,
1038: (screen_hsize(data->backing) - data->oy) + py,
1039: screen_size_x(s) - size, 1);
1.18 nicm 1040:
1041: if (py == data->cy && data->cx == screen_size_x(s)) {
1042: memcpy(&gc, &grid_default_cell, sizeof gc);
1043: screen_write_cursormove(ctx, screen_size_x(s) - 1, py);
1044: screen_write_putc(ctx, &gc, '$');
1045: }
1.1 nicm 1046: }
1047:
1048: void
1049: window_copy_write_lines(
1050: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py, u_int ny)
1051: {
1052: u_int yy;
1053:
1054: for (yy = py; yy < py + ny; yy++)
1055: window_copy_write_line(wp, ctx, py);
1056: }
1057:
1058: void
1059: window_copy_redraw_lines(struct window_pane *wp, u_int py, u_int ny)
1060: {
1061: struct window_copy_mode_data *data = wp->modedata;
1062: struct screen_write_ctx ctx;
1063: u_int i;
1064:
1065: screen_write_start(&ctx, wp, NULL);
1066: for (i = py; i < py + ny; i++)
1067: window_copy_write_line(wp, &ctx, i);
1068: screen_write_cursormove(&ctx, data->cx, data->cy);
1069: screen_write_stop(&ctx);
1070: }
1071:
1072: void
1073: window_copy_redraw_screen(struct window_pane *wp)
1074: {
1075: struct window_copy_mode_data *data = wp->modedata;
1076:
1077: window_copy_redraw_lines(wp, 0, screen_size_y(&data->screen));
1078: }
1079:
1080: void
1.18 nicm 1081: window_copy_update_cursor(struct window_pane *wp, u_int cx, u_int cy)
1.1 nicm 1082: {
1083: struct window_copy_mode_data *data = wp->modedata;
1.18 nicm 1084: struct screen *s = &data->screen;
1.1 nicm 1085: struct screen_write_ctx ctx;
1.18 nicm 1086: u_int old_cx, old_cy;
1.1 nicm 1087:
1.18 nicm 1088: old_cx = data->cx; old_cy = data->cy;
1089: data->cx = cx; data->cy = cy;
1090: if (old_cx == screen_size_x(s))
1091: window_copy_redraw_lines(wp, old_cy, 1);
1092: if (data->cx == screen_size_x(s))
1093: window_copy_redraw_lines(wp, data->cy, 1);
1094: else {
1095: screen_write_start(&ctx, wp, NULL);
1096: screen_write_cursormove(&ctx, data->cx, data->cy);
1097: screen_write_stop(&ctx);
1098: }
1.1 nicm 1099: }
1100:
1101: void
1102: window_copy_start_selection(struct window_pane *wp)
1103: {
1104: struct window_copy_mode_data *data = wp->modedata;
1105: struct screen *s = &data->screen;
1106:
1.18 nicm 1107: data->selx = data->cx;
1.54 nicm 1108: data->sely = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 1109:
1110: s->sel.flag = 1;
1111: window_copy_update_selection(wp);
1112: }
1113:
1114: int
1115: window_copy_update_selection(struct window_pane *wp)
1116: {
1117: struct window_copy_mode_data *data = wp->modedata;
1118: struct screen *s = &data->screen;
1.27 nicm 1119: struct options *oo = &wp->window->options;
1.1 nicm 1120: struct grid_cell gc;
1.42 nicm 1121: u_int sx, sy, ty, cy;
1.1 nicm 1122:
1123: if (!s->sel.flag)
1124: return (0);
1125:
1126: /* Set colours. */
1127: memcpy(&gc, &grid_default_cell, sizeof gc);
1.27 nicm 1128: colour_set_fg(&gc, options_get_number(oo, "mode-fg"));
1129: colour_set_bg(&gc, options_get_number(oo, "mode-bg"));
1130: gc.attr |= options_get_number(oo, "mode-attr");
1.1 nicm 1131:
1.18 nicm 1132: /* Find top of screen. */
1.54 nicm 1133: ty = screen_hsize(data->backing) - data->oy;
1.1 nicm 1134:
1135: /* Adjust the selection. */
1136: sx = data->selx;
1137: sy = data->sely;
1.18 nicm 1138: if (sy < ty) { /* above screen */
1.42 nicm 1139: if (!data->rectflag)
1140: sx = 0;
1.1 nicm 1141: sy = 0;
1.18 nicm 1142: } else if (sy > ty + screen_size_y(s) - 1) { /* below screen */
1.42 nicm 1143: if (!data->rectflag)
1144: sx = screen_size_x(s) - 1;
1.1 nicm 1145: sy = screen_size_y(s) - 1;
1.18 nicm 1146: } else
1.1 nicm 1147: sy -= ty;
1148: sy = screen_hsize(s) + sy;
1149:
1.42 nicm 1150: screen_set_selection(s,
1151: sx, sy, data->cx, screen_hsize(s) + data->cy, data->rectflag, &gc);
1152:
1153: if (data->rectflag) {
1154: /*
1155: * Can't rely on the caller to redraw the right lines for
1156: * rectangle selection - find the highest line and the number
1157: * of lines, and redraw just past that in both directions
1158: */
1159: cy = data->cy;
1160: if (sy < cy)
1161: window_copy_redraw_lines(wp, sy, cy - sy + 1);
1162: else
1163: window_copy_redraw_lines(wp, cy, sy - cy + 1);
1164: }
1165:
1.1 nicm 1166: return (1);
1167: }
1168:
1169: void
1.56 ! nicm 1170: window_copy_copy_selection(struct window_pane *wp, struct session *sess)
1.1 nicm 1171: {
1172: struct window_copy_mode_data *data = wp->modedata;
1173: struct screen *s = &data->screen;
1174: char *buf;
1.42 nicm 1175: size_t off;
1176: u_int i, xx, yy, sx, sy, ex, ey, limit;
1177: u_int firstsx, lastex, restex, restsx;
1.1 nicm 1178:
1179: if (!s->sel.flag)
1180: return;
1181:
1182: buf = xmalloc(1);
1183: off = 0;
1184:
1185: *buf = '\0';
1186:
1187: /*
1188: * The selection extends from selx,sely to (adjusted) cx,cy on
1189: * the base screen.
1190: */
1191:
1192: /* Find start and end. */
1.18 nicm 1193: xx = data->cx;
1.54 nicm 1194: yy = screen_hsize(data->backing) + data->cy - data->oy;
1.2 nicm 1195: if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
1.1 nicm 1196: sx = xx; sy = yy;
1197: ex = data->selx; ey = data->sely;
1198: } else {
1199: sx = data->selx; sy = data->sely;
1200: ex = xx; ey = yy;
1201: }
1202:
1203: /* Trim ex to end of line. */
1204: xx = window_copy_find_length(wp, ey);
1205: if (ex > xx)
1206: ex = xx;
1207:
1.42 nicm 1208: /*
1209: * Deal with rectangle-copy if necessary; four situations: start of
1210: * first line (firstsx), end of last line (lastex), start (restsx) and
1211: * end (restex) of all other lines.
1212: */
1213: xx = screen_size_x(s);
1214: if (data->rectflag) {
1215: /*
1216: * Need to ignore the column with the cursor in it, which for
1217: * rectangular copy means knowing which side the cursor is on.
1218: */
1219: if (data->selx < data->cx) {
1220: /* Selection start is on the left. */
1221: lastex = data->cx;
1222: restex = data->cx;
1223: firstsx = data->selx;
1224: restsx = data->selx;
1225: } else {
1226: /* Cursor is on the left. */
1227: lastex = data->selx + 1;
1228: restex = data->selx + 1;
1229: firstsx = data->cx + 1;
1230: restsx = data->cx + 1;
1231: }
1232: } else {
1233: /*
1234: * Like emacs, keep the top-left-most character, and drop the
1235: * bottom-right-most, regardless of copy direction.
1236: */
1237: lastex = ex;
1238: restex = xx;
1239: firstsx = sx;
1240: restsx = 0;
1241: }
1242:
1.1 nicm 1243: /* Copy the lines. */
1244: if (sy == ey)
1.42 nicm 1245: window_copy_copy_line(wp, &buf, &off, sy, firstsx, lastex);
1.1 nicm 1246: else {
1.42 nicm 1247: window_copy_copy_line(wp, &buf, &off, sy, firstsx, restex);
1.1 nicm 1248: if (ey - sy > 1) {
1.42 nicm 1249: for (i = sy + 1; i < ey; i++) {
1250: window_copy_copy_line(
1251: wp, &buf, &off, i, restsx, restex);
1252: }
1.1 nicm 1253: }
1.42 nicm 1254: window_copy_copy_line(wp, &buf, &off, ey, restsx, lastex);
1.1 nicm 1255: }
1256:
1.26 nicm 1257: /* Don't bother if no data. */
1258: if (off == 0) {
1259: xfree(buf);
1260: return;
1261: }
1262: off--; /* remove final \n */
1.1 nicm 1263:
1264: /* Add the buffer to the stack. */
1.56 ! nicm 1265: limit = options_get_number(&sess->options, "buffer-limit");
! 1266: paste_add(&sess->buffers, buf, off, limit);
1.1 nicm 1267: }
1268:
1269: void
1270: window_copy_copy_line(struct window_pane *wp,
1271: char **buf, size_t *off, u_int sy, u_int sx, u_int ex)
1272: {
1.54 nicm 1273: struct window_copy_mode_data *data = wp->modedata;
1274: struct grid *gd = data->backing->grid;
1275: const struct grid_cell *gc;
1276: const struct grid_utf8 *gu;
1277: struct grid_line *gl;
1278: u_int i, xx, wrapped = 0;
1279: size_t size;
1.1 nicm 1280:
1281: if (sx > ex)
1282: return;
1283:
1.16 nicm 1284: /*
1285: * Work out if the line was wrapped at the screen edge and all of it is
1286: * on screen.
1287: */
1288: gl = &gd->linedata[sy];
1.35 nicm 1289: if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
1.16 nicm 1290: wrapped = 1;
1291:
1292: /* If the line was wrapped, don't strip spaces (use the full length). */
1293: if (wrapped)
1294: xx = gl->cellsize;
1295: else
1296: xx = window_copy_find_length(wp, sy);
1.1 nicm 1297: if (ex > xx)
1298: ex = xx;
1299: if (sx > xx)
1300: sx = xx;
1301:
1302: if (sx < ex) {
1303: for (i = sx; i < ex; i++) {
1.16 nicm 1304: gc = grid_peek_cell(gd, i, sy);
1.1 nicm 1305: if (gc->flags & GRID_FLAG_PADDING)
1306: continue;
1307: if (!(gc->flags & GRID_FLAG_UTF8)) {
1308: *buf = xrealloc(*buf, 1, (*off) + 1);
1309: (*buf)[(*off)++] = gc->data;
1310: } else {
1.16 nicm 1311: gu = grid_peek_utf8(gd, i, sy);
1.32 nicm 1312: size = grid_utf8_size(gu);
1313: *buf = xrealloc(*buf, 1, (*off) + size);
1314: *off += grid_utf8_copy(gu, *buf + *off, size);
1.1 nicm 1315: }
1316: }
1317: }
1318:
1.16 nicm 1319: /* Only add a newline if the line wasn't wrapped. */
1.44 nicm 1320: if (!wrapped || ex != xx) {
1.16 nicm 1321: *buf = xrealloc(*buf, 1, (*off) + 1);
1322: (*buf)[(*off)++] = '\n';
1323: }
1.1 nicm 1324: }
1325:
1.47 nicm 1326: void
1327: window_copy_clear_selection(struct window_pane *wp)
1328: {
1329: struct window_copy_mode_data *data = wp->modedata;
1330: u_int px, py;
1331:
1332: screen_clear_selection(&data->screen);
1333:
1.54 nicm 1334: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 1335: px = window_copy_find_length(wp, py);
1336: if (data->cx > px)
1337: window_copy_update_cursor(wp, px, data->cy);
1338: }
1339:
1.1 nicm 1340: int
1.41 nicm 1341: window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set)
1.1 nicm 1342: {
1.54 nicm 1343: struct window_copy_mode_data *data = wp->modedata;
1344: const struct grid_cell *gc;
1.1 nicm 1345:
1.54 nicm 1346: gc = grid_peek_cell(data->backing->grid, px, py);
1.1 nicm 1347: if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8))
1348: return (0);
1349: if (gc->data == 0x00 || gc->data == 0x7f)
1350: return (0);
1.41 nicm 1351: return (strchr(set, gc->data) != NULL);
1.1 nicm 1352: }
1353:
1354: u_int
1355: window_copy_find_length(struct window_pane *wp, u_int py)
1356: {
1.54 nicm 1357: struct window_copy_mode_data *data = wp->modedata;
1358: struct screen *s = data->backing;
1359: const struct grid_cell *gc;
1360: u_int px;
1.1 nicm 1361:
1.4 nicm 1362: /*
1363: * If the pane has been resized, its grid can contain old overlong
1364: * lines. grid_peek_cell does not allow accessing cells beyond the
1365: * width of the grid, and screen_write_copy treats them as spaces, so
1366: * ignore them here too.
1367: */
1.54 nicm 1368: px = s->grid->linedata[py].cellsize;
1369: if (px > screen_size_x(s))
1370: px = screen_size_x(s);
1.1 nicm 1371: while (px > 0) {
1.54 nicm 1372: gc = grid_peek_cell(s->grid, px - 1, py);
1.1 nicm 1373: if (gc->flags & GRID_FLAG_UTF8)
1374: break;
1375: if (gc->data != ' ')
1376: break;
1377: px--;
1378: }
1379: return (px);
1380: }
1381:
1382: void
1.5 nicm 1383: window_copy_cursor_start_of_line(struct window_pane *wp)
1384: {
1385: struct window_copy_mode_data *data = wp->modedata;
1386:
1.18 nicm 1387: window_copy_update_cursor(wp, 0, data->cy);
1.5 nicm 1388: if (window_copy_update_selection(wp))
1389: window_copy_redraw_lines(wp, data->cy, 1);
1.6 nicm 1390: }
1391:
1392: void
1393: window_copy_cursor_back_to_indentation(struct window_pane *wp)
1394: {
1395: struct window_copy_mode_data *data = wp->modedata;
1396: u_int px, py, xx;
1397: const struct grid_cell *gc;
1398:
1399: px = 0;
1.54 nicm 1400: py = screen_hsize(data->backing) + data->cy - data->oy;
1.6 nicm 1401: xx = window_copy_find_length(wp, py);
1402:
1403: while (px < xx) {
1.54 nicm 1404: gc = grid_peek_cell(data->backing->grid, px, py);
1.6 nicm 1405: if (gc->flags & GRID_FLAG_UTF8)
1406: break;
1407: if (gc->data != ' ')
1408: break;
1409: px++;
1410: }
1411:
1.18 nicm 1412: window_copy_update_cursor(wp, px, data->cy);
1413: if (window_copy_update_selection(wp))
1414: window_copy_redraw_lines(wp, data->cy, 1);
1.5 nicm 1415: }
1416:
1417: void
1418: window_copy_cursor_end_of_line(struct window_pane *wp)
1419: {
1420: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1421: struct screen *back_s = data->backing;
1422: struct grid *gd = back_s->grid;
1.5 nicm 1423: u_int px, py;
1424:
1.54 nicm 1425: py = screen_hsize(back_s) + data->cy - data->oy;
1.5 nicm 1426: px = window_copy_find_length(wp, py);
1427:
1.49 nicm 1428: if (data->cx == px) {
1429: if (data->screen.sel.flag && data->rectflag)
1.54 nicm 1430: px = screen_size_x(back_s);
1.49 nicm 1431: if (gd->linedata[py].flags & GRID_LINE_WRAPPED) {
1432: while (py < gd->sy + gd->hsize &&
1433: gd->linedata[py].flags & GRID_LINE_WRAPPED) {
1434: window_copy_cursor_down(wp, 0);
1.54 nicm 1435: py = screen_hsize(back_s)
1436: + data->cy - data->oy;
1.49 nicm 1437: }
1438: px = window_copy_find_length(wp, py);
1439: }
1440: }
1.18 nicm 1441: window_copy_update_cursor(wp, px, data->cy);
1.49 nicm 1442:
1.18 nicm 1443: if (window_copy_update_selection(wp))
1444: window_copy_redraw_lines(wp, data->cy, 1);
1.5 nicm 1445: }
1446:
1447: void
1.1 nicm 1448: window_copy_cursor_left(struct window_pane *wp)
1449: {
1450: struct window_copy_mode_data *data = wp->modedata;
1451:
1452: if (data->cx == 0) {
1.28 nicm 1453: window_copy_cursor_up(wp, 0);
1.18 nicm 1454: window_copy_cursor_end_of_line(wp);
1.1 nicm 1455: } else {
1.18 nicm 1456: window_copy_update_cursor(wp, data->cx - 1, data->cy);
1.1 nicm 1457: if (window_copy_update_selection(wp))
1458: window_copy_redraw_lines(wp, data->cy, 1);
1459: }
1460: }
1461:
1462: void
1463: window_copy_cursor_right(struct window_pane *wp)
1464: {
1465: struct window_copy_mode_data *data = wp->modedata;
1466: u_int px, py;
1467:
1.47 nicm 1468: if (data->screen.sel.flag && data->rectflag)
1469: px = screen_size_x(&data->screen);
1470: else {
1.54 nicm 1471: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 1472: px = window_copy_find_length(wp, py);
1473: }
1.1 nicm 1474:
1475: if (data->cx >= px) {
1476: window_copy_cursor_start_of_line(wp);
1.28 nicm 1477: window_copy_cursor_down(wp, 0);
1.1 nicm 1478: } else {
1.18 nicm 1479: window_copy_update_cursor(wp, data->cx + 1, data->cy);
1.1 nicm 1480: if (window_copy_update_selection(wp))
1481: window_copy_redraw_lines(wp, data->cy, 1);
1482: }
1483: }
1484:
1485: void
1.28 nicm 1486: window_copy_cursor_up(struct window_pane *wp, int scroll_only)
1.1 nicm 1487: {
1488: struct window_copy_mode_data *data = wp->modedata;
1.36 nicm 1489: struct screen *s = &data->screen;
1.1 nicm 1490: u_int ox, oy, px, py;
1491:
1.54 nicm 1492: oy = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 1493: ox = window_copy_find_length(wp, oy);
1.25 nicm 1494: if (ox != 0) {
1495: data->lastcx = data->cx;
1496: data->lastsx = ox;
1497: }
1.1 nicm 1498:
1.25 nicm 1499: data->cx = data->lastcx;
1.28 nicm 1500: if (scroll_only || data->cy == 0) {
1.1 nicm 1501: window_copy_scroll_down(wp, 1);
1.36 nicm 1502: if (scroll_only) {
1503: if (data->cy == screen_size_y(s) - 1)
1504: window_copy_redraw_lines(wp, data->cy, 1);
1505: else
1506: window_copy_redraw_lines(wp, data->cy, 2);
1507: }
1.28 nicm 1508: } else {
1.18 nicm 1509: window_copy_update_cursor(wp, data->cx, data->cy - 1);
1.36 nicm 1510: if (window_copy_update_selection(wp)) {
1511: if (data->cy == screen_size_y(s) - 1)
1512: window_copy_redraw_lines(wp, data->cy, 1);
1513: else
1514: window_copy_redraw_lines(wp, data->cy, 2);
1515: }
1.1 nicm 1516: }
1517:
1.47 nicm 1518: if (!data->screen.sel.flag || !data->rectflag) {
1.54 nicm 1519: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 1520: px = window_copy_find_length(wp, py);
1.49 nicm 1521: if ((data->cx >= data->lastsx && data->cx != px) ||
1522: data->cx > px)
1.47 nicm 1523: window_copy_cursor_end_of_line(wp);
1524: }
1.1 nicm 1525: }
1526:
1527: void
1.28 nicm 1528: window_copy_cursor_down(struct window_pane *wp, int scroll_only)
1.1 nicm 1529: {
1530: struct window_copy_mode_data *data = wp->modedata;
1531: struct screen *s = &data->screen;
1532: u_int ox, oy, px, py;
1533:
1.54 nicm 1534: oy = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 1535: ox = window_copy_find_length(wp, oy);
1.25 nicm 1536: if (ox != 0) {
1537: data->lastcx = data->cx;
1538: data->lastsx = ox;
1539: }
1.1 nicm 1540:
1.25 nicm 1541: data->cx = data->lastcx;
1.28 nicm 1542: if (scroll_only || data->cy == screen_size_y(s) - 1) {
1.1 nicm 1543: window_copy_scroll_up(wp, 1);
1.31 nicm 1544: if (scroll_only && data->cy > 0)
1.28 nicm 1545: window_copy_redraw_lines(wp, data->cy - 1, 2);
1546: } else {
1.18 nicm 1547: window_copy_update_cursor(wp, data->cx, data->cy + 1);
1.1 nicm 1548: if (window_copy_update_selection(wp))
1549: window_copy_redraw_lines(wp, data->cy - 1, 2);
1550: }
1551:
1.47 nicm 1552: if (!data->screen.sel.flag || !data->rectflag) {
1.54 nicm 1553: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 1554: px = window_copy_find_length(wp, py);
1.49 nicm 1555: if ((data->cx >= data->lastsx && data->cx != px) ||
1556: data->cx > px)
1.47 nicm 1557: window_copy_cursor_end_of_line(wp);
1.52 nicm 1558: }
1559: }
1560:
1561: void
1562: window_copy_cursor_jump(struct window_pane *wp)
1563: {
1564: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1565: struct screen *back_s = data->backing;
1.52 nicm 1566: const struct grid_cell *gc;
1567: uint px, py, xx;
1568:
1569: px = data->cx + 1;
1.54 nicm 1570: py = screen_hsize(back_s) + data->cy - data->oy;
1.52 nicm 1571: xx = window_copy_find_length(wp, py);
1572:
1573: while (px < xx) {
1.54 nicm 1574: gc = grid_peek_cell(back_s->grid, px, py);
1.52 nicm 1575: if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
1576: && gc->data == data->jumpchar) {
1577:
1578: window_copy_update_cursor(wp, px, data->cy);
1579: if (window_copy_update_selection(wp))
1580: window_copy_redraw_lines(wp, data->cy, 1);
1581: return;
1582: }
1583: px++;
1584: }
1585: }
1586:
1587: void
1588: window_copy_cursor_jump_back(struct window_pane *wp)
1589: {
1590: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1591: struct screen *back_s = data->backing;
1.52 nicm 1592: const struct grid_cell *gc;
1593: uint px, py;
1594:
1595: px = data->cx;
1.54 nicm 1596: py = screen_hsize(back_s) + data->cy - data->oy;
1.52 nicm 1597:
1598: if (px > 0)
1599: px--;
1600:
1601: for (;;) {
1.54 nicm 1602: gc = grid_peek_cell(back_s->grid, px, py);
1.52 nicm 1603: if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
1604: && gc->data == data->jumpchar) {
1605:
1606: window_copy_update_cursor(wp, px, data->cy);
1607: if (window_copy_update_selection(wp))
1608: window_copy_redraw_lines(wp, data->cy, 1);
1609: return;
1610: }
1611: if (px == 0)
1612: break;
1613: px--;
1.47 nicm 1614: }
1.1 nicm 1615: }
1616:
1617: void
1.41 nicm 1618: window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
1.40 nicm 1619: {
1620: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1621: struct screen *back_s = data->backing;
1.40 nicm 1622: u_int px, py, xx, yy;
1.48 nicm 1623: int expected = 0;
1.40 nicm 1624:
1625: px = data->cx;
1.54 nicm 1626: py = screen_hsize(back_s) + data->cy - data->oy;
1.40 nicm 1627: xx = window_copy_find_length(wp, py);
1.54 nicm 1628: yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
1.40 nicm 1629:
1.48 nicm 1630: /*
1631: * First skip past any nonword characters and then any word characters.
1632: *
1633: * expected is initially set to 0 for the former and then 1 for the
1634: * latter.
1635: */
1636: do {
1637: while (px > xx ||
1638: window_copy_in_set(wp, px, py, separators) == expected) {
1639: /* Move down if we're past the end of the line. */
1640: if (px > xx) {
1641: if (py == yy)
1642: return;
1643: window_copy_cursor_down(wp, 0);
1644: px = 0;
1645:
1.54 nicm 1646: py = screen_hsize(back_s) + data->cy - data->oy;
1.48 nicm 1647: xx = window_copy_find_length(wp, py);
1648: } else
1649: px++;
1650: }
1651: expected = !expected;
1652: } while (expected == 1);
1.40 nicm 1653:
1654: window_copy_update_cursor(wp, px, data->cy);
1655: if (window_copy_update_selection(wp))
1656: window_copy_redraw_lines(wp, data->cy, 1);
1657: }
1658:
1659: void
1.41 nicm 1660: window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators)
1.1 nicm 1661: {
1662: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1663: struct screen *back_s = data->backing;
1.39 nicm 1664: u_int px, py, xx, yy;
1.48 nicm 1665: int expected = 1;
1.1 nicm 1666:
1.18 nicm 1667: px = data->cx;
1.54 nicm 1668: py = screen_hsize(back_s) + data->cy - data->oy;
1.1 nicm 1669: xx = window_copy_find_length(wp, py);
1.54 nicm 1670: yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
1.1 nicm 1671:
1.48 nicm 1672: /*
1673: * First skip past any word characters, then any nonword characters.
1674: *
1675: * expected is initially set to 1 for the former and then 0 for the
1676: * latter.
1677: */
1678: do {
1679: while (px > xx ||
1680: window_copy_in_set(wp, px, py, separators) == expected) {
1681: /* Move down if we're past the end of the line. */
1682: if (px > xx) {
1683: if (py == yy)
1684: return;
1685: window_copy_cursor_down(wp, 0);
1686: px = 0;
1687:
1.54 nicm 1688: py = screen_hsize(back_s) + data->cy - data->oy;
1.48 nicm 1689: xx = window_copy_find_length(wp, py);
1690: } else
1691: px++;
1692: }
1693: expected = !expected;
1694: } while (expected == 0);
1.18 nicm 1695:
1696: window_copy_update_cursor(wp, px, data->cy);
1697: if (window_copy_update_selection(wp))
1698: window_copy_redraw_lines(wp, data->cy, 1);
1.1 nicm 1699: }
1700:
1.8 nicm 1701: /* Move to the previous place where a word begins. */
1.1 nicm 1702: void
1.41 nicm 1703: window_copy_cursor_previous_word(struct window_pane *wp, const char *separators)
1.1 nicm 1704: {
1705: struct window_copy_mode_data *data = wp->modedata;
1.8 nicm 1706: u_int px, py;
1.1 nicm 1707:
1.18 nicm 1708: px = data->cx;
1.54 nicm 1709: py = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 1710:
1.8 nicm 1711: /* Move back to the previous word character. */
1.1 nicm 1712: for (;;) {
1.8 nicm 1713: if (px > 0) {
1714: px--;
1.41 nicm 1715: if (!window_copy_in_set(wp, px, py, separators))
1.1 nicm 1716: break;
1.8 nicm 1717: } else {
1718: if (data->cy == 0 &&
1.54 nicm 1719: (screen_hsize(data->backing) == 0 ||
1720: data->oy >= screen_hsize(data->backing) - 1))
1.8 nicm 1721: goto out;
1.28 nicm 1722: window_copy_cursor_up(wp, 0);
1.1 nicm 1723:
1.54 nicm 1724: py = screen_hsize(data->backing) + data->cy - data->oy;
1.8 nicm 1725: px = window_copy_find_length(wp, py);
1.1 nicm 1726: }
1.8 nicm 1727: }
1.1 nicm 1728:
1.8 nicm 1729: /* Move back to the beginning of this word. */
1.41 nicm 1730: while (px > 0 && !window_copy_in_set(wp, px - 1, py, separators))
1.1 nicm 1731: px--;
1.8 nicm 1732:
1.1 nicm 1733: out:
1.18 nicm 1734: window_copy_update_cursor(wp, px, data->cy);
1735: if (window_copy_update_selection(wp))
1736: window_copy_redraw_lines(wp, data->cy, 1);
1.1 nicm 1737: }
1738:
1739: void
1740: window_copy_scroll_up(struct window_pane *wp, u_int ny)
1741: {
1742: struct window_copy_mode_data *data = wp->modedata;
1743: struct screen *s = &data->screen;
1744: struct screen_write_ctx ctx;
1745:
1746: if (data->oy < ny)
1747: ny = data->oy;
1748: if (ny == 0)
1749: return;
1750: data->oy -= ny;
1751:
1752: screen_write_start(&ctx, wp, NULL);
1753: screen_write_cursormove(&ctx, 0, 0);
1754: screen_write_deleteline(&ctx, ny);
1755: window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, ny);
1756: window_copy_write_line(wp, &ctx, 0);
1.31 nicm 1757: if (screen_size_y(s) > 1)
1758: window_copy_write_line(wp, &ctx, 1);
1759: if (screen_size_y(s) > 3)
1760: window_copy_write_line(wp, &ctx, screen_size_y(s) - 2);
1.42 nicm 1761: if (s->sel.flag && screen_size_y(s) > ny) {
1762: window_copy_update_selection(wp);
1.1 nicm 1763: window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1);
1.42 nicm 1764: }
1.1 nicm 1765: screen_write_cursormove(&ctx, data->cx, data->cy);
1.42 nicm 1766: window_copy_update_selection(wp);
1.1 nicm 1767: screen_write_stop(&ctx);
1768: }
1769:
1770: void
1771: window_copy_scroll_down(struct window_pane *wp, u_int ny)
1772: {
1773: struct window_copy_mode_data *data = wp->modedata;
1774: struct screen *s = &data->screen;
1775: struct screen_write_ctx ctx;
1776:
1.54 nicm 1777: if (ny > screen_hsize(data->backing))
1.1 nicm 1778: return;
1779:
1.54 nicm 1780: if (data->oy > screen_hsize(data->backing) - ny)
1781: ny = screen_hsize(data->backing) - data->oy;
1.1 nicm 1782: if (ny == 0)
1783: return;
1784: data->oy += ny;
1785:
1786: screen_write_start(&ctx, wp, NULL);
1787: screen_write_cursormove(&ctx, 0, 0);
1788: screen_write_insertline(&ctx, ny);
1789: window_copy_write_lines(wp, &ctx, 0, ny);
1.42 nicm 1790: if (s->sel.flag && screen_size_y(s) > ny) {
1791: window_copy_update_selection(wp);
1.1 nicm 1792: window_copy_write_line(wp, &ctx, ny);
1.42 nicm 1793: } else if (ny == 1) /* nuke position */
1.1 nicm 1794: window_copy_write_line(wp, &ctx, 1);
1795: screen_write_cursormove(&ctx, data->cx, data->cy);
1.42 nicm 1796: window_copy_update_selection(wp);
1.1 nicm 1797: screen_write_stop(&ctx);
1798: }
1.42 nicm 1799:
1800: void
1801: window_copy_rectangle_toggle(struct window_pane *wp)
1802: {
1803: struct window_copy_mode_data *data = wp->modedata;
1.47 nicm 1804: u_int px, py;
1.42 nicm 1805:
1806: data->rectflag = !data->rectflag;
1.47 nicm 1807:
1.54 nicm 1808: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 1809: px = window_copy_find_length(wp, py);
1810: if (data->cx > px)
1811: window_copy_update_cursor(wp, px, data->cy);
1.42 nicm 1812:
1813: window_copy_update_selection(wp);
1814: window_copy_redraw_screen(wp);
1815: }