Annotation of src/usr.bin/tmux/window-copy.c, Revision 1.16
1.16 ! nicm 1: /* $OpenBSD: window-copy.c,v 1.15 2009/08/08 13:29:27 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 {
1.16 ! nicm 452: xx = screen_size_x(s);
1.1 nicm 453: window_copy_copy_line(wp, &buf, &off, sy, sx, xx);
454: if (ey - sy > 1) {
1.16 ! nicm 455: for (i = sy + 1; i < ey; i++)
1.1 nicm 456: window_copy_copy_line(wp, &buf, &off, i, 0, xx);
457: }
458: window_copy_copy_line(wp, &buf, &off, ey, 0, ex);
459: }
460:
461: /* Terminate buffer, overwriting final \n. */
462: if (off != 0)
463: buf[off - 1] = '\0';
464:
465: /* Add the buffer to the stack. */
466: limit = options_get_number(&c->session->options, "buffer-limit");
467: paste_add(&c->session->buffers, buf, limit);
468: }
469:
470: void
471: window_copy_copy_line(struct window_pane *wp,
472: char **buf, size_t *off, u_int sy, u_int sx, u_int ex)
473: {
1.16 ! nicm 474: struct grid *gd = wp->base.grid;
1.1 nicm 475: const struct grid_cell *gc;
476: const struct grid_utf8 *gu;
1.16 ! nicm 477: struct grid_line *gl;
! 478: u_int i, j, xx, wrapped = 0;
1.1 nicm 479:
480: if (sx > ex)
481: return;
482:
1.16 ! nicm 483: /*
! 484: * Work out if the line was wrapped at the screen edge and all of it is
! 485: * on screen.
! 486: */
! 487: gl = &gd->linedata[sy];
! 488: if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
! 489: wrapped = 1;
! 490:
! 491: /* If the line was wrapped, don't strip spaces (use the full length). */
! 492: if (wrapped)
! 493: xx = gl->cellsize;
! 494: else
! 495: xx = window_copy_find_length(wp, sy);
1.1 nicm 496: if (ex > xx)
497: ex = xx;
498: if (sx > xx)
499: sx = xx;
500:
501: if (sx < ex) {
502: for (i = sx; i < ex; i++) {
1.16 ! nicm 503: gc = grid_peek_cell(gd, i, sy);
1.1 nicm 504: if (gc->flags & GRID_FLAG_PADDING)
505: continue;
506: if (!(gc->flags & GRID_FLAG_UTF8)) {
507: *buf = xrealloc(*buf, 1, (*off) + 1);
508: (*buf)[(*off)++] = gc->data;
509: } else {
1.16 ! nicm 510: gu = grid_peek_utf8(gd, i, sy);
1.1 nicm 511: *buf = xrealloc(*buf, 1, (*off) + UTF8_SIZE);
512: for (j = 0; j < UTF8_SIZE; j++) {
513: if (gu->data[j] == 0xff)
514: break;
515: (*buf)[(*off)++] = gu->data[j];
516: }
517: }
518: }
519: }
520:
1.16 ! nicm 521: /* Only add a newline if the line wasn't wrapped. */
! 522: if (!wrapped) {
! 523: *buf = xrealloc(*buf, 1, (*off) + 1);
! 524: (*buf)[(*off)++] = '\n';
! 525: }
1.1 nicm 526: }
527:
528: int
529: window_copy_is_space(struct window_pane *wp, u_int px, u_int py)
530: {
531: const struct grid_cell *gc;
532: const char *spaces = " -_@";
533:
534: gc = grid_peek_cell(wp->base.grid, px, py);
535: if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8))
536: return (0);
537: if (gc->data == 0x00 || gc->data == 0x7f)
538: return (0);
539: return (strchr(spaces, gc->data) != NULL);
540: }
541:
542: u_int
543: window_copy_find_length(struct window_pane *wp, u_int py)
544: {
545: const struct grid_cell *gc;
546: u_int px;
547:
1.4 nicm 548: /*
549: * If the pane has been resized, its grid can contain old overlong
550: * lines. grid_peek_cell does not allow accessing cells beyond the
551: * width of the grid, and screen_write_copy treats them as spaces, so
552: * ignore them here too.
553: */
1.15 nicm 554: px = wp->base.grid->linedata[py].cellsize;
1.4 nicm 555: if (px > screen_size_x(&wp->base))
556: px = screen_size_x(&wp->base);
1.1 nicm 557: while (px > 0) {
558: gc = grid_peek_cell(wp->base.grid, px - 1, py);
559: if (gc->flags & GRID_FLAG_UTF8)
560: break;
561: if (gc->data != ' ')
562: break;
563: px--;
564: }
565: return (px);
566: }
567:
1.5 nicm 568: /*
569: * Set the cursor X coordinate and scroll horizontally to make it visible.
570: * Also redraw the selection or the cursor, as needed.
571: */
1.1 nicm 572: void
1.5 nicm 573: window_copy_set_cursor_x(struct window_pane *wp, u_int px)
1.1 nicm 574: {
575: struct window_copy_mode_data *data = wp->modedata;
576: struct screen *s = &data->screen;
577:
578: /* On screen. */
579: if (px > data->ox && px <= data->ox + screen_size_x(s) - 1)
580: data->cx = px - data->ox;
581:
582: /* Off right of screen. */
583: if (px > data->ox + screen_size_x(s) - 1) {
584: /* Move cursor to last and scroll screen. */
585: window_copy_scroll_left(
586: wp, px - data->ox - (screen_size_x(s) - 1));
587: data->cx = screen_size_x(s) - 1;
588: }
589:
590: /* Off left of screen. */
591: if (px <= data->ox) {
592: if (px < screen_size_x(s) - 1) {
593: /* Short enough to fit on screen. */
594: window_copy_scroll_right(wp, data->ox);
595: data->cx = px;
596: } else {
597: /* Too long to fit on screen. */
598: window_copy_scroll_right(
599: wp, data->ox - (px - (screen_size_x(s) - 1)));
600: data->cx = screen_size_x(s) - 1;
601: }
602: }
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);
608: }
609:
610: void
1.5 nicm 611: window_copy_cursor_start_of_line(struct window_pane *wp)
612: {
613: struct window_copy_mode_data *data = wp->modedata;
614:
615: if (data->ox != 0)
616: window_copy_scroll_right(wp, data->ox);
617: data->cx = 0;
618:
619: if (window_copy_update_selection(wp))
620: window_copy_redraw_lines(wp, data->cy, 1);
621: else
622: window_copy_update_cursor(wp);
1.6 nicm 623: }
624:
625: void
626: window_copy_cursor_back_to_indentation(struct window_pane *wp)
627: {
628: struct window_copy_mode_data *data = wp->modedata;
629: u_int px, py, xx;
630: const struct grid_cell *gc;
631:
632: px = 0;
633: py = screen_hsize(&wp->base) + data->cy - data->oy;
634: xx = window_copy_find_length(wp, py);
635:
636: /*
637: * Don't use window_copy_is_space because that treats some word
638: * delimiters as spaces.
639: */
640: while (px < xx) {
641: gc = grid_peek_cell(wp->base.grid, px, py);
642: if (gc->flags & GRID_FLAG_UTF8)
643: break;
644: if (gc->data != ' ')
645: break;
646: px++;
647: }
648:
649: window_copy_set_cursor_x(wp, px);
1.5 nicm 650: }
651:
652: void
653: window_copy_cursor_end_of_line(struct window_pane *wp)
654: {
655: struct window_copy_mode_data *data = wp->modedata;
656: u_int px, py;
657:
658: py = screen_hsize(&wp->base) + data->cy - data->oy;
659: px = window_copy_find_length(wp, py);
660:
661: window_copy_set_cursor_x(wp, px);
662: }
663:
664: void
1.1 nicm 665: window_copy_cursor_left(struct window_pane *wp)
666: {
667: struct window_copy_mode_data *data = wp->modedata;
668:
669: if (data->cx == 0) {
670: if (data->ox > 0)
671: window_copy_scroll_right(wp, 1);
672: else {
673: window_copy_cursor_up(wp);
674: window_copy_cursor_end_of_line(wp);
675: }
676: } else {
677: data->cx--;
678: if (window_copy_update_selection(wp))
679: window_copy_redraw_lines(wp, data->cy, 1);
680: else
681: window_copy_update_cursor(wp);
682: }
683: }
684:
685: void
686: window_copy_cursor_right(struct window_pane *wp)
687: {
688: struct window_copy_mode_data *data = wp->modedata;
689: u_int px, py;
690:
691: py = screen_hsize(&wp->base) + data->cy - data->oy;
692: px = window_copy_find_length(wp, py);
693:
694: if (data->cx >= px) {
695: window_copy_cursor_start_of_line(wp);
696: window_copy_cursor_down(wp);
697: } else {
698: data->cx++;
699: if (window_copy_update_selection(wp))
700: window_copy_redraw_lines(wp, data->cy, 1);
701: else
702: window_copy_update_cursor(wp);
703: }
704: }
705:
706: void
707: window_copy_cursor_up(struct window_pane *wp)
708: {
709: struct window_copy_mode_data *data = wp->modedata;
710: u_int ox, oy, px, py;
711:
712: oy = screen_hsize(&wp->base) + data->cy - data->oy;
713: ox = window_copy_find_length(wp, oy);
714:
715: if (data->cy == 0)
716: window_copy_scroll_down(wp, 1);
717: else {
718: data->cy--;
719: if (window_copy_update_selection(wp))
720: window_copy_redraw_lines(wp, data->cy, 2);
721: else
722: window_copy_update_cursor(wp);
723: }
724:
725: py = screen_hsize(&wp->base) + data->cy - data->oy;
726: px = window_copy_find_length(wp, py);
727:
728: if (data->cx + data->ox >= px || data->cx + data->ox >= ox)
729: window_copy_cursor_end_of_line(wp);
730: }
731:
732: void
733: window_copy_cursor_down(struct window_pane *wp)
734: {
735: struct window_copy_mode_data *data = wp->modedata;
736: struct screen *s = &data->screen;
737: u_int ox, oy, px, py;
738:
739: oy = screen_hsize(&wp->base) + data->cy - data->oy;
740: ox = window_copy_find_length(wp, oy);
741:
742: if (data->cy == screen_size_y(s) - 1)
743: window_copy_scroll_up(wp, 1);
744: else {
745: data->cy++;
746: if (window_copy_update_selection(wp))
747: window_copy_redraw_lines(wp, data->cy - 1, 2);
748: else
749: window_copy_update_cursor(wp);
750: }
751:
752: py = screen_hsize(&wp->base) + data->cy - data->oy;
753: px = window_copy_find_length(wp, py);
754:
755: if (data->cx + data->ox >= px || data->cx + data->ox >= ox)
756: window_copy_cursor_end_of_line(wp);
757: }
758:
759: void
760: window_copy_cursor_next_word(struct window_pane *wp)
761: {
762: struct window_copy_mode_data *data = wp->modedata;
763: struct screen *s = &data->screen;
764: u_int px, py, xx, skip;
765:
766: px = data->ox + data->cx;
767: py = screen_hsize(&wp->base) + data->cy - data->oy;
768: xx = window_copy_find_length(wp, py);
769:
770: skip = 1;
771: if (px < xx) {
772: /* If currently on a space, skip space. */
773: if (window_copy_is_space(wp, px, py))
774: skip = 0;
775: } else
776: skip = 0;
777: for (;;) {
778: if (px >= xx) {
779: if (skip) {
780: px = xx;
781: break;
782: }
783:
784: while (px >= xx) {
785: if (data->cy == screen_size_y(s) - 1) {
786: if (data->oy == 0)
787: goto out;
788: }
789:
790: px = 0;
791: window_copy_cursor_down(wp);
792:
793: py =screen_hsize(
794: &wp->base) + data->cy - data->oy;
795: xx = window_copy_find_length(wp, py);
796: }
797: }
798:
799: if (skip) {
800: /* Currently skipping non-space (until space). */
801: if (window_copy_is_space(wp, px, py))
802: break;
803: } else {
804: /* Currently skipping space (until non-space). */
805: if (!window_copy_is_space(wp, px, py))
806: skip = 1;
807: }
808:
809: px++;
810: }
811: out:
812:
1.5 nicm 813: window_copy_set_cursor_x(wp, px);
1.1 nicm 814: }
815:
1.8 nicm 816: /* Move to the previous place where a word begins. */
1.1 nicm 817: void
818: window_copy_cursor_previous_word(struct window_pane *wp)
819: {
820: struct window_copy_mode_data *data = wp->modedata;
1.8 nicm 821: u_int px, py;
1.1 nicm 822:
1.8 nicm 823: px = data->ox + data->cx;
1.1 nicm 824: py = screen_hsize(&wp->base) + data->cy - data->oy;
825:
1.8 nicm 826: /* Move back to the previous word character. */
1.1 nicm 827: for (;;) {
1.8 nicm 828: if (px > 0) {
829: px--;
830: if (!window_copy_is_space(wp, px, py))
1.1 nicm 831: break;
1.8 nicm 832: } else {
833: if (data->cy == 0 &&
834: (screen_hsize(&wp->base) == 0 ||
835: data->oy >= screen_hsize(&wp->base) - 1))
836: goto out;
837: window_copy_cursor_up(wp);
1.1 nicm 838:
1.8 nicm 839: py = screen_hsize(
840: &wp->base) + data->cy - data->oy;
841: px = window_copy_find_length(wp, py);
1.1 nicm 842: }
1.8 nicm 843: }
1.1 nicm 844:
1.8 nicm 845: /* Move back to the beginning of this word. */
846: while (px > 0 && !window_copy_is_space(wp, px - 1, py))
1.1 nicm 847: px--;
1.8 nicm 848:
1.1 nicm 849: out:
1.5 nicm 850: window_copy_set_cursor_x(wp, px);
1.1 nicm 851: }
852:
853: void
854: window_copy_scroll_left(struct window_pane *wp, u_int nx)
855: {
856: struct window_copy_mode_data *data = wp->modedata;
857: struct screen *s = &data->screen;
858: struct screen_write_ctx ctx;
859: u_int i;
860:
861: if (data->ox > SHRT_MAX - nx)
862: nx = SHRT_MAX - data->ox;
863: if (nx == 0)
864: return;
865: data->ox += nx;
866: window_copy_update_selection(wp);
867:
868: screen_write_start(&ctx, wp, NULL);
869: for (i = 1; i < screen_size_y(s); i++) {
870: screen_write_cursormove(&ctx, 0, i);
871: screen_write_deletecharacter(&ctx, nx);
872: }
873: window_copy_write_columns(wp, &ctx, screen_size_x(s) - nx, nx);
874: window_copy_write_line(wp, &ctx, 0);
875: if (s->sel.flag) {
876: window_copy_update_selection(wp);
877: window_copy_write_lines(wp, &ctx, data->cy, 1);
878: }
879: screen_write_cursormove(&ctx, data->cx, data->cy);
880: screen_write_stop(&ctx);
881: }
882:
883: void
884: window_copy_scroll_right(struct window_pane *wp, u_int nx)
885: {
886: struct window_copy_mode_data *data = wp->modedata;
887: struct screen *s = &data->screen;
888: struct screen_write_ctx ctx;
889: u_int i;
890:
891: if (data->ox < nx)
892: nx = data->ox;
893: if (nx == 0)
894: return;
895: data->ox -= nx;
896: window_copy_update_selection(wp);
897:
898: screen_write_start(&ctx, wp, NULL);
899: for (i = 1; i < screen_size_y(s); i++) {
900: screen_write_cursormove(&ctx, 0, i);
901: screen_write_insertcharacter(&ctx, nx);
902: }
903: window_copy_write_columns(wp, &ctx, 0, nx);
904: window_copy_write_line(wp, &ctx, 0);
905: if (s->sel.flag)
906: window_copy_write_line(wp, &ctx, data->cy);
907: screen_write_cursormove(&ctx, data->cx, data->cy);
908: screen_write_stop(&ctx);
909: }
910:
911: void
912: window_copy_scroll_up(struct window_pane *wp, u_int ny)
913: {
914: struct window_copy_mode_data *data = wp->modedata;
915: struct screen *s = &data->screen;
916: struct screen_write_ctx ctx;
917:
918: if (data->oy < ny)
919: ny = data->oy;
920: if (ny == 0)
921: return;
922: data->oy -= ny;
923: window_copy_update_selection(wp);
924:
925: screen_write_start(&ctx, wp, NULL);
926: screen_write_cursormove(&ctx, 0, 0);
927: screen_write_deleteline(&ctx, ny);
928: window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, ny);
929: window_copy_write_line(wp, &ctx, 0);
930: window_copy_write_line(wp, &ctx, 1);
931: if (s->sel.flag && screen_size_y(s) > ny)
932: window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1);
933: screen_write_cursormove(&ctx, data->cx, data->cy);
934: screen_write_stop(&ctx);
935: }
936:
937: void
938: window_copy_scroll_down(struct window_pane *wp, u_int ny)
939: {
940: struct window_copy_mode_data *data = wp->modedata;
941: struct screen *s = &data->screen;
942: struct screen_write_ctx ctx;
943:
944: if (ny > screen_hsize(&wp->base))
945: return;
946:
947: if (data->oy > screen_hsize(&wp->base) - ny)
948: ny = screen_hsize(&wp->base) - data->oy;
949: if (ny == 0)
950: return;
951: data->oy += ny;
952: window_copy_update_selection(wp);
953:
954: screen_write_start(&ctx, wp, NULL);
955: screen_write_cursormove(&ctx, 0, 0);
956: screen_write_insertline(&ctx, ny);
957: window_copy_write_lines(wp, &ctx, 0, ny);
958: if (s->sel.flag && screen_size_y(s) > ny)
959: window_copy_write_line(wp, &ctx, ny);
960: else if (ny == 1) /* nuke position */
961: window_copy_write_line(wp, &ctx, 1);
962: screen_write_cursormove(&ctx, data->cx, data->cy);
963: screen_write_stop(&ctx);
964: }