Annotation of src/usr.bin/tmux/window-copy.c, Revision 1.60
1.60 ! tedu 1: /* $OpenBSD: window-copy.c,v 1.59 2010/06/06 19:00:13 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. */
1.59 nicm 370: if ((key & KEYC_MASK_MOD) == 0) {
1.52 nicm 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:
1.59 nicm 630: key &= KEYC_MASK_KEY;
1.50 nicm 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:
1.59 nicm 744: key &= KEYC_MASK_KEY;
1.50 nicm 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;
1.57 nicm 763: u_int i;
764:
1.29 nicm 765: if (m->x >= screen_size_x(s))
1.1 nicm 766: return;
1.29 nicm 767: if (m->y >= screen_size_y(s))
1.1 nicm 768: return;
769:
1.57 nicm 770: /* If mouse wheel (buttons 4 and 5), scroll. */
1.60 ! tedu 771: if ((m->b & MOUSE_45)) {
! 772: if ((m->b & MOUSE_BUTTON) == MOUSE_1) {
1.57 nicm 773: for (i = 0; i < 5; i++)
774: window_copy_cursor_up(wp, 0);
1.60 ! tedu 775: } else if ((m->b & MOUSE_BUTTON) == MOUSE_2) {
1.57 nicm 776: for (i = 0; i < 5; i++)
777: window_copy_cursor_down(wp, 0);
778: }
779: return;
780: }
781:
782: /*
783: * If already reading motion, move the cursor while buttons are still
784: * pressed, or stop the selection on their release.
785: */
786: if (s->mode & MODE_MOUSEMOTION) {
1.60 ! tedu 787: if ((m->b & MOUSE_BUTTON) != MOUSE_UP) {
1.57 nicm 788: window_copy_update_cursor(wp, m->x, m->y);
789: if (window_copy_update_selection(wp))
790: window_copy_redraw_screen(wp);
791: } else {
792: s->mode &= ~MODE_MOUSEMOTION;
793: if (sess != NULL) {
794: window_copy_copy_selection(wp, sess);
795: window_pane_reset_mode(wp);
796: }
797: }
798: return;
799: }
800:
801: /* Otherwise i other buttons pressed, start selection and motion. */
1.60 ! tedu 802: if ((m->b & MOUSE_BUTTON) != MOUSE_UP) {
1.57 nicm 803: s->mode |= MODE_MOUSEMOTION;
804:
805: window_copy_update_cursor(wp, m->x, m->y);
806: window_copy_start_selection(wp);
1.35 nicm 807: window_copy_redraw_screen(wp);
1.57 nicm 808: }
1.1 nicm 809: }
810:
811: void
1.21 nicm 812: window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py)
813: {
814: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 815: struct grid *gd = data->backing->grid;
1.21 nicm 816: u_int offset, gap;
817:
818: data->cx = px;
819:
820: gap = gd->sy / 4;
821: if (py < gd->sy) {
822: offset = 0;
823: data->cy = py;
824: } else if (py > gd->hsize + gd->sy - gap) {
825: offset = gd->hsize;
826: data->cy = py - gd->hsize;
827: } else {
828: offset = py + gap - gd->sy;
829: data->cy = py - offset;
830: }
1.35 nicm 831: data->oy = gd->hsize - offset;
1.21 nicm 832:
1.38 nicm 833: window_copy_update_selection(wp);
1.21 nicm 834: window_copy_redraw_screen(wp);
835: }
836:
837: int
838: window_copy_search_compare(
839: struct grid *gd, u_int px, u_int py, struct grid *sgd, u_int spx)
840: {
841: const struct grid_cell *gc, *sgc;
842: const struct grid_utf8 *gu, *sgu;
843:
844: gc = grid_peek_cell(gd, px, py);
845: sgc = grid_peek_cell(sgd, spx, 0);
1.35 nicm 846:
1.21 nicm 847: if ((gc->flags & GRID_FLAG_UTF8) != (sgc->flags & GRID_FLAG_UTF8))
848: return (0);
849:
850: if (gc->flags & GRID_FLAG_UTF8) {
851: gu = grid_peek_utf8(gd, px, py);
852: sgu = grid_peek_utf8(sgd, spx, 0);
1.32 nicm 853: if (grid_utf8_compare(gu, sgu))
1.21 nicm 854: return (1);
855: } else {
856: if (gc->data == sgc->data)
857: return (1);
858: }
859: return (0);
860: }
861:
862: int
863: window_copy_search_lr(struct grid *gd,
864: struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last)
865: {
866: u_int ax, bx, px;
867:
868: for (ax = first; ax < last; ax++) {
869: if (ax + sgd->sx >= gd->sx)
870: break;
871: for (bx = 0; bx < sgd->sx; bx++) {
872: px = ax + bx;
873: if (!window_copy_search_compare(gd, px, py, sgd, bx))
874: break;
875: }
876: if (bx == sgd->sx) {
877: *ppx = ax;
878: return (1);
879: }
880: }
881: return (0);
882: }
883:
884: int
885: window_copy_search_rl(struct grid *gd,
886: struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last)
887: {
888: u_int ax, bx, px;
889:
890: for (ax = last + 1; ax > first; ax--) {
1.24 nicm 891: if (gd->sx - (ax - 1) < sgd->sx)
892: continue;
1.21 nicm 893: for (bx = 0; bx < sgd->sx; bx++) {
894: px = ax - 1 + bx;
895: if (!window_copy_search_compare(gd, px, py, sgd, bx))
896: break;
897: }
898: if (bx == sgd->sx) {
899: *ppx = ax - 1;
900: return (1);
901: }
902: }
903: return (0);
904: }
905:
906: void
907: window_copy_search_up(struct window_pane *wp, const char *searchstr)
908: {
909: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 910: struct screen *s = data->backing, ss;
1.21 nicm 911: struct screen_write_ctx ctx;
912: struct grid *gd = s->grid, *sgd;
913: struct grid_cell gc;
914: size_t searchlen;
915: u_int i, last, fx, fy, px;
916: int utf8flag, n, wrapped;
917:
918: if (*searchstr == '\0')
919: return;
920: utf8flag = options_get_number(&wp->window->options, "utf8");
921: searchlen = screen_write_strlen(utf8flag, "%s", searchstr);
922:
923: screen_init(&ss, searchlen, 1, 0);
924: screen_write_start(&ctx, NULL, &ss);
925: memcpy(&gc, &grid_default_cell, sizeof gc);
926: screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr);
927: screen_write_stop(&ctx);
928:
929: fx = data->cx;
930: fy = gd->hsize - data->oy + data->cy;
931:
932: if (fx == 0) {
933: if (fy == 0)
934: return;
935: fx = gd->sx - 1;
936: fy--;
937: } else
938: fx--;
939: n = wrapped = 0;
940:
941: retry:
942: sgd = ss.grid;
943: for (i = fy + 1; i > 0; i--) {
944: last = screen_size_x(s);
945: if (i == fy + 1)
946: last = fx;
947: n = window_copy_search_rl(gd, sgd, &px, i - 1, 0, last);
948: if (n) {
949: window_copy_scroll_to(wp, px, i - 1);
950: break;
951: }
952: }
953: if (!n && !wrapped) {
954: fx = gd->sx - 1;
955: fy = gd->hsize + gd->sy - 1;
956: wrapped = 1;
957: goto retry;
958: }
959:
960: screen_free(&ss);
961: }
962:
963: void
964: window_copy_search_down(struct window_pane *wp, const char *searchstr)
965: {
966: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 967: struct screen *s = data->backing, ss;
1.21 nicm 968: struct screen_write_ctx ctx;
969: struct grid *gd = s->grid, *sgd;
970: struct grid_cell gc;
971: size_t searchlen;
972: u_int i, first, fx, fy, px;
973: int utf8flag, n, wrapped;
974:
975: if (*searchstr == '\0')
976: return;
977: utf8flag = options_get_number(&wp->window->options, "utf8");
978: searchlen = screen_write_strlen(utf8flag, "%s", searchstr);
979:
980: screen_init(&ss, searchlen, 1, 0);
981: screen_write_start(&ctx, NULL, &ss);
982: memcpy(&gc, &grid_default_cell, sizeof gc);
983: screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr);
984: screen_write_stop(&ctx);
985:
986: fx = data->cx;
987: fy = gd->hsize - data->oy + data->cy;
988:
989: if (fx == gd->sx - 1) {
990: if (fy == gd->hsize + gd->sy)
991: return;
992: fx = 0;
993: fy++;
994: } else
995: fx++;
996: n = wrapped = 0;
997:
998: retry:
999: sgd = ss.grid;
1000: for (i = fy + 1; i < gd->hsize + gd->sy; i++) {
1001: first = 0;
1002: if (i == fy + 1)
1003: first = fx;
1004: n = window_copy_search_lr(gd, sgd, &px, i - 1, first, gd->sx);
1005: if (n) {
1006: window_copy_scroll_to(wp, px, i - 1);
1007: break;
1008: }
1009: }
1010: if (!n && !wrapped) {
1011: fx = 0;
1012: fy = 0;
1013: wrapped = 1;
1014: goto retry;
1015: }
1016:
1017: screen_free(&ss);
1018: }
1019:
1020: void
1021: window_copy_goto_line(struct window_pane *wp, const char *linestr)
1022: {
1023: struct window_copy_mode_data *data = wp->modedata;
1024: const char *errstr;
1025: u_int lineno;
1026:
1.54 nicm 1027: lineno = strtonum(linestr, 0, screen_hsize(data->backing), &errstr);
1.21 nicm 1028: if (errstr != NULL)
1029: return;
1.35 nicm 1030:
1.21 nicm 1031: data->oy = lineno;
1.38 nicm 1032: window_copy_update_selection(wp);
1.21 nicm 1033: window_copy_redraw_screen(wp);
1034: }
1035:
1036: void
1.18 nicm 1037: window_copy_write_line(
1038: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
1.1 nicm 1039: {
1040: struct window_copy_mode_data *data = wp->modedata;
1041: struct screen *s = &data->screen;
1.27 nicm 1042: struct options *oo = &wp->window->options;
1.1 nicm 1043: struct grid_cell gc;
1044: char hdr[32];
1.21 nicm 1045: size_t last, xoff = 0, size = 0;
1046:
1047: memcpy(&gc, &grid_default_cell, sizeof gc);
1.27 nicm 1048: colour_set_fg(&gc, options_get_number(oo, "mode-fg"));
1049: colour_set_bg(&gc, options_get_number(oo, "mode-bg"));
1050: gc.attr |= options_get_number(oo, "mode-attr");
1.1 nicm 1051:
1.21 nicm 1052: last = screen_size_y(s) - 1;
1.1 nicm 1053: if (py == 0) {
1054: size = xsnprintf(hdr, sizeof hdr,
1.54 nicm 1055: "[%u/%u]", data->oy, screen_hsize(data->backing));
1.1 nicm 1056: screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
1057: screen_write_puts(ctx, &gc, "%s", hdr);
1.21 nicm 1058: } else if (py == last && data->inputtype != WINDOW_COPY_OFF) {
1.50 nicm 1059: if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) {
1060: xoff = size = xsnprintf(hdr, sizeof hdr,
1061: "Repeat: %u", data->numprefix);
1062: } else {
1063: xoff = size = xsnprintf(hdr, sizeof hdr,
1064: "%s: %s", data->inputprompt, data->inputstr);
1065: }
1.21 nicm 1066: screen_write_cursormove(ctx, 0, last);
1067: screen_write_puts(ctx, &gc, "%s", hdr);
1.1 nicm 1068: } else
1069: size = 0;
1070:
1.21 nicm 1071: screen_write_cursormove(ctx, xoff, py);
1.54 nicm 1072: screen_write_copy(ctx, data->backing, xoff,
1073: (screen_hsize(data->backing) - data->oy) + py,
1074: screen_size_x(s) - size, 1);
1.18 nicm 1075:
1076: if (py == data->cy && data->cx == screen_size_x(s)) {
1077: memcpy(&gc, &grid_default_cell, sizeof gc);
1078: screen_write_cursormove(ctx, screen_size_x(s) - 1, py);
1079: screen_write_putc(ctx, &gc, '$');
1080: }
1.1 nicm 1081: }
1082:
1083: void
1084: window_copy_write_lines(
1085: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py, u_int ny)
1086: {
1087: u_int yy;
1088:
1089: for (yy = py; yy < py + ny; yy++)
1090: window_copy_write_line(wp, ctx, py);
1091: }
1092:
1093: void
1094: window_copy_redraw_lines(struct window_pane *wp, u_int py, u_int ny)
1095: {
1096: struct window_copy_mode_data *data = wp->modedata;
1097: struct screen_write_ctx ctx;
1098: u_int i;
1099:
1100: screen_write_start(&ctx, wp, NULL);
1101: for (i = py; i < py + ny; i++)
1102: window_copy_write_line(wp, &ctx, i);
1103: screen_write_cursormove(&ctx, data->cx, data->cy);
1104: screen_write_stop(&ctx);
1105: }
1106:
1107: void
1108: window_copy_redraw_screen(struct window_pane *wp)
1109: {
1110: struct window_copy_mode_data *data = wp->modedata;
1111:
1112: window_copy_redraw_lines(wp, 0, screen_size_y(&data->screen));
1113: }
1114:
1115: void
1.18 nicm 1116: window_copy_update_cursor(struct window_pane *wp, u_int cx, u_int cy)
1.1 nicm 1117: {
1118: struct window_copy_mode_data *data = wp->modedata;
1.18 nicm 1119: struct screen *s = &data->screen;
1.1 nicm 1120: struct screen_write_ctx ctx;
1.18 nicm 1121: u_int old_cx, old_cy;
1.1 nicm 1122:
1.18 nicm 1123: old_cx = data->cx; old_cy = data->cy;
1124: data->cx = cx; data->cy = cy;
1125: if (old_cx == screen_size_x(s))
1126: window_copy_redraw_lines(wp, old_cy, 1);
1127: if (data->cx == screen_size_x(s))
1128: window_copy_redraw_lines(wp, data->cy, 1);
1129: else {
1130: screen_write_start(&ctx, wp, NULL);
1131: screen_write_cursormove(&ctx, data->cx, data->cy);
1132: screen_write_stop(&ctx);
1133: }
1.1 nicm 1134: }
1135:
1136: void
1137: window_copy_start_selection(struct window_pane *wp)
1138: {
1139: struct window_copy_mode_data *data = wp->modedata;
1140: struct screen *s = &data->screen;
1141:
1.18 nicm 1142: data->selx = data->cx;
1.54 nicm 1143: data->sely = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 1144:
1145: s->sel.flag = 1;
1146: window_copy_update_selection(wp);
1147: }
1148:
1149: int
1150: window_copy_update_selection(struct window_pane *wp)
1151: {
1152: struct window_copy_mode_data *data = wp->modedata;
1153: struct screen *s = &data->screen;
1.27 nicm 1154: struct options *oo = &wp->window->options;
1.1 nicm 1155: struct grid_cell gc;
1.42 nicm 1156: u_int sx, sy, ty, cy;
1.1 nicm 1157:
1158: if (!s->sel.flag)
1159: return (0);
1160:
1161: /* Set colours. */
1162: memcpy(&gc, &grid_default_cell, sizeof gc);
1.27 nicm 1163: colour_set_fg(&gc, options_get_number(oo, "mode-fg"));
1164: colour_set_bg(&gc, options_get_number(oo, "mode-bg"));
1165: gc.attr |= options_get_number(oo, "mode-attr");
1.1 nicm 1166:
1.18 nicm 1167: /* Find top of screen. */
1.54 nicm 1168: ty = screen_hsize(data->backing) - data->oy;
1.1 nicm 1169:
1170: /* Adjust the selection. */
1171: sx = data->selx;
1172: sy = data->sely;
1.18 nicm 1173: if (sy < ty) { /* above screen */
1.42 nicm 1174: if (!data->rectflag)
1175: sx = 0;
1.1 nicm 1176: sy = 0;
1.18 nicm 1177: } else if (sy > ty + screen_size_y(s) - 1) { /* below screen */
1.42 nicm 1178: if (!data->rectflag)
1179: sx = screen_size_x(s) - 1;
1.1 nicm 1180: sy = screen_size_y(s) - 1;
1.18 nicm 1181: } else
1.1 nicm 1182: sy -= ty;
1183: sy = screen_hsize(s) + sy;
1184:
1.42 nicm 1185: screen_set_selection(s,
1186: sx, sy, data->cx, screen_hsize(s) + data->cy, data->rectflag, &gc);
1187:
1188: if (data->rectflag) {
1189: /*
1190: * Can't rely on the caller to redraw the right lines for
1191: * rectangle selection - find the highest line and the number
1192: * of lines, and redraw just past that in both directions
1193: */
1194: cy = data->cy;
1195: if (sy < cy)
1196: window_copy_redraw_lines(wp, sy, cy - sy + 1);
1197: else
1198: window_copy_redraw_lines(wp, cy, sy - cy + 1);
1199: }
1200:
1.1 nicm 1201: return (1);
1202: }
1203:
1204: void
1.56 nicm 1205: window_copy_copy_selection(struct window_pane *wp, struct session *sess)
1.1 nicm 1206: {
1207: struct window_copy_mode_data *data = wp->modedata;
1208: struct screen *s = &data->screen;
1209: char *buf;
1.42 nicm 1210: size_t off;
1211: u_int i, xx, yy, sx, sy, ex, ey, limit;
1212: u_int firstsx, lastex, restex, restsx;
1.1 nicm 1213:
1214: if (!s->sel.flag)
1215: return;
1216:
1217: buf = xmalloc(1);
1218: off = 0;
1219:
1220: *buf = '\0';
1221:
1222: /*
1223: * The selection extends from selx,sely to (adjusted) cx,cy on
1224: * the base screen.
1225: */
1226:
1227: /* Find start and end. */
1.18 nicm 1228: xx = data->cx;
1.54 nicm 1229: yy = screen_hsize(data->backing) + data->cy - data->oy;
1.2 nicm 1230: if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
1.1 nicm 1231: sx = xx; sy = yy;
1232: ex = data->selx; ey = data->sely;
1233: } else {
1234: sx = data->selx; sy = data->sely;
1235: ex = xx; ey = yy;
1236: }
1237:
1238: /* Trim ex to end of line. */
1239: xx = window_copy_find_length(wp, ey);
1240: if (ex > xx)
1241: ex = xx;
1242:
1.42 nicm 1243: /*
1244: * Deal with rectangle-copy if necessary; four situations: start of
1245: * first line (firstsx), end of last line (lastex), start (restsx) and
1246: * end (restex) of all other lines.
1247: */
1248: xx = screen_size_x(s);
1249: if (data->rectflag) {
1250: /*
1251: * Need to ignore the column with the cursor in it, which for
1252: * rectangular copy means knowing which side the cursor is on.
1253: */
1254: if (data->selx < data->cx) {
1255: /* Selection start is on the left. */
1256: lastex = data->cx;
1257: restex = data->cx;
1258: firstsx = data->selx;
1259: restsx = data->selx;
1260: } else {
1261: /* Cursor is on the left. */
1262: lastex = data->selx + 1;
1263: restex = data->selx + 1;
1264: firstsx = data->cx + 1;
1265: restsx = data->cx + 1;
1266: }
1267: } else {
1268: /*
1269: * Like emacs, keep the top-left-most character, and drop the
1270: * bottom-right-most, regardless of copy direction.
1271: */
1272: lastex = ex;
1273: restex = xx;
1274: firstsx = sx;
1275: restsx = 0;
1276: }
1277:
1.1 nicm 1278: /* Copy the lines. */
1279: if (sy == ey)
1.42 nicm 1280: window_copy_copy_line(wp, &buf, &off, sy, firstsx, lastex);
1.1 nicm 1281: else {
1.42 nicm 1282: window_copy_copy_line(wp, &buf, &off, sy, firstsx, restex);
1.1 nicm 1283: if (ey - sy > 1) {
1.42 nicm 1284: for (i = sy + 1; i < ey; i++) {
1285: window_copy_copy_line(
1286: wp, &buf, &off, i, restsx, restex);
1287: }
1.1 nicm 1288: }
1.42 nicm 1289: window_copy_copy_line(wp, &buf, &off, ey, restsx, lastex);
1.1 nicm 1290: }
1291:
1.26 nicm 1292: /* Don't bother if no data. */
1293: if (off == 0) {
1294: xfree(buf);
1295: return;
1296: }
1297: off--; /* remove final \n */
1.1 nicm 1298:
1299: /* Add the buffer to the stack. */
1.56 nicm 1300: limit = options_get_number(&sess->options, "buffer-limit");
1301: paste_add(&sess->buffers, buf, off, limit);
1.1 nicm 1302: }
1303:
1304: void
1305: window_copy_copy_line(struct window_pane *wp,
1306: char **buf, size_t *off, u_int sy, u_int sx, u_int ex)
1307: {
1.54 nicm 1308: struct window_copy_mode_data *data = wp->modedata;
1309: struct grid *gd = data->backing->grid;
1310: const struct grid_cell *gc;
1311: const struct grid_utf8 *gu;
1312: struct grid_line *gl;
1313: u_int i, xx, wrapped = 0;
1314: size_t size;
1.1 nicm 1315:
1316: if (sx > ex)
1317: return;
1318:
1.16 nicm 1319: /*
1320: * Work out if the line was wrapped at the screen edge and all of it is
1321: * on screen.
1322: */
1323: gl = &gd->linedata[sy];
1.35 nicm 1324: if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
1.16 nicm 1325: wrapped = 1;
1326:
1327: /* If the line was wrapped, don't strip spaces (use the full length). */
1328: if (wrapped)
1329: xx = gl->cellsize;
1330: else
1331: xx = window_copy_find_length(wp, sy);
1.1 nicm 1332: if (ex > xx)
1333: ex = xx;
1334: if (sx > xx)
1335: sx = xx;
1336:
1337: if (sx < ex) {
1338: for (i = sx; i < ex; i++) {
1.16 nicm 1339: gc = grid_peek_cell(gd, i, sy);
1.1 nicm 1340: if (gc->flags & GRID_FLAG_PADDING)
1341: continue;
1342: if (!(gc->flags & GRID_FLAG_UTF8)) {
1343: *buf = xrealloc(*buf, 1, (*off) + 1);
1344: (*buf)[(*off)++] = gc->data;
1345: } else {
1.16 nicm 1346: gu = grid_peek_utf8(gd, i, sy);
1.32 nicm 1347: size = grid_utf8_size(gu);
1348: *buf = xrealloc(*buf, 1, (*off) + size);
1349: *off += grid_utf8_copy(gu, *buf + *off, size);
1.1 nicm 1350: }
1351: }
1352: }
1353:
1.16 nicm 1354: /* Only add a newline if the line wasn't wrapped. */
1.44 nicm 1355: if (!wrapped || ex != xx) {
1.16 nicm 1356: *buf = xrealloc(*buf, 1, (*off) + 1);
1357: (*buf)[(*off)++] = '\n';
1358: }
1.1 nicm 1359: }
1360:
1.47 nicm 1361: void
1362: window_copy_clear_selection(struct window_pane *wp)
1363: {
1364: struct window_copy_mode_data *data = wp->modedata;
1365: u_int px, py;
1366:
1367: screen_clear_selection(&data->screen);
1368:
1.54 nicm 1369: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 1370: px = window_copy_find_length(wp, py);
1371: if (data->cx > px)
1372: window_copy_update_cursor(wp, px, data->cy);
1373: }
1374:
1.1 nicm 1375: int
1.41 nicm 1376: window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set)
1.1 nicm 1377: {
1.54 nicm 1378: struct window_copy_mode_data *data = wp->modedata;
1379: const struct grid_cell *gc;
1.1 nicm 1380:
1.54 nicm 1381: gc = grid_peek_cell(data->backing->grid, px, py);
1.1 nicm 1382: if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8))
1383: return (0);
1384: if (gc->data == 0x00 || gc->data == 0x7f)
1385: return (0);
1.41 nicm 1386: return (strchr(set, gc->data) != NULL);
1.1 nicm 1387: }
1388:
1389: u_int
1390: window_copy_find_length(struct window_pane *wp, u_int py)
1391: {
1.54 nicm 1392: struct window_copy_mode_data *data = wp->modedata;
1393: struct screen *s = data->backing;
1394: const struct grid_cell *gc;
1395: u_int px;
1.1 nicm 1396:
1.4 nicm 1397: /*
1398: * If the pane has been resized, its grid can contain old overlong
1399: * lines. grid_peek_cell does not allow accessing cells beyond the
1400: * width of the grid, and screen_write_copy treats them as spaces, so
1401: * ignore them here too.
1402: */
1.54 nicm 1403: px = s->grid->linedata[py].cellsize;
1404: if (px > screen_size_x(s))
1405: px = screen_size_x(s);
1.1 nicm 1406: while (px > 0) {
1.54 nicm 1407: gc = grid_peek_cell(s->grid, px - 1, py);
1.1 nicm 1408: if (gc->flags & GRID_FLAG_UTF8)
1409: break;
1410: if (gc->data != ' ')
1411: break;
1412: px--;
1413: }
1414: return (px);
1415: }
1416:
1417: void
1.5 nicm 1418: window_copy_cursor_start_of_line(struct window_pane *wp)
1419: {
1420: struct window_copy_mode_data *data = wp->modedata;
1.58 nicm 1421: struct screen *back_s = data->backing;
1422: struct grid *gd = back_s->grid;
1423: u_int py;
1424:
1425: if (data->cx == 0) {
1426: py = screen_hsize(back_s) + data->cy - data->oy;
1427: while (py > 0 && gd->linedata[py-1].flags & GRID_LINE_WRAPPED) {
1428: window_copy_cursor_up(wp, 0);
1429: py = screen_hsize(back_s) + data->cy - data->oy;
1430: }
1431: }
1.18 nicm 1432: window_copy_update_cursor(wp, 0, data->cy);
1.5 nicm 1433: if (window_copy_update_selection(wp))
1434: window_copy_redraw_lines(wp, data->cy, 1);
1.6 nicm 1435: }
1436:
1437: void
1438: window_copy_cursor_back_to_indentation(struct window_pane *wp)
1439: {
1440: struct window_copy_mode_data *data = wp->modedata;
1441: u_int px, py, xx;
1442: const struct grid_cell *gc;
1443:
1444: px = 0;
1.54 nicm 1445: py = screen_hsize(data->backing) + data->cy - data->oy;
1.6 nicm 1446: xx = window_copy_find_length(wp, py);
1447:
1448: while (px < xx) {
1.54 nicm 1449: gc = grid_peek_cell(data->backing->grid, px, py);
1.6 nicm 1450: if (gc->flags & GRID_FLAG_UTF8)
1451: break;
1452: if (gc->data != ' ')
1453: break;
1454: px++;
1455: }
1456:
1.18 nicm 1457: window_copy_update_cursor(wp, px, data->cy);
1458: if (window_copy_update_selection(wp))
1459: window_copy_redraw_lines(wp, data->cy, 1);
1.5 nicm 1460: }
1461:
1462: void
1463: window_copy_cursor_end_of_line(struct window_pane *wp)
1464: {
1465: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1466: struct screen *back_s = data->backing;
1467: struct grid *gd = back_s->grid;
1.5 nicm 1468: u_int px, py;
1469:
1.54 nicm 1470: py = screen_hsize(back_s) + data->cy - data->oy;
1.5 nicm 1471: px = window_copy_find_length(wp, py);
1472:
1.49 nicm 1473: if (data->cx == px) {
1474: if (data->screen.sel.flag && data->rectflag)
1.54 nicm 1475: px = screen_size_x(back_s);
1.49 nicm 1476: if (gd->linedata[py].flags & GRID_LINE_WRAPPED) {
1477: while (py < gd->sy + gd->hsize &&
1478: gd->linedata[py].flags & GRID_LINE_WRAPPED) {
1479: window_copy_cursor_down(wp, 0);
1.54 nicm 1480: py = screen_hsize(back_s)
1481: + data->cy - data->oy;
1.49 nicm 1482: }
1483: px = window_copy_find_length(wp, py);
1484: }
1485: }
1.18 nicm 1486: window_copy_update_cursor(wp, px, data->cy);
1.49 nicm 1487:
1.18 nicm 1488: if (window_copy_update_selection(wp))
1489: window_copy_redraw_lines(wp, data->cy, 1);
1.5 nicm 1490: }
1491:
1492: void
1.1 nicm 1493: window_copy_cursor_left(struct window_pane *wp)
1494: {
1495: struct window_copy_mode_data *data = wp->modedata;
1496:
1497: if (data->cx == 0) {
1.28 nicm 1498: window_copy_cursor_up(wp, 0);
1.18 nicm 1499: window_copy_cursor_end_of_line(wp);
1.1 nicm 1500: } else {
1.18 nicm 1501: window_copy_update_cursor(wp, data->cx - 1, data->cy);
1.1 nicm 1502: if (window_copy_update_selection(wp))
1503: window_copy_redraw_lines(wp, data->cy, 1);
1504: }
1505: }
1506:
1507: void
1508: window_copy_cursor_right(struct window_pane *wp)
1509: {
1510: struct window_copy_mode_data *data = wp->modedata;
1511: u_int px, py;
1512:
1.47 nicm 1513: if (data->screen.sel.flag && data->rectflag)
1514: px = screen_size_x(&data->screen);
1515: else {
1.54 nicm 1516: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 1517: px = window_copy_find_length(wp, py);
1518: }
1.1 nicm 1519:
1520: if (data->cx >= px) {
1521: window_copy_cursor_start_of_line(wp);
1.28 nicm 1522: window_copy_cursor_down(wp, 0);
1.1 nicm 1523: } else {
1.18 nicm 1524: window_copy_update_cursor(wp, data->cx + 1, data->cy);
1.1 nicm 1525: if (window_copy_update_selection(wp))
1526: window_copy_redraw_lines(wp, data->cy, 1);
1527: }
1528: }
1529:
1530: void
1.28 nicm 1531: window_copy_cursor_up(struct window_pane *wp, int scroll_only)
1.1 nicm 1532: {
1533: struct window_copy_mode_data *data = wp->modedata;
1.36 nicm 1534: struct screen *s = &data->screen;
1.1 nicm 1535: u_int ox, oy, px, py;
1536:
1.54 nicm 1537: oy = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 1538: ox = window_copy_find_length(wp, oy);
1.25 nicm 1539: if (ox != 0) {
1540: data->lastcx = data->cx;
1541: data->lastsx = ox;
1542: }
1.1 nicm 1543:
1.25 nicm 1544: data->cx = data->lastcx;
1.28 nicm 1545: if (scroll_only || data->cy == 0) {
1.1 nicm 1546: window_copy_scroll_down(wp, 1);
1.36 nicm 1547: if (scroll_only) {
1548: if (data->cy == screen_size_y(s) - 1)
1549: window_copy_redraw_lines(wp, data->cy, 1);
1550: else
1551: window_copy_redraw_lines(wp, data->cy, 2);
1552: }
1.28 nicm 1553: } else {
1.18 nicm 1554: window_copy_update_cursor(wp, data->cx, data->cy - 1);
1.36 nicm 1555: if (window_copy_update_selection(wp)) {
1556: if (data->cy == screen_size_y(s) - 1)
1557: window_copy_redraw_lines(wp, data->cy, 1);
1558: else
1559: window_copy_redraw_lines(wp, data->cy, 2);
1560: }
1.1 nicm 1561: }
1562:
1.47 nicm 1563: if (!data->screen.sel.flag || !data->rectflag) {
1.54 nicm 1564: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 1565: px = window_copy_find_length(wp, py);
1.49 nicm 1566: if ((data->cx >= data->lastsx && data->cx != px) ||
1567: data->cx > px)
1.47 nicm 1568: window_copy_cursor_end_of_line(wp);
1569: }
1.1 nicm 1570: }
1571:
1572: void
1.28 nicm 1573: window_copy_cursor_down(struct window_pane *wp, int scroll_only)
1.1 nicm 1574: {
1575: struct window_copy_mode_data *data = wp->modedata;
1576: struct screen *s = &data->screen;
1577: u_int ox, oy, px, py;
1578:
1.54 nicm 1579: oy = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 1580: ox = window_copy_find_length(wp, oy);
1.25 nicm 1581: if (ox != 0) {
1582: data->lastcx = data->cx;
1583: data->lastsx = ox;
1584: }
1.1 nicm 1585:
1.25 nicm 1586: data->cx = data->lastcx;
1.28 nicm 1587: if (scroll_only || data->cy == screen_size_y(s) - 1) {
1.1 nicm 1588: window_copy_scroll_up(wp, 1);
1.31 nicm 1589: if (scroll_only && data->cy > 0)
1.28 nicm 1590: window_copy_redraw_lines(wp, data->cy - 1, 2);
1591: } else {
1.18 nicm 1592: window_copy_update_cursor(wp, data->cx, data->cy + 1);
1.1 nicm 1593: if (window_copy_update_selection(wp))
1594: window_copy_redraw_lines(wp, data->cy - 1, 2);
1595: }
1596:
1.47 nicm 1597: if (!data->screen.sel.flag || !data->rectflag) {
1.54 nicm 1598: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 1599: px = window_copy_find_length(wp, py);
1.49 nicm 1600: if ((data->cx >= data->lastsx && data->cx != px) ||
1601: data->cx > px)
1.47 nicm 1602: window_copy_cursor_end_of_line(wp);
1.52 nicm 1603: }
1604: }
1605:
1606: void
1607: window_copy_cursor_jump(struct window_pane *wp)
1608: {
1609: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1610: struct screen *back_s = data->backing;
1.52 nicm 1611: const struct grid_cell *gc;
1612: uint px, py, xx;
1613:
1614: px = data->cx + 1;
1.54 nicm 1615: py = screen_hsize(back_s) + data->cy - data->oy;
1.52 nicm 1616: xx = window_copy_find_length(wp, py);
1617:
1618: while (px < xx) {
1.54 nicm 1619: gc = grid_peek_cell(back_s->grid, px, py);
1.52 nicm 1620: if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
1621: && gc->data == data->jumpchar) {
1622:
1623: window_copy_update_cursor(wp, px, data->cy);
1624: if (window_copy_update_selection(wp))
1625: window_copy_redraw_lines(wp, data->cy, 1);
1626: return;
1627: }
1628: px++;
1629: }
1630: }
1631:
1632: void
1633: window_copy_cursor_jump_back(struct window_pane *wp)
1634: {
1635: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1636: struct screen *back_s = data->backing;
1.52 nicm 1637: const struct grid_cell *gc;
1638: uint px, py;
1639:
1640: px = data->cx;
1.54 nicm 1641: py = screen_hsize(back_s) + data->cy - data->oy;
1.52 nicm 1642:
1643: if (px > 0)
1644: px--;
1645:
1646: for (;;) {
1.54 nicm 1647: gc = grid_peek_cell(back_s->grid, px, py);
1.52 nicm 1648: if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
1649: && gc->data == data->jumpchar) {
1650:
1651: window_copy_update_cursor(wp, px, data->cy);
1652: if (window_copy_update_selection(wp))
1653: window_copy_redraw_lines(wp, data->cy, 1);
1654: return;
1655: }
1656: if (px == 0)
1657: break;
1658: px--;
1.47 nicm 1659: }
1.1 nicm 1660: }
1661:
1662: void
1.41 nicm 1663: window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
1.40 nicm 1664: {
1665: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1666: struct screen *back_s = data->backing;
1.40 nicm 1667: u_int px, py, xx, yy;
1.48 nicm 1668: int expected = 0;
1.40 nicm 1669:
1670: px = data->cx;
1.54 nicm 1671: py = screen_hsize(back_s) + data->cy - data->oy;
1.40 nicm 1672: xx = window_copy_find_length(wp, py);
1.54 nicm 1673: yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
1.40 nicm 1674:
1.48 nicm 1675: /*
1676: * First skip past any nonword characters and then any word characters.
1677: *
1678: * expected is initially set to 0 for the former and then 1 for the
1679: * latter.
1680: */
1681: do {
1682: while (px > xx ||
1683: window_copy_in_set(wp, px, py, separators) == expected) {
1684: /* Move down if we're past the end of the line. */
1685: if (px > xx) {
1686: if (py == yy)
1687: return;
1688: window_copy_cursor_down(wp, 0);
1689: px = 0;
1690:
1.54 nicm 1691: py = screen_hsize(back_s) + data->cy - data->oy;
1.48 nicm 1692: xx = window_copy_find_length(wp, py);
1693: } else
1694: px++;
1695: }
1696: expected = !expected;
1697: } while (expected == 1);
1.40 nicm 1698:
1699: window_copy_update_cursor(wp, px, data->cy);
1700: if (window_copy_update_selection(wp))
1701: window_copy_redraw_lines(wp, data->cy, 1);
1702: }
1703:
1704: void
1.41 nicm 1705: window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators)
1.1 nicm 1706: {
1707: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1708: struct screen *back_s = data->backing;
1.39 nicm 1709: u_int px, py, xx, yy;
1.48 nicm 1710: int expected = 1;
1.1 nicm 1711:
1.18 nicm 1712: px = data->cx;
1.54 nicm 1713: py = screen_hsize(back_s) + data->cy - data->oy;
1.1 nicm 1714: xx = window_copy_find_length(wp, py);
1.54 nicm 1715: yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
1.1 nicm 1716:
1.48 nicm 1717: /*
1718: * First skip past any word characters, then any nonword characters.
1719: *
1720: * expected is initially set to 1 for the former and then 0 for the
1721: * latter.
1722: */
1723: do {
1724: while (px > xx ||
1725: window_copy_in_set(wp, px, py, separators) == expected) {
1726: /* Move down if we're past the end of the line. */
1727: if (px > xx) {
1728: if (py == yy)
1729: return;
1730: window_copy_cursor_down(wp, 0);
1731: px = 0;
1732:
1.54 nicm 1733: py = screen_hsize(back_s) + data->cy - data->oy;
1.48 nicm 1734: xx = window_copy_find_length(wp, py);
1735: } else
1736: px++;
1737: }
1738: expected = !expected;
1739: } while (expected == 0);
1.18 nicm 1740:
1741: window_copy_update_cursor(wp, px, data->cy);
1742: if (window_copy_update_selection(wp))
1743: window_copy_redraw_lines(wp, data->cy, 1);
1.1 nicm 1744: }
1745:
1.8 nicm 1746: /* Move to the previous place where a word begins. */
1.1 nicm 1747: void
1.41 nicm 1748: window_copy_cursor_previous_word(struct window_pane *wp, const char *separators)
1.1 nicm 1749: {
1750: struct window_copy_mode_data *data = wp->modedata;
1.8 nicm 1751: u_int px, py;
1.1 nicm 1752:
1.18 nicm 1753: px = data->cx;
1.54 nicm 1754: py = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 1755:
1.8 nicm 1756: /* Move back to the previous word character. */
1.1 nicm 1757: for (;;) {
1.8 nicm 1758: if (px > 0) {
1759: px--;
1.41 nicm 1760: if (!window_copy_in_set(wp, px, py, separators))
1.1 nicm 1761: break;
1.8 nicm 1762: } else {
1763: if (data->cy == 0 &&
1.54 nicm 1764: (screen_hsize(data->backing) == 0 ||
1765: data->oy >= screen_hsize(data->backing) - 1))
1.8 nicm 1766: goto out;
1.28 nicm 1767: window_copy_cursor_up(wp, 0);
1.1 nicm 1768:
1.54 nicm 1769: py = screen_hsize(data->backing) + data->cy - data->oy;
1.8 nicm 1770: px = window_copy_find_length(wp, py);
1.1 nicm 1771: }
1.8 nicm 1772: }
1.1 nicm 1773:
1.8 nicm 1774: /* Move back to the beginning of this word. */
1.41 nicm 1775: while (px > 0 && !window_copy_in_set(wp, px - 1, py, separators))
1.1 nicm 1776: px--;
1.8 nicm 1777:
1.1 nicm 1778: out:
1.18 nicm 1779: window_copy_update_cursor(wp, px, data->cy);
1780: if (window_copy_update_selection(wp))
1781: window_copy_redraw_lines(wp, data->cy, 1);
1.1 nicm 1782: }
1783:
1784: void
1785: window_copy_scroll_up(struct window_pane *wp, u_int ny)
1786: {
1787: struct window_copy_mode_data *data = wp->modedata;
1788: struct screen *s = &data->screen;
1789: struct screen_write_ctx ctx;
1790:
1791: if (data->oy < ny)
1792: ny = data->oy;
1793: if (ny == 0)
1794: return;
1795: data->oy -= ny;
1796:
1797: screen_write_start(&ctx, wp, NULL);
1798: screen_write_cursormove(&ctx, 0, 0);
1799: screen_write_deleteline(&ctx, ny);
1800: window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, ny);
1801: window_copy_write_line(wp, &ctx, 0);
1.31 nicm 1802: if (screen_size_y(s) > 1)
1803: window_copy_write_line(wp, &ctx, 1);
1804: if (screen_size_y(s) > 3)
1805: window_copy_write_line(wp, &ctx, screen_size_y(s) - 2);
1.42 nicm 1806: if (s->sel.flag && screen_size_y(s) > ny) {
1807: window_copy_update_selection(wp);
1.1 nicm 1808: window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1);
1.42 nicm 1809: }
1.1 nicm 1810: screen_write_cursormove(&ctx, data->cx, data->cy);
1.42 nicm 1811: window_copy_update_selection(wp);
1.1 nicm 1812: screen_write_stop(&ctx);
1813: }
1814:
1815: void
1816: window_copy_scroll_down(struct window_pane *wp, u_int ny)
1817: {
1818: struct window_copy_mode_data *data = wp->modedata;
1819: struct screen *s = &data->screen;
1820: struct screen_write_ctx ctx;
1821:
1.54 nicm 1822: if (ny > screen_hsize(data->backing))
1.1 nicm 1823: return;
1824:
1.54 nicm 1825: if (data->oy > screen_hsize(data->backing) - ny)
1826: ny = screen_hsize(data->backing) - data->oy;
1.1 nicm 1827: if (ny == 0)
1828: return;
1829: data->oy += ny;
1830:
1831: screen_write_start(&ctx, wp, NULL);
1832: screen_write_cursormove(&ctx, 0, 0);
1833: screen_write_insertline(&ctx, ny);
1834: window_copy_write_lines(wp, &ctx, 0, ny);
1.42 nicm 1835: if (s->sel.flag && screen_size_y(s) > ny) {
1836: window_copy_update_selection(wp);
1.1 nicm 1837: window_copy_write_line(wp, &ctx, ny);
1.42 nicm 1838: } else if (ny == 1) /* nuke position */
1.1 nicm 1839: window_copy_write_line(wp, &ctx, 1);
1840: screen_write_cursormove(&ctx, data->cx, data->cy);
1.42 nicm 1841: window_copy_update_selection(wp);
1.1 nicm 1842: screen_write_stop(&ctx);
1843: }
1.42 nicm 1844:
1845: void
1846: window_copy_rectangle_toggle(struct window_pane *wp)
1847: {
1848: struct window_copy_mode_data *data = wp->modedata;
1.47 nicm 1849: u_int px, py;
1.42 nicm 1850:
1851: data->rectflag = !data->rectflag;
1.47 nicm 1852:
1.54 nicm 1853: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 1854: px = window_copy_find_length(wp, py);
1855: if (data->cx > px)
1856: window_copy_update_cursor(wp, px, data->cy);
1.42 nicm 1857:
1858: window_copy_update_selection(wp);
1859: window_copy_redraw_screen(wp);
1860: }