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