Annotation of src/usr.bin/tmux/window-copy.c, Revision 1.18
1.18 ! nicm 1: /* $OpenBSD: window-copy.c,v 1.17 2009/08/13 16:48:43 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:
1.18 ! nicm 39: void window_copy_update_cursor(struct window_pane *, u_int, u_int);
1.1 nicm 40: void window_copy_start_selection(struct window_pane *);
41: int window_copy_update_selection(struct window_pane *);
42: void window_copy_copy_selection(struct window_pane *, struct client *);
43: void window_copy_copy_line(
44: struct window_pane *, char **, size_t *, u_int, u_int, u_int);
45: int window_copy_is_space(struct window_pane *, u_int, u_int);
46: u_int window_copy_find_length(struct window_pane *, u_int);
47: void window_copy_cursor_start_of_line(struct window_pane *);
1.6 nicm 48: void window_copy_cursor_back_to_indentation(struct window_pane *);
1.1 nicm 49: void window_copy_cursor_end_of_line(struct window_pane *);
50: void window_copy_cursor_left(struct window_pane *);
51: void window_copy_cursor_right(struct window_pane *);
52: void window_copy_cursor_up(struct window_pane *);
53: void window_copy_cursor_down(struct window_pane *);
54: void window_copy_cursor_next_word(struct window_pane *);
55: void window_copy_cursor_previous_word(struct window_pane *);
56: void window_copy_scroll_up(struct window_pane *, u_int);
57: void window_copy_scroll_down(struct window_pane *, u_int);
58:
59: const struct window_mode window_copy_mode = {
60: window_copy_init,
61: window_copy_free,
62: window_copy_resize,
63: window_copy_key,
64: window_copy_mouse,
65: NULL,
66: };
67:
68: struct window_copy_mode_data {
69: struct screen screen;
70:
71: struct mode_key_data mdata;
72:
73: u_int oy;
74:
75: u_int selx;
76: u_int sely;
77:
78: u_int cx;
79: u_int cy;
80: };
81:
82: struct screen *
83: window_copy_init(struct window_pane *wp)
84: {
85: struct window_copy_mode_data *data;
86: struct screen *s;
87: struct screen_write_ctx ctx;
88: u_int i;
1.10 nicm 89: int keys;
1.1 nicm 90:
91: wp->modedata = data = xmalloc(sizeof *data);
92: data->oy = 0;
93: data->cx = wp->base.cx;
94: data->cy = wp->base.cy;
95:
96: s = &data->screen;
97: screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
1.13 nicm 98: if (options_get_number(&wp->window->options, "mode-mouse"))
99: s->mode |= MODE_MOUSE;
1.1 nicm 100:
1.10 nicm 101: keys = options_get_number(&wp->window->options, "mode-keys");
102: if (keys == MODEKEY_EMACS)
1.12 nicm 103: mode_key_init(&data->mdata, &mode_key_tree_emacs_copy);
1.10 nicm 104: else
1.12 nicm 105: mode_key_init(&data->mdata, &mode_key_tree_vi_copy);
1.1 nicm 106:
107: s->cx = data->cx;
108: s->cy = data->cy;
109:
110: screen_write_start(&ctx, NULL, s);
111: for (i = 0; i < screen_size_y(s); i++)
112: window_copy_write_line(wp, &ctx, i);
113: screen_write_cursormove(&ctx, data->cx, data->cy);
114: screen_write_stop(&ctx);
115:
116: return (s);
117: }
118:
119: void
120: window_copy_free(struct window_pane *wp)
121: {
122: struct window_copy_mode_data *data = wp->modedata;
123:
124: screen_free(&data->screen);
125: xfree(data);
126: }
127:
128: void
129: window_copy_pageup(struct window_pane *wp)
130: {
131: struct window_copy_mode_data *data = wp->modedata;
132: struct screen *s = &data->screen;
133:
134: if (data->oy + screen_size_y(s) > screen_hsize(&wp->base))
135: data->oy = screen_hsize(&wp->base);
136: else
137: data->oy += screen_size_y(s);
138: window_copy_update_selection(wp);
139: window_copy_redraw_screen(wp);
140: }
141:
142: void
143: window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
144: {
145: struct window_copy_mode_data *data = wp->modedata;
146: struct screen *s = &data->screen;
147: struct screen_write_ctx ctx;
148:
149: screen_resize(s, sx, sy);
1.18 ! nicm 150:
! 151: if (data->cy > sy - 1)
! 152: data->cy = sy - 1;
! 153: if (data->cx > sx)
! 154: data->cx = sx;
! 155:
! 156: screen_clear_selection(&data->screen);
! 157:
1.1 nicm 158: screen_write_start(&ctx, NULL, s);
159: window_copy_write_lines(wp, &ctx, 0, screen_size_y(s) - 1);
160: screen_write_stop(&ctx);
1.18 ! nicm 161:
1.17 nicm 162: window_copy_redraw_screen(wp);
1.1 nicm 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:
1.18 ! nicm 246: window_copy_update_cursor(wp, x, y);
1.1 nicm 247: if (window_copy_update_selection(wp))
248: window_copy_redraw_screen(wp);
249: }
250:
251: void
1.18 ! nicm 252: window_copy_write_line(
! 253: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
1.1 nicm 254: {
255: struct window_copy_mode_data *data = wp->modedata;
256: struct screen *s = &data->screen;
257: struct grid_cell gc;
258: char hdr[32];
259: size_t size;
260:
261: if (py == 0) {
262: memcpy(&gc, &grid_default_cell, sizeof gc);
263: size = xsnprintf(hdr, sizeof hdr,
1.18 ! nicm 264: "[%u/%u]", data->oy, screen_hsize(&wp->base));
1.14 nicm 265: gc.fg = options_get_number(&wp->window->options, "mode-fg");
266: gc.bg = options_get_number(&wp->window->options, "mode-bg");
1.18 ! nicm 267: gc.attr |= options_get_number(
! 268: &wp->window->options, "mode-attr");
1.1 nicm 269: screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
270: screen_write_puts(ctx, &gc, "%s", hdr);
271: } else
272: size = 0;
273:
274: screen_write_cursormove(ctx, 0, py);
1.18 ! nicm 275: screen_write_copy(ctx, &wp->base, 0, (screen_hsize(&wp->base) -
1.1 nicm 276: data->oy) + py, screen_size_x(s) - size, 1);
1.18 ! nicm 277:
! 278: if (py == data->cy && data->cx == screen_size_x(s)) {
! 279: memcpy(&gc, &grid_default_cell, sizeof gc);
! 280: screen_write_cursormove(ctx, screen_size_x(s) - 1, py);
! 281: screen_write_putc(ctx, &gc, '$');
! 282: }
1.1 nicm 283: }
284:
285: void
286: window_copy_write_lines(
287: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py, u_int ny)
288: {
289: u_int yy;
290:
291: for (yy = py; yy < py + ny; yy++)
292: window_copy_write_line(wp, ctx, py);
293: }
294:
295: void
296: window_copy_redraw_lines(struct window_pane *wp, u_int py, u_int ny)
297: {
298: struct window_copy_mode_data *data = wp->modedata;
299: struct screen_write_ctx ctx;
300: u_int i;
301:
302: screen_write_start(&ctx, wp, NULL);
303: for (i = py; i < py + ny; i++)
304: window_copy_write_line(wp, &ctx, i);
305: screen_write_cursormove(&ctx, data->cx, data->cy);
306: screen_write_stop(&ctx);
307: }
308:
309: void
310: window_copy_redraw_screen(struct window_pane *wp)
311: {
312: struct window_copy_mode_data *data = wp->modedata;
313:
314: window_copy_redraw_lines(wp, 0, screen_size_y(&data->screen));
315: }
316:
317: void
1.18 ! nicm 318: window_copy_update_cursor(struct window_pane *wp, u_int cx, u_int cy)
1.1 nicm 319: {
320: struct window_copy_mode_data *data = wp->modedata;
1.18 ! nicm 321: struct screen *s = &data->screen;
1.1 nicm 322: struct screen_write_ctx ctx;
1.18 ! nicm 323: u_int old_cx, old_cy;
1.1 nicm 324:
1.18 ! nicm 325: old_cx = data->cx; old_cy = data->cy;
! 326: data->cx = cx; data->cy = cy;
! 327: if (old_cx == screen_size_x(s))
! 328: window_copy_redraw_lines(wp, old_cy, 1);
! 329: if (data->cx == screen_size_x(s))
! 330: window_copy_redraw_lines(wp, data->cy, 1);
! 331: else {
! 332: screen_write_start(&ctx, wp, NULL);
! 333: screen_write_cursormove(&ctx, data->cx, data->cy);
! 334: screen_write_stop(&ctx);
! 335: }
1.1 nicm 336: }
337:
338: void
339: window_copy_start_selection(struct window_pane *wp)
340: {
341: struct window_copy_mode_data *data = wp->modedata;
342: struct screen *s = &data->screen;
343:
1.18 ! nicm 344: data->selx = data->cx;
1.1 nicm 345: data->sely = screen_hsize(&wp->base) + data->cy - data->oy;
346:
347: s->sel.flag = 1;
348: window_copy_update_selection(wp);
349: }
350:
351: int
352: window_copy_update_selection(struct window_pane *wp)
353: {
354: struct window_copy_mode_data *data = wp->modedata;
355: struct screen *s = &data->screen;
356: struct grid_cell gc;
1.18 ! nicm 357: u_int sx, sy, ty;
1.1 nicm 358:
359: if (!s->sel.flag)
360: return (0);
361:
362: /* Set colours. */
363: memcpy(&gc, &grid_default_cell, sizeof gc);
1.14 nicm 364: gc.fg = options_get_number(&wp->window->options, "mode-fg");
365: gc.bg = options_get_number(&wp->window->options, "mode-bg");
1.1 nicm 366: gc.attr |= options_get_number(&wp->window->options, "mode-attr");
367:
1.18 ! nicm 368: /* Find top of screen. */
1.1 nicm 369: ty = screen_hsize(&wp->base) - data->oy;
370:
371: /* Adjust the selection. */
372: sx = data->selx;
373: sy = data->sely;
1.18 ! nicm 374: if (sy < ty) { /* above screen */
1.1 nicm 375: sx = 0;
376: sy = 0;
1.18 ! nicm 377: } else if (sy > ty + screen_size_y(s) - 1) { /* below screen */
1.1 nicm 378: sx = screen_size_x(s) - 1;
379: sy = screen_size_y(s) - 1;
1.18 ! nicm 380: } else
1.1 nicm 381: sy -= ty;
382: sy = screen_hsize(s) + sy;
383:
384: screen_set_selection(
385: s, sx, sy, data->cx, screen_hsize(s) + data->cy, &gc);
386: return (1);
387: }
388:
389: void
390: window_copy_copy_selection(struct window_pane *wp, struct client *c)
391: {
392: struct window_copy_mode_data *data = wp->modedata;
393: struct screen *s = &data->screen;
394: char *buf;
395: size_t off;
396: u_int i, xx, yy, sx, sy, ex, ey, limit;
397:
398: if (!s->sel.flag)
399: return;
400:
401: buf = xmalloc(1);
402: off = 0;
403:
404: *buf = '\0';
405:
406: /*
407: * The selection extends from selx,sely to (adjusted) cx,cy on
408: * the base screen.
409: */
410:
411: /* Find start and end. */
1.18 ! nicm 412: xx = data->cx;
1.1 nicm 413: yy = screen_hsize(&wp->base) + data->cy - data->oy;
1.2 nicm 414: if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
1.1 nicm 415: sx = xx; sy = yy;
416: ex = data->selx; ey = data->sely;
417: } else {
418: sx = data->selx; sy = data->sely;
419: ex = xx; ey = yy;
420: }
421:
422: /* Trim ex to end of line. */
423: xx = window_copy_find_length(wp, ey);
424: if (ex > xx)
425: ex = xx;
426:
427: /* Copy the lines. */
428: if (sy == ey)
429: window_copy_copy_line(wp, &buf, &off, sy, sx, ex);
430: else {
1.16 nicm 431: xx = screen_size_x(s);
1.1 nicm 432: window_copy_copy_line(wp, &buf, &off, sy, sx, xx);
433: if (ey - sy > 1) {
1.16 nicm 434: for (i = sy + 1; i < ey; i++)
1.1 nicm 435: window_copy_copy_line(wp, &buf, &off, i, 0, xx);
436: }
437: window_copy_copy_line(wp, &buf, &off, ey, 0, ex);
438: }
439:
440: /* Terminate buffer, overwriting final \n. */
441: if (off != 0)
442: buf[off - 1] = '\0';
443:
444: /* Add the buffer to the stack. */
445: limit = options_get_number(&c->session->options, "buffer-limit");
446: paste_add(&c->session->buffers, buf, limit);
447: }
448:
449: void
450: window_copy_copy_line(struct window_pane *wp,
451: char **buf, size_t *off, u_int sy, u_int sx, u_int ex)
452: {
1.16 nicm 453: struct grid *gd = wp->base.grid;
1.1 nicm 454: const struct grid_cell *gc;
455: const struct grid_utf8 *gu;
1.16 nicm 456: struct grid_line *gl;
457: u_int i, j, xx, wrapped = 0;
1.1 nicm 458:
459: if (sx > ex)
460: return;
461:
1.16 nicm 462: /*
463: * Work out if the line was wrapped at the screen edge and all of it is
464: * on screen.
465: */
466: gl = &gd->linedata[sy];
467: if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
468: wrapped = 1;
469:
470: /* If the line was wrapped, don't strip spaces (use the full length). */
471: if (wrapped)
472: xx = gl->cellsize;
473: else
474: xx = window_copy_find_length(wp, sy);
1.1 nicm 475: if (ex > xx)
476: ex = xx;
477: if (sx > xx)
478: sx = xx;
479:
480: if (sx < ex) {
481: for (i = sx; i < ex; i++) {
1.16 nicm 482: gc = grid_peek_cell(gd, i, sy);
1.1 nicm 483: if (gc->flags & GRID_FLAG_PADDING)
484: continue;
485: if (!(gc->flags & GRID_FLAG_UTF8)) {
486: *buf = xrealloc(*buf, 1, (*off) + 1);
487: (*buf)[(*off)++] = gc->data;
488: } else {
1.16 nicm 489: gu = grid_peek_utf8(gd, i, sy);
1.1 nicm 490: *buf = xrealloc(*buf, 1, (*off) + UTF8_SIZE);
491: for (j = 0; j < UTF8_SIZE; j++) {
492: if (gu->data[j] == 0xff)
493: break;
494: (*buf)[(*off)++] = gu->data[j];
495: }
496: }
497: }
498: }
499:
1.16 nicm 500: /* Only add a newline if the line wasn't wrapped. */
501: if (!wrapped) {
502: *buf = xrealloc(*buf, 1, (*off) + 1);
503: (*buf)[(*off)++] = '\n';
504: }
1.1 nicm 505: }
506:
507: int
508: window_copy_is_space(struct window_pane *wp, u_int px, u_int py)
509: {
510: const struct grid_cell *gc;
511: const char *spaces = " -_@";
512:
513: gc = grid_peek_cell(wp->base.grid, px, py);
514: if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8))
515: return (0);
516: if (gc->data == 0x00 || gc->data == 0x7f)
517: return (0);
518: return (strchr(spaces, gc->data) != NULL);
519: }
520:
521: u_int
522: window_copy_find_length(struct window_pane *wp, u_int py)
523: {
524: const struct grid_cell *gc;
525: u_int px;
526:
1.4 nicm 527: /*
528: * If the pane has been resized, its grid can contain old overlong
529: * lines. grid_peek_cell does not allow accessing cells beyond the
530: * width of the grid, and screen_write_copy treats them as spaces, so
531: * ignore them here too.
532: */
1.15 nicm 533: px = wp->base.grid->linedata[py].cellsize;
1.4 nicm 534: if (px > screen_size_x(&wp->base))
535: px = screen_size_x(&wp->base);
1.1 nicm 536: while (px > 0) {
537: gc = grid_peek_cell(wp->base.grid, px - 1, py);
538: if (gc->flags & GRID_FLAG_UTF8)
539: break;
540: if (gc->data != ' ')
541: break;
542: px--;
543: }
544: return (px);
545: }
546:
547: void
1.5 nicm 548: window_copy_cursor_start_of_line(struct window_pane *wp)
549: {
550: struct window_copy_mode_data *data = wp->modedata;
551:
1.18 ! nicm 552: window_copy_update_cursor(wp, 0, data->cy);
1.5 nicm 553: if (window_copy_update_selection(wp))
554: window_copy_redraw_lines(wp, data->cy, 1);
1.6 nicm 555: }
556:
557: void
558: window_copy_cursor_back_to_indentation(struct window_pane *wp)
559: {
560: struct window_copy_mode_data *data = wp->modedata;
561: u_int px, py, xx;
562: const struct grid_cell *gc;
563:
564: px = 0;
565: py = screen_hsize(&wp->base) + data->cy - data->oy;
566: xx = window_copy_find_length(wp, py);
567:
568: /*
569: * Don't use window_copy_is_space because that treats some word
570: * delimiters as spaces.
571: */
572: while (px < xx) {
573: gc = grid_peek_cell(wp->base.grid, px, py);
574: if (gc->flags & GRID_FLAG_UTF8)
575: break;
576: if (gc->data != ' ')
577: break;
578: px++;
579: }
580:
1.18 ! nicm 581: window_copy_update_cursor(wp, px, data->cy);
! 582: if (window_copy_update_selection(wp))
! 583: window_copy_redraw_lines(wp, data->cy, 1);
1.5 nicm 584: }
585:
586: void
587: window_copy_cursor_end_of_line(struct window_pane *wp)
588: {
589: struct window_copy_mode_data *data = wp->modedata;
590: u_int px, py;
591:
592: py = screen_hsize(&wp->base) + data->cy - data->oy;
593: px = window_copy_find_length(wp, py);
594:
1.18 ! nicm 595: window_copy_update_cursor(wp, px, data->cy);
! 596: if (window_copy_update_selection(wp))
! 597: window_copy_redraw_lines(wp, data->cy, 1);
1.5 nicm 598: }
599:
600: void
1.1 nicm 601: window_copy_cursor_left(struct window_pane *wp)
602: {
603: struct window_copy_mode_data *data = wp->modedata;
604:
605: if (data->cx == 0) {
1.18 ! nicm 606: window_copy_cursor_up(wp);
! 607: window_copy_cursor_end_of_line(wp);
1.1 nicm 608: } else {
1.18 ! nicm 609: window_copy_update_cursor(wp, data->cx - 1, data->cy);
1.1 nicm 610: if (window_copy_update_selection(wp))
611: window_copy_redraw_lines(wp, data->cy, 1);
612: }
613: }
614:
615: void
616: window_copy_cursor_right(struct window_pane *wp)
617: {
618: struct window_copy_mode_data *data = wp->modedata;
619: u_int px, py;
620:
621: py = screen_hsize(&wp->base) + data->cy - data->oy;
622: px = window_copy_find_length(wp, py);
623:
624: if (data->cx >= px) {
625: window_copy_cursor_start_of_line(wp);
626: window_copy_cursor_down(wp);
627: } else {
1.18 ! nicm 628: window_copy_update_cursor(wp, data->cx + 1, data->cy);
1.1 nicm 629: if (window_copy_update_selection(wp))
630: window_copy_redraw_lines(wp, data->cy, 1);
631: }
632: }
633:
634: void
635: window_copy_cursor_up(struct window_pane *wp)
636: {
637: struct window_copy_mode_data *data = wp->modedata;
638: u_int ox, oy, px, py;
639:
640: oy = screen_hsize(&wp->base) + data->cy - data->oy;
641: ox = window_copy_find_length(wp, oy);
642:
643: if (data->cy == 0)
644: window_copy_scroll_down(wp, 1);
645: else {
1.18 ! nicm 646: window_copy_update_cursor(wp, data->cx, data->cy - 1);
1.1 nicm 647: if (window_copy_update_selection(wp))
648: window_copy_redraw_lines(wp, data->cy, 2);
649: }
650:
651: py = screen_hsize(&wp->base) + data->cy - data->oy;
652: px = window_copy_find_length(wp, py);
653:
1.18 ! nicm 654: if (data->cx >= px || data->cx >= ox)
1.1 nicm 655: window_copy_cursor_end_of_line(wp);
656: }
657:
658: void
659: window_copy_cursor_down(struct window_pane *wp)
660: {
661: struct window_copy_mode_data *data = wp->modedata;
662: struct screen *s = &data->screen;
663: u_int ox, oy, px, py;
664:
665: oy = screen_hsize(&wp->base) + data->cy - data->oy;
666: ox = window_copy_find_length(wp, oy);
667:
668: if (data->cy == screen_size_y(s) - 1)
669: window_copy_scroll_up(wp, 1);
670: else {
1.18 ! nicm 671: window_copy_update_cursor(wp, data->cx, data->cy + 1);
1.1 nicm 672: if (window_copy_update_selection(wp))
673: window_copy_redraw_lines(wp, data->cy - 1, 2);
674: }
675:
676: py = screen_hsize(&wp->base) + data->cy - data->oy;
677: px = window_copy_find_length(wp, py);
678:
1.18 ! nicm 679: if (data->cx >= px || data->cx >= ox)
1.1 nicm 680: window_copy_cursor_end_of_line(wp);
681: }
682:
683: void
684: window_copy_cursor_next_word(struct window_pane *wp)
685: {
686: struct window_copy_mode_data *data = wp->modedata;
687: struct screen *s = &data->screen;
688: u_int px, py, xx, skip;
689:
1.18 ! nicm 690: px = data->cx;
1.1 nicm 691: py = screen_hsize(&wp->base) + data->cy - data->oy;
692: xx = window_copy_find_length(wp, py);
693:
694: skip = 1;
695: if (px < xx) {
696: /* If currently on a space, skip space. */
697: if (window_copy_is_space(wp, px, py))
698: skip = 0;
699: } else
700: skip = 0;
701: for (;;) {
702: if (px >= xx) {
703: if (skip) {
704: px = xx;
705: break;
706: }
707:
708: while (px >= xx) {
709: if (data->cy == screen_size_y(s) - 1) {
710: if (data->oy == 0)
711: goto out;
712: }
713:
714: px = 0;
715: window_copy_cursor_down(wp);
716:
717: py =screen_hsize(
718: &wp->base) + data->cy - data->oy;
719: xx = window_copy_find_length(wp, py);
720: }
721: }
722:
723: if (skip) {
724: /* Currently skipping non-space (until space). */
725: if (window_copy_is_space(wp, px, py))
726: break;
727: } else {
728: /* Currently skipping space (until non-space). */
729: if (!window_copy_is_space(wp, px, py))
730: skip = 1;
731: }
732:
733: px++;
734: }
1.18 ! nicm 735:
1.1 nicm 736: out:
1.18 ! nicm 737: window_copy_update_cursor(wp, px, data->cy);
! 738: if (window_copy_update_selection(wp))
! 739: window_copy_redraw_lines(wp, data->cy, 1);
1.1 nicm 740: }
741:
1.8 nicm 742: /* Move to the previous place where a word begins. */
1.1 nicm 743: void
744: window_copy_cursor_previous_word(struct window_pane *wp)
745: {
746: struct window_copy_mode_data *data = wp->modedata;
1.8 nicm 747: u_int px, py;
1.1 nicm 748:
1.18 ! nicm 749: px = data->cx;
1.1 nicm 750: py = screen_hsize(&wp->base) + data->cy - data->oy;
751:
1.8 nicm 752: /* Move back to the previous word character. */
1.1 nicm 753: for (;;) {
1.8 nicm 754: if (px > 0) {
755: px--;
756: if (!window_copy_is_space(wp, px, py))
1.1 nicm 757: break;
1.8 nicm 758: } else {
759: if (data->cy == 0 &&
760: (screen_hsize(&wp->base) == 0 ||
761: data->oy >= screen_hsize(&wp->base) - 1))
762: goto out;
763: window_copy_cursor_up(wp);
1.1 nicm 764:
1.8 nicm 765: py = screen_hsize(
766: &wp->base) + data->cy - data->oy;
767: px = window_copy_find_length(wp, py);
1.1 nicm 768: }
1.8 nicm 769: }
1.1 nicm 770:
1.8 nicm 771: /* Move back to the beginning of this word. */
772: while (px > 0 && !window_copy_is_space(wp, px - 1, py))
1.1 nicm 773: px--;
1.8 nicm 774:
1.1 nicm 775: out:
1.18 ! nicm 776: window_copy_update_cursor(wp, px, data->cy);
! 777: if (window_copy_update_selection(wp))
! 778: window_copy_redraw_lines(wp, data->cy, 1);
1.1 nicm 779: }
780:
781: void
782: window_copy_scroll_up(struct window_pane *wp, u_int ny)
783: {
784: struct window_copy_mode_data *data = wp->modedata;
785: struct screen *s = &data->screen;
786: struct screen_write_ctx ctx;
787:
788: if (data->oy < ny)
789: ny = data->oy;
790: if (ny == 0)
791: return;
792: data->oy -= ny;
793: window_copy_update_selection(wp);
794:
795: screen_write_start(&ctx, wp, NULL);
796: screen_write_cursormove(&ctx, 0, 0);
797: screen_write_deleteline(&ctx, ny);
798: window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, ny);
799: window_copy_write_line(wp, &ctx, 0);
800: window_copy_write_line(wp, &ctx, 1);
801: if (s->sel.flag && screen_size_y(s) > ny)
802: window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1);
803: screen_write_cursormove(&ctx, data->cx, data->cy);
804: screen_write_stop(&ctx);
805: }
806:
807: void
808: window_copy_scroll_down(struct window_pane *wp, u_int ny)
809: {
810: struct window_copy_mode_data *data = wp->modedata;
811: struct screen *s = &data->screen;
812: struct screen_write_ctx ctx;
813:
814: if (ny > screen_hsize(&wp->base))
815: return;
816:
817: if (data->oy > screen_hsize(&wp->base) - ny)
818: ny = screen_hsize(&wp->base) - data->oy;
819: if (ny == 0)
820: return;
821: data->oy += ny;
822: window_copy_update_selection(wp);
823:
824: screen_write_start(&ctx, wp, NULL);
825: screen_write_cursormove(&ctx, 0, 0);
826: screen_write_insertline(&ctx, ny);
827: window_copy_write_lines(wp, &ctx, 0, ny);
828: if (s->sel.flag && screen_size_y(s) > ny)
829: window_copy_write_line(wp, &ctx, ny);
830: else if (ny == 1) /* nuke position */
831: window_copy_write_line(wp, &ctx, 1);
832: screen_write_cursormove(&ctx, data->cx, data->cy);
833: screen_write_stop(&ctx);
834: }