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