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