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