Annotation of src/usr.bin/tmux/window-copy.c, Revision 1.19
1.19 ! nicm 1: /* $OpenBSD: window-copy.c,v 1.18 2009/08/13 19:35:20 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:
21: #include <string.h>
22:
23: #include "tmux.h"
24:
25: struct screen *window_copy_init(struct window_pane *);
26: void window_copy_free(struct window_pane *);
27: void window_copy_resize(struct window_pane *, u_int, u_int);
28: void window_copy_key(struct window_pane *, struct client *, int);
29: void window_copy_mouse(
30: struct window_pane *, struct client *, u_char, u_char, u_char);
31:
32: void window_copy_redraw_lines(struct window_pane *, u_int, u_int);
33: void window_copy_redraw_screen(struct window_pane *);
34: void window_copy_write_line(
35: struct window_pane *, struct screen_write_ctx *, u_int);
36: void window_copy_write_lines(
37: struct window_pane *, struct screen_write_ctx *, u_int, u_int);
38:
1.18 nicm 39: void window_copy_update_cursor(struct window_pane *, u_int, u_int);
1.1 nicm 40: void window_copy_start_selection(struct window_pane *);
41: int window_copy_update_selection(struct window_pane *);
42: void window_copy_copy_selection(struct window_pane *, struct client *);
43: void window_copy_copy_line(
44: struct window_pane *, char **, size_t *, u_int, u_int, u_int);
45: int window_copy_is_space(struct window_pane *, u_int, u_int);
46: u_int window_copy_find_length(struct window_pane *, u_int);
47: void window_copy_cursor_start_of_line(struct window_pane *);
1.6 nicm 48: void window_copy_cursor_back_to_indentation(struct window_pane *);
1.1 nicm 49: void window_copy_cursor_end_of_line(struct window_pane *);
50: void window_copy_cursor_left(struct window_pane *);
51: void window_copy_cursor_right(struct window_pane *);
52: void window_copy_cursor_up(struct window_pane *);
53: void window_copy_cursor_down(struct window_pane *);
54: void window_copy_cursor_next_word(struct window_pane *);
55: void window_copy_cursor_previous_word(struct window_pane *);
56: void window_copy_scroll_up(struct window_pane *, u_int);
57: void window_copy_scroll_down(struct window_pane *, u_int);
58:
59: const struct window_mode window_copy_mode = {
60: window_copy_init,
61: window_copy_free,
62: window_copy_resize,
63: window_copy_key,
64: window_copy_mouse,
65: NULL,
66: };
67:
68: struct window_copy_mode_data {
69: struct screen screen;
70:
71: struct mode_key_data mdata;
72:
73: u_int oy;
74:
75: u_int selx;
76: u_int sely;
77:
78: u_int cx;
79: u_int cy;
80: };
81:
82: struct screen *
83: window_copy_init(struct window_pane *wp)
84: {
85: struct window_copy_mode_data *data;
86: struct screen *s;
87: struct screen_write_ctx ctx;
88: u_int i;
1.10 nicm 89: int keys;
1.1 nicm 90:
91: wp->modedata = data = xmalloc(sizeof *data);
92: data->oy = 0;
93: data->cx = wp->base.cx;
94: data->cy = wp->base.cy;
95:
96: s = &data->screen;
97: screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
1.13 nicm 98: if (options_get_number(&wp->window->options, "mode-mouse"))
99: s->mode |= MODE_MOUSE;
1.1 nicm 100:
1.10 nicm 101: keys = options_get_number(&wp->window->options, "mode-keys");
102: if (keys == MODEKEY_EMACS)
1.12 nicm 103: mode_key_init(&data->mdata, &mode_key_tree_emacs_copy);
1.10 nicm 104: else
1.12 nicm 105: mode_key_init(&data->mdata, &mode_key_tree_vi_copy);
1.1 nicm 106:
107: s->cx = data->cx;
108: s->cy = data->cy;
109:
110: screen_write_start(&ctx, NULL, s);
111: for (i = 0; i < screen_size_y(s); i++)
112: window_copy_write_line(wp, &ctx, i);
113: screen_write_cursormove(&ctx, data->cx, data->cy);
114: screen_write_stop(&ctx);
115:
116: return (s);
117: }
118:
119: void
120: window_copy_free(struct window_pane *wp)
121: {
122: struct window_copy_mode_data *data = wp->modedata;
123:
124: screen_free(&data->screen);
125: xfree(data);
126: }
127:
128: void
129: window_copy_pageup(struct window_pane *wp)
130: {
131: struct window_copy_mode_data *data = wp->modedata;
132: struct screen *s = &data->screen;
1.19 ! nicm 133: u_int n;
1.1 nicm 134:
1.19 ! nicm 135: n = 1;
! 136: if (screen_size_y(s) > 2)
! 137: n = screen_size_y(s) - 2;
! 138: if (data->oy + n > screen_hsize(&wp->base))
1.1 nicm 139: data->oy = screen_hsize(&wp->base);
140: else
1.19 ! nicm 141: data->oy += n;
1.1 nicm 142: window_copy_update_selection(wp);
143: window_copy_redraw_screen(wp);
144: }
145:
146: void
147: window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
148: {
149: struct window_copy_mode_data *data = wp->modedata;
150: struct screen *s = &data->screen;
151: struct screen_write_ctx ctx;
152:
153: screen_resize(s, sx, sy);
1.18 nicm 154:
155: if (data->cy > sy - 1)
156: data->cy = sy - 1;
157: if (data->cx > sx)
158: data->cx = sx;
159:
160: screen_clear_selection(&data->screen);
161:
1.1 nicm 162: screen_write_start(&ctx, NULL, s);
163: window_copy_write_lines(wp, &ctx, 0, screen_size_y(s) - 1);
164: screen_write_stop(&ctx);
1.18 nicm 165:
1.17 nicm 166: window_copy_redraw_screen(wp);
1.1 nicm 167: }
168:
169: void
170: window_copy_key(struct window_pane *wp, struct client *c, int key)
171: {
172: struct window_copy_mode_data *data = wp->modedata;
173: struct screen *s = &data->screen;
1.19 ! nicm 174: u_int n;
1.1 nicm 175:
176: switch (mode_key_lookup(&data->mdata, key)) {
1.11 nicm 177: case MODEKEYCOPY_CANCEL:
1.1 nicm 178: window_pane_reset_mode(wp);
179: break;
1.10 nicm 180: case MODEKEYCOPY_LEFT:
1.1 nicm 181: window_copy_cursor_left(wp);
182: return;
1.10 nicm 183: case MODEKEYCOPY_RIGHT:
1.1 nicm 184: window_copy_cursor_right(wp);
185: return;
1.10 nicm 186: case MODEKEYCOPY_UP:
1.1 nicm 187: window_copy_cursor_up(wp);
188: return;
1.10 nicm 189: case MODEKEYCOPY_DOWN:
1.1 nicm 190: window_copy_cursor_down(wp);
191: return;
1.10 nicm 192: case MODEKEYCOPY_PREVIOUSPAGE:
1.1 nicm 193: window_copy_pageup(wp);
194: break;
1.10 nicm 195: case MODEKEYCOPY_NEXTPAGE:
1.19 ! nicm 196: n = 1;
! 197: if (screen_size_y(s) > 2)
! 198: n = screen_size_y(s) - 2;
! 199: if (data->oy < n)
1.1 nicm 200: data->oy = 0;
201: else
1.19 ! nicm 202: data->oy -= n;
1.1 nicm 203: window_copy_update_selection(wp);
204: window_copy_redraw_screen(wp);
205: break;
1.10 nicm 206: case MODEKEYCOPY_STARTSELECTION:
1.1 nicm 207: window_copy_start_selection(wp);
1.7 nicm 208: window_copy_redraw_screen(wp);
1.1 nicm 209: break;
1.10 nicm 210: case MODEKEYCOPY_CLEARSELECTION:
1.1 nicm 211: screen_clear_selection(&data->screen);
212: window_copy_redraw_screen(wp);
213: break;
1.10 nicm 214: case MODEKEYCOPY_COPYSELECTION:
1.1 nicm 215: if (c != NULL && c->session != NULL) {
216: window_copy_copy_selection(wp, c);
217: window_pane_reset_mode(wp);
218: }
219: break;
1.10 nicm 220: case MODEKEYCOPY_STARTOFLINE:
1.1 nicm 221: window_copy_cursor_start_of_line(wp);
222: break;
1.10 nicm 223: case MODEKEYCOPY_BACKTOINDENTATION:
1.6 nicm 224: window_copy_cursor_back_to_indentation(wp);
225: break;
1.10 nicm 226: case MODEKEYCOPY_ENDOFLINE:
1.1 nicm 227: window_copy_cursor_end_of_line(wp);
228: break;
1.10 nicm 229: case MODEKEYCOPY_NEXTWORD:
1.1 nicm 230: window_copy_cursor_next_word(wp);
231: break;
1.10 nicm 232: case MODEKEYCOPY_PREVIOUSWORD:
1.1 nicm 233: window_copy_cursor_previous_word(wp);
234: break;
235: default:
236: break;
237: }
238: }
239:
240: void
241: window_copy_mouse(struct window_pane *wp,
242: unused struct client *c, u_char b, u_char x, u_char y)
243: {
244: struct window_copy_mode_data *data = wp->modedata;
245: struct screen *s = &data->screen;
246:
247: if ((b & 3) == 3)
248: return;
249: if (x >= screen_size_x(s))
250: return;
251: if (y >= screen_size_y(s))
252: return;
253:
1.18 nicm 254: window_copy_update_cursor(wp, x, y);
1.1 nicm 255: if (window_copy_update_selection(wp))
256: window_copy_redraw_screen(wp);
257: }
258:
259: void
1.18 nicm 260: window_copy_write_line(
261: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
1.1 nicm 262: {
263: struct window_copy_mode_data *data = wp->modedata;
264: struct screen *s = &data->screen;
265: struct grid_cell gc;
266: char hdr[32];
267: size_t size;
268:
269: if (py == 0) {
270: memcpy(&gc, &grid_default_cell, sizeof gc);
271: size = xsnprintf(hdr, sizeof hdr,
1.18 nicm 272: "[%u/%u]", data->oy, screen_hsize(&wp->base));
1.14 nicm 273: gc.fg = options_get_number(&wp->window->options, "mode-fg");
274: gc.bg = options_get_number(&wp->window->options, "mode-bg");
1.18 nicm 275: gc.attr |= options_get_number(
276: &wp->window->options, "mode-attr");
1.1 nicm 277: screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
278: screen_write_puts(ctx, &gc, "%s", hdr);
279: } else
280: size = 0;
281:
282: screen_write_cursormove(ctx, 0, py);
1.18 nicm 283: screen_write_copy(ctx, &wp->base, 0, (screen_hsize(&wp->base) -
1.1 nicm 284: data->oy) + py, screen_size_x(s) - size, 1);
1.18 nicm 285:
286: if (py == data->cy && data->cx == screen_size_x(s)) {
287: memcpy(&gc, &grid_default_cell, sizeof gc);
288: screen_write_cursormove(ctx, screen_size_x(s) - 1, py);
289: screen_write_putc(ctx, &gc, '$');
290: }
1.1 nicm 291: }
292:
293: void
294: window_copy_write_lines(
295: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py, u_int ny)
296: {
297: u_int yy;
298:
299: for (yy = py; yy < py + ny; yy++)
300: window_copy_write_line(wp, ctx, py);
301: }
302:
303: void
304: window_copy_redraw_lines(struct window_pane *wp, u_int py, u_int ny)
305: {
306: struct window_copy_mode_data *data = wp->modedata;
307: struct screen_write_ctx ctx;
308: u_int i;
309:
310: screen_write_start(&ctx, wp, NULL);
311: for (i = py; i < py + ny; i++)
312: window_copy_write_line(wp, &ctx, i);
313: screen_write_cursormove(&ctx, data->cx, data->cy);
314: screen_write_stop(&ctx);
315: }
316:
317: void
318: window_copy_redraw_screen(struct window_pane *wp)
319: {
320: struct window_copy_mode_data *data = wp->modedata;
321:
322: window_copy_redraw_lines(wp, 0, screen_size_y(&data->screen));
323: }
324:
325: void
1.18 nicm 326: window_copy_update_cursor(struct window_pane *wp, u_int cx, u_int cy)
1.1 nicm 327: {
328: struct window_copy_mode_data *data = wp->modedata;
1.18 nicm 329: struct screen *s = &data->screen;
1.1 nicm 330: struct screen_write_ctx ctx;
1.18 nicm 331: u_int old_cx, old_cy;
1.1 nicm 332:
1.18 nicm 333: old_cx = data->cx; old_cy = data->cy;
334: data->cx = cx; data->cy = cy;
335: if (old_cx == screen_size_x(s))
336: window_copy_redraw_lines(wp, old_cy, 1);
337: if (data->cx == screen_size_x(s))
338: window_copy_redraw_lines(wp, data->cy, 1);
339: else {
340: screen_write_start(&ctx, wp, NULL);
341: screen_write_cursormove(&ctx, data->cx, data->cy);
342: screen_write_stop(&ctx);
343: }
1.1 nicm 344: }
345:
346: void
347: window_copy_start_selection(struct window_pane *wp)
348: {
349: struct window_copy_mode_data *data = wp->modedata;
350: struct screen *s = &data->screen;
351:
1.18 nicm 352: data->selx = data->cx;
1.1 nicm 353: data->sely = screen_hsize(&wp->base) + data->cy - data->oy;
354:
355: s->sel.flag = 1;
356: window_copy_update_selection(wp);
357: }
358:
359: int
360: window_copy_update_selection(struct window_pane *wp)
361: {
362: struct window_copy_mode_data *data = wp->modedata;
363: struct screen *s = &data->screen;
364: struct grid_cell gc;
1.18 nicm 365: u_int sx, sy, ty;
1.1 nicm 366:
367: if (!s->sel.flag)
368: return (0);
369:
370: /* Set colours. */
371: memcpy(&gc, &grid_default_cell, sizeof gc);
1.14 nicm 372: gc.fg = options_get_number(&wp->window->options, "mode-fg");
373: gc.bg = options_get_number(&wp->window->options, "mode-bg");
1.1 nicm 374: gc.attr |= options_get_number(&wp->window->options, "mode-attr");
375:
1.18 nicm 376: /* Find top of screen. */
1.1 nicm 377: ty = screen_hsize(&wp->base) - data->oy;
378:
379: /* Adjust the selection. */
380: sx = data->selx;
381: sy = data->sely;
1.18 nicm 382: if (sy < ty) { /* above screen */
1.1 nicm 383: sx = 0;
384: sy = 0;
1.18 nicm 385: } else if (sy > ty + screen_size_y(s) - 1) { /* below screen */
1.1 nicm 386: sx = screen_size_x(s) - 1;
387: sy = screen_size_y(s) - 1;
1.18 nicm 388: } else
1.1 nicm 389: sy -= ty;
390: sy = screen_hsize(s) + sy;
391:
392: screen_set_selection(
393: s, sx, sy, data->cx, screen_hsize(s) + data->cy, &gc);
394: return (1);
395: }
396:
397: void
398: window_copy_copy_selection(struct window_pane *wp, struct client *c)
399: {
400: struct window_copy_mode_data *data = wp->modedata;
401: struct screen *s = &data->screen;
402: char *buf;
403: size_t off;
404: u_int i, xx, yy, sx, sy, ex, ey, limit;
405:
406: if (!s->sel.flag)
407: return;
408:
409: buf = xmalloc(1);
410: off = 0;
411:
412: *buf = '\0';
413:
414: /*
415: * The selection extends from selx,sely to (adjusted) cx,cy on
416: * the base screen.
417: */
418:
419: /* Find start and end. */
1.18 nicm 420: xx = data->cx;
1.1 nicm 421: yy = screen_hsize(&wp->base) + data->cy - data->oy;
1.2 nicm 422: if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
1.1 nicm 423: sx = xx; sy = yy;
424: ex = data->selx; ey = data->sely;
425: } else {
426: sx = data->selx; sy = data->sely;
427: ex = xx; ey = yy;
428: }
429:
430: /* Trim ex to end of line. */
431: xx = window_copy_find_length(wp, ey);
432: if (ex > xx)
433: ex = xx;
434:
435: /* Copy the lines. */
436: if (sy == ey)
437: window_copy_copy_line(wp, &buf, &off, sy, sx, ex);
438: else {
1.16 nicm 439: xx = screen_size_x(s);
1.1 nicm 440: window_copy_copy_line(wp, &buf, &off, sy, sx, xx);
441: if (ey - sy > 1) {
1.16 nicm 442: for (i = sy + 1; i < ey; i++)
1.1 nicm 443: window_copy_copy_line(wp, &buf, &off, i, 0, xx);
444: }
445: window_copy_copy_line(wp, &buf, &off, ey, 0, ex);
446: }
447:
448: /* Terminate buffer, overwriting final \n. */
449: if (off != 0)
450: buf[off - 1] = '\0';
451:
452: /* Add the buffer to the stack. */
453: limit = options_get_number(&c->session->options, "buffer-limit");
454: paste_add(&c->session->buffers, buf, limit);
455: }
456:
457: void
458: window_copy_copy_line(struct window_pane *wp,
459: char **buf, size_t *off, u_int sy, u_int sx, u_int ex)
460: {
1.16 nicm 461: struct grid *gd = wp->base.grid;
1.1 nicm 462: const struct grid_cell *gc;
463: const struct grid_utf8 *gu;
1.16 nicm 464: struct grid_line *gl;
465: u_int i, j, xx, wrapped = 0;
1.1 nicm 466:
467: if (sx > ex)
468: return;
469:
1.16 nicm 470: /*
471: * Work out if the line was wrapped at the screen edge and all of it is
472: * on screen.
473: */
474: gl = &gd->linedata[sy];
475: if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
476: wrapped = 1;
477:
478: /* If the line was wrapped, don't strip spaces (use the full length). */
479: if (wrapped)
480: xx = gl->cellsize;
481: else
482: xx = window_copy_find_length(wp, sy);
1.1 nicm 483: if (ex > xx)
484: ex = xx;
485: if (sx > xx)
486: sx = xx;
487:
488: if (sx < ex) {
489: for (i = sx; i < ex; i++) {
1.16 nicm 490: gc = grid_peek_cell(gd, i, sy);
1.1 nicm 491: if (gc->flags & GRID_FLAG_PADDING)
492: continue;
493: if (!(gc->flags & GRID_FLAG_UTF8)) {
494: *buf = xrealloc(*buf, 1, (*off) + 1);
495: (*buf)[(*off)++] = gc->data;
496: } else {
1.16 nicm 497: gu = grid_peek_utf8(gd, i, sy);
1.1 nicm 498: *buf = xrealloc(*buf, 1, (*off) + UTF8_SIZE);
499: for (j = 0; j < UTF8_SIZE; j++) {
500: if (gu->data[j] == 0xff)
501: break;
502: (*buf)[(*off)++] = gu->data[j];
503: }
504: }
505: }
506: }
507:
1.16 nicm 508: /* Only add a newline if the line wasn't wrapped. */
509: if (!wrapped) {
510: *buf = xrealloc(*buf, 1, (*off) + 1);
511: (*buf)[(*off)++] = '\n';
512: }
1.1 nicm 513: }
514:
515: int
516: window_copy_is_space(struct window_pane *wp, u_int px, u_int py)
517: {
518: const struct grid_cell *gc;
519: const char *spaces = " -_@";
520:
521: gc = grid_peek_cell(wp->base.grid, px, py);
522: if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8))
523: return (0);
524: if (gc->data == 0x00 || gc->data == 0x7f)
525: return (0);
526: return (strchr(spaces, gc->data) != NULL);
527: }
528:
529: u_int
530: window_copy_find_length(struct window_pane *wp, u_int py)
531: {
532: const struct grid_cell *gc;
533: u_int px;
534:
1.4 nicm 535: /*
536: * If the pane has been resized, its grid can contain old overlong
537: * lines. grid_peek_cell does not allow accessing cells beyond the
538: * width of the grid, and screen_write_copy treats them as spaces, so
539: * ignore them here too.
540: */
1.15 nicm 541: px = wp->base.grid->linedata[py].cellsize;
1.4 nicm 542: if (px > screen_size_x(&wp->base))
543: px = screen_size_x(&wp->base);
1.1 nicm 544: while (px > 0) {
545: gc = grid_peek_cell(wp->base.grid, px - 1, py);
546: if (gc->flags & GRID_FLAG_UTF8)
547: break;
548: if (gc->data != ' ')
549: break;
550: px--;
551: }
552: return (px);
553: }
554:
555: void
1.5 nicm 556: window_copy_cursor_start_of_line(struct window_pane *wp)
557: {
558: struct window_copy_mode_data *data = wp->modedata;
559:
1.18 nicm 560: window_copy_update_cursor(wp, 0, data->cy);
1.5 nicm 561: if (window_copy_update_selection(wp))
562: window_copy_redraw_lines(wp, data->cy, 1);
1.6 nicm 563: }
564:
565: void
566: window_copy_cursor_back_to_indentation(struct window_pane *wp)
567: {
568: struct window_copy_mode_data *data = wp->modedata;
569: u_int px, py, xx;
570: const struct grid_cell *gc;
571:
572: px = 0;
573: py = screen_hsize(&wp->base) + data->cy - data->oy;
574: xx = window_copy_find_length(wp, py);
575:
576: /*
577: * Don't use window_copy_is_space because that treats some word
578: * delimiters as spaces.
579: */
580: while (px < xx) {
581: gc = grid_peek_cell(wp->base.grid, px, py);
582: if (gc->flags & GRID_FLAG_UTF8)
583: break;
584: if (gc->data != ' ')
585: break;
586: px++;
587: }
588:
1.18 nicm 589: window_copy_update_cursor(wp, px, data->cy);
590: if (window_copy_update_selection(wp))
591: window_copy_redraw_lines(wp, data->cy, 1);
1.5 nicm 592: }
593:
594: void
595: window_copy_cursor_end_of_line(struct window_pane *wp)
596: {
597: struct window_copy_mode_data *data = wp->modedata;
598: u_int px, py;
599:
600: py = screen_hsize(&wp->base) + data->cy - data->oy;
601: px = window_copy_find_length(wp, py);
602:
1.18 nicm 603: window_copy_update_cursor(wp, px, data->cy);
604: if (window_copy_update_selection(wp))
605: window_copy_redraw_lines(wp, data->cy, 1);
1.5 nicm 606: }
607:
608: void
1.1 nicm 609: window_copy_cursor_left(struct window_pane *wp)
610: {
611: struct window_copy_mode_data *data = wp->modedata;
612:
613: if (data->cx == 0) {
1.18 nicm 614: window_copy_cursor_up(wp);
615: window_copy_cursor_end_of_line(wp);
1.1 nicm 616: } else {
1.18 nicm 617: window_copy_update_cursor(wp, data->cx - 1, data->cy);
1.1 nicm 618: if (window_copy_update_selection(wp))
619: window_copy_redraw_lines(wp, data->cy, 1);
620: }
621: }
622:
623: void
624: window_copy_cursor_right(struct window_pane *wp)
625: {
626: struct window_copy_mode_data *data = wp->modedata;
627: u_int px, py;
628:
629: py = screen_hsize(&wp->base) + data->cy - data->oy;
630: px = window_copy_find_length(wp, py);
631:
632: if (data->cx >= px) {
633: window_copy_cursor_start_of_line(wp);
634: window_copy_cursor_down(wp);
635: } else {
1.18 nicm 636: window_copy_update_cursor(wp, data->cx + 1, data->cy);
1.1 nicm 637: if (window_copy_update_selection(wp))
638: window_copy_redraw_lines(wp, data->cy, 1);
639: }
640: }
641:
642: void
643: window_copy_cursor_up(struct window_pane *wp)
644: {
645: struct window_copy_mode_data *data = wp->modedata;
646: u_int ox, oy, px, py;
647:
648: oy = screen_hsize(&wp->base) + data->cy - data->oy;
649: ox = window_copy_find_length(wp, oy);
650:
651: if (data->cy == 0)
652: window_copy_scroll_down(wp, 1);
653: else {
1.18 nicm 654: window_copy_update_cursor(wp, data->cx, data->cy - 1);
1.1 nicm 655: if (window_copy_update_selection(wp))
656: window_copy_redraw_lines(wp, data->cy, 2);
657: }
658:
659: py = screen_hsize(&wp->base) + data->cy - data->oy;
660: px = window_copy_find_length(wp, py);
661:
1.18 nicm 662: if (data->cx >= px || data->cx >= ox)
1.1 nicm 663: window_copy_cursor_end_of_line(wp);
664: }
665:
666: void
667: window_copy_cursor_down(struct window_pane *wp)
668: {
669: struct window_copy_mode_data *data = wp->modedata;
670: struct screen *s = &data->screen;
671: u_int ox, oy, px, py;
672:
673: oy = screen_hsize(&wp->base) + data->cy - data->oy;
674: ox = window_copy_find_length(wp, oy);
675:
676: if (data->cy == screen_size_y(s) - 1)
677: window_copy_scroll_up(wp, 1);
678: else {
1.18 nicm 679: window_copy_update_cursor(wp, data->cx, data->cy + 1);
1.1 nicm 680: if (window_copy_update_selection(wp))
681: window_copy_redraw_lines(wp, data->cy - 1, 2);
682: }
683:
684: py = screen_hsize(&wp->base) + data->cy - data->oy;
685: px = window_copy_find_length(wp, py);
686:
1.18 nicm 687: if (data->cx >= px || data->cx >= ox)
1.1 nicm 688: window_copy_cursor_end_of_line(wp);
689: }
690:
691: void
692: window_copy_cursor_next_word(struct window_pane *wp)
693: {
694: struct window_copy_mode_data *data = wp->modedata;
695: struct screen *s = &data->screen;
696: u_int px, py, xx, skip;
697:
1.18 nicm 698: px = data->cx;
1.1 nicm 699: py = screen_hsize(&wp->base) + data->cy - data->oy;
700: xx = window_copy_find_length(wp, py);
701:
702: skip = 1;
703: if (px < xx) {
704: /* If currently on a space, skip space. */
705: if (window_copy_is_space(wp, px, py))
706: skip = 0;
707: } else
708: skip = 0;
709: for (;;) {
710: if (px >= xx) {
711: if (skip) {
712: px = xx;
713: break;
714: }
715:
716: while (px >= xx) {
717: if (data->cy == screen_size_y(s) - 1) {
718: if (data->oy == 0)
719: goto out;
720: }
721:
722: px = 0;
723: window_copy_cursor_down(wp);
724:
725: py =screen_hsize(
726: &wp->base) + data->cy - data->oy;
727: xx = window_copy_find_length(wp, py);
728: }
729: }
730:
731: if (skip) {
732: /* Currently skipping non-space (until space). */
733: if (window_copy_is_space(wp, px, py))
734: break;
735: } else {
736: /* Currently skipping space (until non-space). */
737: if (!window_copy_is_space(wp, px, py))
738: skip = 1;
739: }
740:
741: px++;
742: }
1.18 nicm 743:
1.1 nicm 744: out:
1.18 nicm 745: window_copy_update_cursor(wp, px, data->cy);
746: if (window_copy_update_selection(wp))
747: window_copy_redraw_lines(wp, data->cy, 1);
1.1 nicm 748: }
749:
1.8 nicm 750: /* Move to the previous place where a word begins. */
1.1 nicm 751: void
752: window_copy_cursor_previous_word(struct window_pane *wp)
753: {
754: struct window_copy_mode_data *data = wp->modedata;
1.8 nicm 755: u_int px, py;
1.1 nicm 756:
1.18 nicm 757: px = data->cx;
1.1 nicm 758: py = screen_hsize(&wp->base) + data->cy - data->oy;
759:
1.8 nicm 760: /* Move back to the previous word character. */
1.1 nicm 761: for (;;) {
1.8 nicm 762: if (px > 0) {
763: px--;
764: if (!window_copy_is_space(wp, px, py))
1.1 nicm 765: break;
1.8 nicm 766: } else {
767: if (data->cy == 0 &&
768: (screen_hsize(&wp->base) == 0 ||
769: data->oy >= screen_hsize(&wp->base) - 1))
770: goto out;
771: window_copy_cursor_up(wp);
1.1 nicm 772:
1.8 nicm 773: py = screen_hsize(
774: &wp->base) + data->cy - data->oy;
775: px = window_copy_find_length(wp, py);
1.1 nicm 776: }
1.8 nicm 777: }
1.1 nicm 778:
1.8 nicm 779: /* Move back to the beginning of this word. */
780: while (px > 0 && !window_copy_is_space(wp, px - 1, py))
1.1 nicm 781: px--;
1.8 nicm 782:
1.1 nicm 783: out:
1.18 nicm 784: window_copy_update_cursor(wp, px, data->cy);
785: if (window_copy_update_selection(wp))
786: window_copy_redraw_lines(wp, data->cy, 1);
1.1 nicm 787: }
788:
789: void
790: window_copy_scroll_up(struct window_pane *wp, u_int ny)
791: {
792: struct window_copy_mode_data *data = wp->modedata;
793: struct screen *s = &data->screen;
794: struct screen_write_ctx ctx;
795:
796: if (data->oy < ny)
797: ny = data->oy;
798: if (ny == 0)
799: return;
800: data->oy -= ny;
801: window_copy_update_selection(wp);
802:
803: screen_write_start(&ctx, wp, NULL);
804: screen_write_cursormove(&ctx, 0, 0);
805: screen_write_deleteline(&ctx, ny);
806: window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, ny);
807: window_copy_write_line(wp, &ctx, 0);
808: window_copy_write_line(wp, &ctx, 1);
809: if (s->sel.flag && screen_size_y(s) > ny)
810: window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1);
811: screen_write_cursormove(&ctx, data->cx, data->cy);
812: screen_write_stop(&ctx);
813: }
814:
815: void
816: window_copy_scroll_down(struct window_pane *wp, u_int ny)
817: {
818: struct window_copy_mode_data *data = wp->modedata;
819: struct screen *s = &data->screen;
820: struct screen_write_ctx ctx;
821:
822: if (ny > screen_hsize(&wp->base))
823: return;
824:
825: if (data->oy > screen_hsize(&wp->base) - ny)
826: ny = screen_hsize(&wp->base) - data->oy;
827: if (ny == 0)
828: return;
829: data->oy += ny;
830: window_copy_update_selection(wp);
831:
832: screen_write_start(&ctx, wp, NULL);
833: screen_write_cursormove(&ctx, 0, 0);
834: screen_write_insertline(&ctx, ny);
835: window_copy_write_lines(wp, &ctx, 0, ny);
836: if (s->sel.flag && screen_size_y(s) > ny)
837: window_copy_write_line(wp, &ctx, ny);
838: else if (ny == 1) /* nuke position */
839: window_copy_write_line(wp, &ctx, 1);
840: screen_write_cursormove(&ctx, data->cx, data->cy);
841: screen_write_stop(&ctx);
842: }