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