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