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