Annotation of src/usr.bin/tmux/window-copy.c, Revision 1.41
1.41 ! nicm 1: /* $OpenBSD: window-copy.c,v 1.40 2010/01/27 20:18:52 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:
1.21 nicm 21: #include <stdlib.h>
1.1 nicm 22: #include <string.h>
23:
24: #include "tmux.h"
25:
26: struct screen *window_copy_init(struct window_pane *);
27: void window_copy_free(struct window_pane *);
28: void window_copy_resize(struct window_pane *, u_int, u_int);
29: void window_copy_key(struct window_pane *, struct client *, int);
1.21 nicm 30: int window_copy_key_input(struct window_pane *, int);
1.1 nicm 31: void window_copy_mouse(
1.35 nicm 32: struct window_pane *, struct client *, struct mouse_event *);
1.1 nicm 33:
34: void window_copy_redraw_lines(struct window_pane *, u_int, u_int);
35: void window_copy_redraw_screen(struct window_pane *);
36: void window_copy_write_line(
1.35 nicm 37: struct window_pane *, struct screen_write_ctx *, u_int);
1.1 nicm 38: void window_copy_write_lines(
1.35 nicm 39: struct window_pane *, struct screen_write_ctx *, u_int, u_int);
1.1 nicm 40:
1.21 nicm 41: void window_copy_scroll_to(struct window_pane *, u_int, u_int);
42: int window_copy_search_compare(
43: struct grid *, u_int, u_int, struct grid *, u_int);
44: int window_copy_search_lr(
45: struct grid *, struct grid *, u_int *, u_int, u_int, u_int);
46: int window_copy_search_rl(
47: struct grid *, struct grid *, u_int *, u_int, u_int, u_int);
48: void window_copy_search_up(struct window_pane *, const char *);
49: void window_copy_search_down(struct window_pane *, const char *);
50: void window_copy_goto_line(struct window_pane *, const char *);
1.18 nicm 51: void window_copy_update_cursor(struct window_pane *, u_int, u_int);
1.1 nicm 52: void window_copy_start_selection(struct window_pane *);
53: int window_copy_update_selection(struct window_pane *);
54: void window_copy_copy_selection(struct window_pane *, struct client *);
55: void window_copy_copy_line(
56: struct window_pane *, char **, size_t *, u_int, u_int, u_int);
1.41 ! nicm 57: int window_copy_in_set(struct window_pane *, u_int, u_int, const char *);
1.1 nicm 58: u_int window_copy_find_length(struct window_pane *, u_int);
59: void window_copy_cursor_start_of_line(struct window_pane *);
1.6 nicm 60: void window_copy_cursor_back_to_indentation(struct window_pane *);
1.1 nicm 61: void window_copy_cursor_end_of_line(struct window_pane *);
62: void window_copy_cursor_left(struct window_pane *);
63: void window_copy_cursor_right(struct window_pane *);
1.28 nicm 64: void window_copy_cursor_up(struct window_pane *, int);
65: void window_copy_cursor_down(struct window_pane *, int);
1.41 ! nicm 66: void window_copy_cursor_next_word(struct window_pane *, const char *);
! 67: void window_copy_cursor_next_word_end(struct window_pane *, const char *);
! 68: void window_copy_cursor_previous_word(struct window_pane *, const char *);
1.1 nicm 69: void window_copy_scroll_up(struct window_pane *, u_int);
70: void window_copy_scroll_down(struct window_pane *, u_int);
71:
72: const struct window_mode window_copy_mode = {
73: window_copy_init,
74: window_copy_free,
75: window_copy_resize,
76: window_copy_key,
77: window_copy_mouse,
78: NULL,
79: };
80:
1.21 nicm 81: enum window_copy_input_type {
82: WINDOW_COPY_OFF,
83: WINDOW_COPY_SEARCHUP,
84: WINDOW_COPY_SEARCHDOWN,
85: WINDOW_COPY_GOTOLINE,
86: };
87:
1.1 nicm 88: struct window_copy_mode_data {
89: struct screen screen;
90:
1.21 nicm 91: struct mode_key_data mdata;
92:
93: u_int oy;
94:
95: u_int selx;
96: u_int sely;
1.1 nicm 97:
1.21 nicm 98: u_int cx;
99: u_int cy;
1.1 nicm 100:
1.25 nicm 101: u_int lastcx; /* position in last line with content */
102: u_int lastsx; /* size of last line with content */
103:
1.21 nicm 104: enum window_copy_input_type inputtype;
105: const char *inputprompt;
106: char *inputstr;
1.1 nicm 107:
1.21 nicm 108: enum window_copy_input_type searchtype;
109: char *searchstr;
1.1 nicm 110: };
111:
112: struct screen *
113: window_copy_init(struct window_pane *wp)
114: {
115: struct window_copy_mode_data *data;
116: struct screen *s;
117: struct screen_write_ctx ctx;
118: u_int i;
1.10 nicm 119: int keys;
1.1 nicm 120:
121: wp->modedata = data = xmalloc(sizeof *data);
122: data->oy = 0;
123: data->cx = wp->base.cx;
124: data->cy = wp->base.cy;
125:
1.25 nicm 126: data->lastcx = 0;
127: data->lastsx = 0;
128:
1.21 nicm 129: data->inputtype = WINDOW_COPY_OFF;
130: data->inputprompt = NULL;
131: data->inputstr = xstrdup("");
132:
133: data->searchtype = WINDOW_COPY_OFF;
134: data->searchstr = NULL;
135:
1.1 nicm 136: s = &data->screen;
137: screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
1.13 nicm 138: if (options_get_number(&wp->window->options, "mode-mouse"))
139: s->mode |= MODE_MOUSE;
1.1 nicm 140:
1.10 nicm 141: keys = options_get_number(&wp->window->options, "mode-keys");
142: if (keys == MODEKEY_EMACS)
1.12 nicm 143: mode_key_init(&data->mdata, &mode_key_tree_emacs_copy);
1.10 nicm 144: else
1.12 nicm 145: mode_key_init(&data->mdata, &mode_key_tree_vi_copy);
1.1 nicm 146:
147: s->cx = data->cx;
148: s->cy = data->cy;
149:
150: screen_write_start(&ctx, NULL, s);
151: for (i = 0; i < screen_size_y(s); i++)
152: window_copy_write_line(wp, &ctx, i);
153: screen_write_cursormove(&ctx, data->cx, data->cy);
154: screen_write_stop(&ctx);
155:
156: return (s);
157: }
158:
159: void
160: window_copy_free(struct window_pane *wp)
161: {
162: struct window_copy_mode_data *data = wp->modedata;
163:
1.21 nicm 164: if (data->searchstr != NULL)
165: xfree(data->searchstr);
166: xfree(data->inputstr);
167:
1.1 nicm 168: screen_free(&data->screen);
1.21 nicm 169:
1.1 nicm 170: xfree(data);
171: }
172:
173: void
174: window_copy_pageup(struct window_pane *wp)
175: {
176: struct window_copy_mode_data *data = wp->modedata;
177: struct screen *s = &data->screen;
1.19 nicm 178: u_int n;
1.1 nicm 179:
1.19 nicm 180: n = 1;
181: if (screen_size_y(s) > 2)
182: n = screen_size_y(s) - 2;
183: if (data->oy + n > screen_hsize(&wp->base))
1.1 nicm 184: data->oy = screen_hsize(&wp->base);
185: else
1.19 nicm 186: data->oy += n;
1.1 nicm 187: window_copy_update_selection(wp);
188: window_copy_redraw_screen(wp);
189: }
190:
191: void
192: window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
193: {
194: struct window_copy_mode_data *data = wp->modedata;
195: struct screen *s = &data->screen;
196: struct screen_write_ctx ctx;
197:
198: screen_resize(s, sx, sy);
1.35 nicm 199:
1.18 nicm 200: if (data->cy > sy - 1)
201: data->cy = sy - 1;
202: if (data->cx > sx)
203: data->cx = sx;
204:
205: screen_clear_selection(&data->screen);
206:
1.1 nicm 207: screen_write_start(&ctx, NULL, s);
208: window_copy_write_lines(wp, &ctx, 0, screen_size_y(s) - 1);
209: screen_write_stop(&ctx);
1.18 nicm 210:
1.17 nicm 211: window_copy_redraw_screen(wp);
1.1 nicm 212: }
213:
214: void
215: window_copy_key(struct window_pane *wp, struct client *c, int key)
216: {
1.41 ! nicm 217: const char *word_separators = " -_@";
1.1 nicm 218: struct window_copy_mode_data *data = wp->modedata;
219: struct screen *s = &data->screen;
1.19 nicm 220: u_int n;
1.21 nicm 221: int keys;
222:
223: if (data->inputtype != WINDOW_COPY_OFF) {
224: if (window_copy_key_input(wp, key) != 0)
225: goto input_off;
226: return;
227: }
1.1 nicm 228:
229: switch (mode_key_lookup(&data->mdata, key)) {
1.11 nicm 230: case MODEKEYCOPY_CANCEL:
1.1 nicm 231: window_pane_reset_mode(wp);
232: break;
1.10 nicm 233: case MODEKEYCOPY_LEFT:
1.1 nicm 234: window_copy_cursor_left(wp);
235: return;
1.10 nicm 236: case MODEKEYCOPY_RIGHT:
1.1 nicm 237: window_copy_cursor_right(wp);
1.35 nicm 238: return;
1.10 nicm 239: case MODEKEYCOPY_UP:
1.28 nicm 240: window_copy_cursor_up(wp, 0);
1.1 nicm 241: return;
1.10 nicm 242: case MODEKEYCOPY_DOWN:
1.28 nicm 243: window_copy_cursor_down(wp, 0);
1.1 nicm 244: return;
1.28 nicm 245: case MODEKEYCOPY_SCROLLUP:
246: window_copy_cursor_up(wp, 1);
247: break;
248: case MODEKEYCOPY_SCROLLDOWN:
249: window_copy_cursor_down(wp, 1);
250: break;
1.10 nicm 251: case MODEKEYCOPY_PREVIOUSPAGE:
1.1 nicm 252: window_copy_pageup(wp);
253: break;
1.10 nicm 254: case MODEKEYCOPY_NEXTPAGE:
1.19 nicm 255: n = 1;
256: if (screen_size_y(s) > 2)
257: n = screen_size_y(s) - 2;
1.20 nicm 258: if (data->oy < n)
259: data->oy = 0;
260: else
261: data->oy -= n;
262: window_copy_update_selection(wp);
263: window_copy_redraw_screen(wp);
264: break;
265: case MODEKEYCOPY_HALFPAGEUP:
266: n = screen_size_y(s) / 2;
267: if (data->oy + n > screen_hsize(&wp->base))
268: data->oy = screen_hsize(&wp->base);
269: else
270: data->oy += n;
271: window_copy_update_selection(wp);
272: window_copy_redraw_screen(wp);
273: break;
274: case MODEKEYCOPY_HALFPAGEDOWN:
275: n = screen_size_y(s) / 2;
1.19 nicm 276: if (data->oy < n)
1.1 nicm 277: data->oy = 0;
278: else
1.19 nicm 279: data->oy -= n;
1.30 nicm 280: window_copy_update_selection(wp);
281: window_copy_redraw_screen(wp);
282: break;
283: case MODEKEYCOPY_TOPLINE:
284: data->cx = 0;
285: data->cy = 0;
286: window_copy_update_selection(wp);
287: window_copy_redraw_screen(wp);
288: break;
289: case MODEKEYCOPY_MIDDLELINE:
290: data->cx = 0;
291: data->cy = (screen_size_y(s) - 1) / 2;
292: window_copy_update_selection(wp);
293: window_copy_redraw_screen(wp);
294: break;
295: case MODEKEYCOPY_BOTTOMLINE:
296: data->cx = 0;
297: data->cy = screen_size_y(s) - 1;
1.37 nicm 298: window_copy_update_selection(wp);
299: window_copy_redraw_screen(wp);
300: break;
301: case MODEKEYCOPY_HISTORYTOP:
302: data->cx = 0;
303: data->cy = 0;
304: data->oy = screen_hsize(&wp->base);
305: window_copy_update_selection(wp);
306: window_copy_redraw_screen(wp);
307: break;
308: case MODEKEYCOPY_HISTORYBOTTOM:
309: data->cx = 0;
310: data->cy = screen_size_y(s) - 1;
311: data->oy = 0;
1.1 nicm 312: window_copy_update_selection(wp);
313: window_copy_redraw_screen(wp);
314: break;
1.10 nicm 315: case MODEKEYCOPY_STARTSELECTION:
1.35 nicm 316: window_copy_start_selection(wp);
1.7 nicm 317: window_copy_redraw_screen(wp);
1.1 nicm 318: break;
1.10 nicm 319: case MODEKEYCOPY_CLEARSELECTION:
1.1 nicm 320: screen_clear_selection(&data->screen);
321: window_copy_redraw_screen(wp);
322: break;
1.10 nicm 323: case MODEKEYCOPY_COPYSELECTION:
1.1 nicm 324: if (c != NULL && c->session != NULL) {
325: window_copy_copy_selection(wp, c);
326: window_pane_reset_mode(wp);
327: }
328: break;
1.10 nicm 329: case MODEKEYCOPY_STARTOFLINE:
1.1 nicm 330: window_copy_cursor_start_of_line(wp);
331: break;
1.10 nicm 332: case MODEKEYCOPY_BACKTOINDENTATION:
1.6 nicm 333: window_copy_cursor_back_to_indentation(wp);
334: break;
1.10 nicm 335: case MODEKEYCOPY_ENDOFLINE:
1.1 nicm 336: window_copy_cursor_end_of_line(wp);
337: break;
1.41 ! nicm 338: case MODEKEYCOPY_NEXTSPACE:
! 339: window_copy_cursor_next_word(wp, " ");
! 340: break;
! 341: case MODEKEYCOPY_NEXTSPACEEND:
! 342: window_copy_cursor_next_word_end(wp, " ");
! 343: break;
1.10 nicm 344: case MODEKEYCOPY_NEXTWORD:
1.41 ! nicm 345: window_copy_cursor_next_word(wp, word_separators);
1.1 nicm 346: break;
1.40 nicm 347: case MODEKEYCOPY_NEXTWORDEND:
1.41 ! nicm 348: window_copy_cursor_next_word_end(wp, word_separators);
! 349: break;
! 350: case MODEKEYCOPY_PREVIOUSSPACE:
! 351: window_copy_cursor_previous_word(wp, " ");
1.40 nicm 352: break;
1.10 nicm 353: case MODEKEYCOPY_PREVIOUSWORD:
1.41 ! nicm 354: window_copy_cursor_previous_word(wp, word_separators);
1.1 nicm 355: break;
1.21 nicm 356: case MODEKEYCOPY_SEARCHUP:
357: data->inputtype = WINDOW_COPY_SEARCHUP;
358: data->inputprompt = "Search Up";
359: goto input_on;
360: case MODEKEYCOPY_SEARCHDOWN:
361: data->inputtype = WINDOW_COPY_SEARCHDOWN;
362: data->inputprompt = "Search Down";
363: goto input_on;
364: case MODEKEYCOPY_SEARCHAGAIN:
365: switch (data->searchtype) {
366: case WINDOW_COPY_OFF:
367: case WINDOW_COPY_GOTOLINE:
368: break;
369: case WINDOW_COPY_SEARCHUP:
370: window_copy_search_up(wp, data->searchstr);
371: break;
372: case WINDOW_COPY_SEARCHDOWN:
373: window_copy_search_down(wp, data->searchstr);
374: break;
375: }
376: break;
377: case MODEKEYCOPY_GOTOLINE:
378: data->inputtype = WINDOW_COPY_GOTOLINE;
379: data->inputprompt = "Goto Line";
380: *data->inputstr = '\0';
381: goto input_on;
382: default:
383: break;
384: }
385:
386: return;
387:
388: input_on:
389: keys = options_get_number(&wp->window->options, "mode-keys");
390: if (keys == MODEKEY_EMACS)
391: mode_key_init(&data->mdata, &mode_key_tree_emacs_edit);
392: else
393: mode_key_init(&data->mdata, &mode_key_tree_vi_edit);
394:
395: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
396: return;
397:
398: input_off:
399: keys = options_get_number(&wp->window->options, "mode-keys");
400: if (keys == MODEKEY_EMACS)
401: mode_key_init(&data->mdata, &mode_key_tree_emacs_copy);
402: else
403: mode_key_init(&data->mdata, &mode_key_tree_vi_copy);
404:
405: data->inputtype = WINDOW_COPY_OFF;
406: data->inputprompt = NULL;
407:
408: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
409: }
410:
411: int
412: window_copy_key_input(struct window_pane *wp, int key)
413: {
414: struct window_copy_mode_data *data = wp->modedata;
415: struct screen *s = &data->screen;
416: size_t inputlen;
417:
418: switch (mode_key_lookup(&data->mdata, key)) {
419: case MODEKEYEDIT_CANCEL:
420: return (-1);
421: case MODEKEYEDIT_BACKSPACE:
422: inputlen = strlen(data->inputstr);
423: if (inputlen > 0)
424: data->inputstr[inputlen - 1] = '\0';
1.22 nicm 425: break;
426: case MODEKEYEDIT_DELETELINE:
427: *data->inputstr = '\0';
1.21 nicm 428: break;
429: case MODEKEYEDIT_ENTER:
430: switch (data->inputtype) {
431: case WINDOW_COPY_OFF:
432: break;
433: case WINDOW_COPY_SEARCHUP:
434: window_copy_search_up(wp, data->inputstr);
435: data->searchtype = data->inputtype;
436: data->searchstr = xstrdup(data->inputstr);
437: break;
438: case WINDOW_COPY_SEARCHDOWN:
439: window_copy_search_down(wp, data->inputstr);
440: data->searchtype = data->inputtype;
441: data->searchstr = xstrdup(data->inputstr);
442: break;
443: case WINDOW_COPY_GOTOLINE:
444: window_copy_goto_line(wp, data->inputstr);
445: *data->inputstr = '\0';
446: break;
447: }
448: return (1);
449: case MODEKEY_OTHER:
450: if (key < 32 || key > 126)
451: break;
452: inputlen = strlen(data->inputstr) + 2;
1.35 nicm 453:
1.21 nicm 454: data->inputstr = xrealloc(data->inputstr, 1, inputlen);
455: data->inputstr[inputlen - 2] = key;
456: data->inputstr[inputlen - 1] = '\0';
457: break;
1.1 nicm 458: default:
459: break;
460: }
1.21 nicm 461:
462: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
463: return (0);
1.1 nicm 464: }
465:
1.34 nicm 466: /* ARGSUSED */
1.1 nicm 467: void
1.29 nicm 468: window_copy_mouse(
469: struct window_pane *wp, unused struct client *c, struct mouse_event *m)
1.1 nicm 470: {
471: struct window_copy_mode_data *data = wp->modedata;
472: struct screen *s = &data->screen;
473:
1.29 nicm 474: if ((m->b & 3) == 3)
1.1 nicm 475: return;
1.29 nicm 476: if (m->x >= screen_size_x(s))
1.1 nicm 477: return;
1.29 nicm 478: if (m->y >= screen_size_y(s))
1.1 nicm 479: return;
480:
1.29 nicm 481: window_copy_update_cursor(wp, m->x, m->y);
1.1 nicm 482: if (window_copy_update_selection(wp))
1.35 nicm 483: window_copy_redraw_screen(wp);
1.1 nicm 484: }
485:
486: void
1.21 nicm 487: window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py)
488: {
489: struct window_copy_mode_data *data = wp->modedata;
490: struct screen *s = &wp->base;
491: struct grid *gd = s->grid;
492: u_int offset, gap;
493:
494: data->cx = px;
495:
496: gap = gd->sy / 4;
497: if (py < gd->sy) {
498: offset = 0;
499: data->cy = py;
500: } else if (py > gd->hsize + gd->sy - gap) {
501: offset = gd->hsize;
502: data->cy = py - gd->hsize;
503: } else {
504: offset = py + gap - gd->sy;
505: data->cy = py - offset;
506: }
1.35 nicm 507: data->oy = gd->hsize - offset;
1.21 nicm 508:
1.38 nicm 509: window_copy_update_selection(wp);
1.21 nicm 510: window_copy_redraw_screen(wp);
511: }
512:
513: int
514: window_copy_search_compare(
515: struct grid *gd, u_int px, u_int py, struct grid *sgd, u_int spx)
516: {
517: const struct grid_cell *gc, *sgc;
518: const struct grid_utf8 *gu, *sgu;
519:
520: gc = grid_peek_cell(gd, px, py);
521: sgc = grid_peek_cell(sgd, spx, 0);
1.35 nicm 522:
1.21 nicm 523: if ((gc->flags & GRID_FLAG_UTF8) != (sgc->flags & GRID_FLAG_UTF8))
524: return (0);
525:
526: if (gc->flags & GRID_FLAG_UTF8) {
527: gu = grid_peek_utf8(gd, px, py);
528: sgu = grid_peek_utf8(sgd, spx, 0);
1.32 nicm 529: if (grid_utf8_compare(gu, sgu))
1.21 nicm 530: return (1);
531: } else {
532: if (gc->data == sgc->data)
533: return (1);
534: }
535: return (0);
536: }
537:
538: int
539: window_copy_search_lr(struct grid *gd,
540: struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last)
541: {
542: u_int ax, bx, px;
543:
544: for (ax = first; ax < last; ax++) {
545: if (ax + sgd->sx >= gd->sx)
546: break;
547: for (bx = 0; bx < sgd->sx; bx++) {
548: px = ax + bx;
549: if (!window_copy_search_compare(gd, px, py, sgd, bx))
550: break;
551: }
552: if (bx == sgd->sx) {
553: *ppx = ax;
554: return (1);
555: }
556: }
557: return (0);
558: }
559:
560: int
561: window_copy_search_rl(struct grid *gd,
562: struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last)
563: {
564: u_int ax, bx, px;
565:
566: for (ax = last + 1; ax > first; ax--) {
1.24 nicm 567: if (gd->sx - (ax - 1) < sgd->sx)
568: continue;
1.21 nicm 569: for (bx = 0; bx < sgd->sx; bx++) {
570: px = ax - 1 + bx;
571: if (!window_copy_search_compare(gd, px, py, sgd, bx))
572: break;
573: }
574: if (bx == sgd->sx) {
575: *ppx = ax - 1;
576: return (1);
577: }
578: }
579: return (0);
580: }
581:
582: void
583: window_copy_search_up(struct window_pane *wp, const char *searchstr)
584: {
585: struct window_copy_mode_data *data = wp->modedata;
586: struct screen *s = &wp->base, ss;
587: struct screen_write_ctx ctx;
588: struct grid *gd = s->grid, *sgd;
589: struct grid_cell gc;
590: size_t searchlen;
591: u_int i, last, fx, fy, px;
592: int utf8flag, n, wrapped;
593:
594: if (*searchstr == '\0')
595: return;
596: utf8flag = options_get_number(&wp->window->options, "utf8");
597: searchlen = screen_write_strlen(utf8flag, "%s", searchstr);
598:
599: screen_init(&ss, searchlen, 1, 0);
600: screen_write_start(&ctx, NULL, &ss);
601: memcpy(&gc, &grid_default_cell, sizeof gc);
602: screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr);
603: screen_write_stop(&ctx);
604:
605: fx = data->cx;
606: fy = gd->hsize - data->oy + data->cy;
607:
608: if (fx == 0) {
609: if (fy == 0)
610: return;
611: fx = gd->sx - 1;
612: fy--;
613: } else
614: fx--;
615: n = wrapped = 0;
616:
617: retry:
618: sgd = ss.grid;
619: for (i = fy + 1; i > 0; i--) {
620: last = screen_size_x(s);
621: if (i == fy + 1)
622: last = fx;
623: n = window_copy_search_rl(gd, sgd, &px, i - 1, 0, last);
624: if (n) {
625: window_copy_scroll_to(wp, px, i - 1);
626: break;
627: }
628: }
629: if (!n && !wrapped) {
630: fx = gd->sx - 1;
631: fy = gd->hsize + gd->sy - 1;
632: wrapped = 1;
633: goto retry;
634: }
635:
636: screen_free(&ss);
637: }
638:
639: void
640: window_copy_search_down(struct window_pane *wp, const char *searchstr)
641: {
642: struct window_copy_mode_data *data = wp->modedata;
643: struct screen *s = &wp->base, ss;
644: struct screen_write_ctx ctx;
645: struct grid *gd = s->grid, *sgd;
646: struct grid_cell gc;
647: size_t searchlen;
648: u_int i, first, fx, fy, px;
649: int utf8flag, n, wrapped;
650:
651: if (*searchstr == '\0')
652: return;
653: utf8flag = options_get_number(&wp->window->options, "utf8");
654: searchlen = screen_write_strlen(utf8flag, "%s", searchstr);
655:
656: screen_init(&ss, searchlen, 1, 0);
657: screen_write_start(&ctx, NULL, &ss);
658: memcpy(&gc, &grid_default_cell, sizeof gc);
659: screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr);
660: screen_write_stop(&ctx);
661:
662: fx = data->cx;
663: fy = gd->hsize - data->oy + data->cy;
664:
665: if (fx == gd->sx - 1) {
666: if (fy == gd->hsize + gd->sy)
667: return;
668: fx = 0;
669: fy++;
670: } else
671: fx++;
672: n = wrapped = 0;
673:
674: retry:
675: sgd = ss.grid;
676: for (i = fy + 1; i < gd->hsize + gd->sy; i++) {
677: first = 0;
678: if (i == fy + 1)
679: first = fx;
680: n = window_copy_search_lr(gd, sgd, &px, i - 1, first, gd->sx);
681: if (n) {
682: window_copy_scroll_to(wp, px, i - 1);
683: break;
684: }
685: }
686: if (!n && !wrapped) {
687: fx = 0;
688: fy = 0;
689: wrapped = 1;
690: goto retry;
691: }
692:
693: screen_free(&ss);
694: }
695:
696: void
697: window_copy_goto_line(struct window_pane *wp, const char *linestr)
698: {
699: struct window_copy_mode_data *data = wp->modedata;
700: const char *errstr;
701: u_int lineno;
702:
703: lineno = strtonum(linestr, 0, screen_hsize(&wp->base), &errstr);
704: if (errstr != NULL)
705: return;
1.35 nicm 706:
1.21 nicm 707: data->oy = lineno;
1.38 nicm 708: window_copy_update_selection(wp);
1.21 nicm 709: window_copy_redraw_screen(wp);
710: }
711:
712: void
1.18 nicm 713: window_copy_write_line(
714: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
1.1 nicm 715: {
716: struct window_copy_mode_data *data = wp->modedata;
717: struct screen *s = &data->screen;
1.27 nicm 718: struct options *oo = &wp->window->options;
1.1 nicm 719: struct grid_cell gc;
720: char hdr[32];
1.21 nicm 721: size_t last, xoff = 0, size = 0;
722:
723: memcpy(&gc, &grid_default_cell, sizeof gc);
1.27 nicm 724: colour_set_fg(&gc, options_get_number(oo, "mode-fg"));
725: colour_set_bg(&gc, options_get_number(oo, "mode-bg"));
726: gc.attr |= options_get_number(oo, "mode-attr");
1.1 nicm 727:
1.21 nicm 728: last = screen_size_y(s) - 1;
1.1 nicm 729: if (py == 0) {
730: size = xsnprintf(hdr, sizeof hdr,
1.18 nicm 731: "[%u/%u]", data->oy, screen_hsize(&wp->base));
1.1 nicm 732: screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
733: screen_write_puts(ctx, &gc, "%s", hdr);
1.21 nicm 734: } else if (py == last && data->inputtype != WINDOW_COPY_OFF) {
735: xoff = size = xsnprintf(hdr, sizeof hdr,
736: "%s: %s", data->inputprompt, data->inputstr);
737: screen_write_cursormove(ctx, 0, last);
738: screen_write_puts(ctx, &gc, "%s", hdr);
1.1 nicm 739: } else
740: size = 0;
741:
1.21 nicm 742: screen_write_cursormove(ctx, xoff, py);
743: screen_write_copy(ctx, &wp->base, xoff, (screen_hsize(&wp->base) -
1.1 nicm 744: data->oy) + py, screen_size_x(s) - size, 1);
1.18 nicm 745:
746: if (py == data->cy && data->cx == screen_size_x(s)) {
747: memcpy(&gc, &grid_default_cell, sizeof gc);
748: screen_write_cursormove(ctx, screen_size_x(s) - 1, py);
749: screen_write_putc(ctx, &gc, '$');
750: }
1.1 nicm 751: }
752:
753: void
754: window_copy_write_lines(
755: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py, u_int ny)
756: {
757: u_int yy;
758:
759: for (yy = py; yy < py + ny; yy++)
760: window_copy_write_line(wp, ctx, py);
761: }
762:
763: void
764: window_copy_redraw_lines(struct window_pane *wp, u_int py, u_int ny)
765: {
766: struct window_copy_mode_data *data = wp->modedata;
767: struct screen_write_ctx ctx;
768: u_int i;
769:
770: screen_write_start(&ctx, wp, NULL);
771: for (i = py; i < py + ny; i++)
772: window_copy_write_line(wp, &ctx, i);
773: screen_write_cursormove(&ctx, data->cx, data->cy);
774: screen_write_stop(&ctx);
775: }
776:
777: void
778: window_copy_redraw_screen(struct window_pane *wp)
779: {
780: struct window_copy_mode_data *data = wp->modedata;
781:
782: window_copy_redraw_lines(wp, 0, screen_size_y(&data->screen));
783: }
784:
785: void
1.18 nicm 786: window_copy_update_cursor(struct window_pane *wp, u_int cx, u_int cy)
1.1 nicm 787: {
788: struct window_copy_mode_data *data = wp->modedata;
1.18 nicm 789: struct screen *s = &data->screen;
1.1 nicm 790: struct screen_write_ctx ctx;
1.18 nicm 791: u_int old_cx, old_cy;
1.1 nicm 792:
1.18 nicm 793: old_cx = data->cx; old_cy = data->cy;
794: data->cx = cx; data->cy = cy;
795: if (old_cx == screen_size_x(s))
796: window_copy_redraw_lines(wp, old_cy, 1);
797: if (data->cx == screen_size_x(s))
798: window_copy_redraw_lines(wp, data->cy, 1);
799: else {
800: screen_write_start(&ctx, wp, NULL);
801: screen_write_cursormove(&ctx, data->cx, data->cy);
802: screen_write_stop(&ctx);
803: }
1.1 nicm 804: }
805:
806: void
807: window_copy_start_selection(struct window_pane *wp)
808: {
809: struct window_copy_mode_data *data = wp->modedata;
810: struct screen *s = &data->screen;
811:
1.18 nicm 812: data->selx = data->cx;
1.1 nicm 813: data->sely = screen_hsize(&wp->base) + data->cy - data->oy;
814:
815: s->sel.flag = 1;
816: window_copy_update_selection(wp);
817: }
818:
819: int
820: window_copy_update_selection(struct window_pane *wp)
821: {
822: struct window_copy_mode_data *data = wp->modedata;
823: struct screen *s = &data->screen;
1.27 nicm 824: struct options *oo = &wp->window->options;
1.1 nicm 825: struct grid_cell gc;
1.18 nicm 826: u_int sx, sy, ty;
1.1 nicm 827:
828: if (!s->sel.flag)
829: return (0);
830:
831: /* Set colours. */
832: memcpy(&gc, &grid_default_cell, sizeof gc);
1.27 nicm 833: colour_set_fg(&gc, options_get_number(oo, "mode-fg"));
834: colour_set_bg(&gc, options_get_number(oo, "mode-bg"));
835: gc.attr |= options_get_number(oo, "mode-attr");
1.1 nicm 836:
1.18 nicm 837: /* Find top of screen. */
1.1 nicm 838: ty = screen_hsize(&wp->base) - data->oy;
839:
840: /* Adjust the selection. */
841: sx = data->selx;
842: sy = data->sely;
1.18 nicm 843: if (sy < ty) { /* above screen */
1.1 nicm 844: sx = 0;
845: sy = 0;
1.18 nicm 846: } else if (sy > ty + screen_size_y(s) - 1) { /* below screen */
1.1 nicm 847: sx = screen_size_x(s) - 1;
848: sy = screen_size_y(s) - 1;
1.18 nicm 849: } else
1.1 nicm 850: sy -= ty;
851: sy = screen_hsize(s) + sy;
852:
853: screen_set_selection(
854: s, sx, sy, data->cx, screen_hsize(s) + data->cy, &gc);
855: return (1);
856: }
857:
858: void
859: window_copy_copy_selection(struct window_pane *wp, struct client *c)
860: {
861: struct window_copy_mode_data *data = wp->modedata;
862: struct screen *s = &data->screen;
863: char *buf;
864: size_t off;
865: u_int i, xx, yy, sx, sy, ex, ey, limit;
866:
867: if (!s->sel.flag)
868: return;
869:
870: buf = xmalloc(1);
871: off = 0;
872:
873: *buf = '\0';
874:
875: /*
876: * The selection extends from selx,sely to (adjusted) cx,cy on
877: * the base screen.
878: */
879:
880: /* Find start and end. */
1.18 nicm 881: xx = data->cx;
1.1 nicm 882: yy = screen_hsize(&wp->base) + data->cy - data->oy;
1.2 nicm 883: if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
1.1 nicm 884: sx = xx; sy = yy;
885: ex = data->selx; ey = data->sely;
886: } else {
887: sx = data->selx; sy = data->sely;
888: ex = xx; ey = yy;
889: }
890:
891: /* Trim ex to end of line. */
892: xx = window_copy_find_length(wp, ey);
893: if (ex > xx)
894: ex = xx;
895:
896: /* Copy the lines. */
897: if (sy == ey)
898: window_copy_copy_line(wp, &buf, &off, sy, sx, ex);
899: else {
1.16 nicm 900: xx = screen_size_x(s);
1.1 nicm 901: window_copy_copy_line(wp, &buf, &off, sy, sx, xx);
902: if (ey - sy > 1) {
1.16 nicm 903: for (i = sy + 1; i < ey; i++)
1.1 nicm 904: window_copy_copy_line(wp, &buf, &off, i, 0, xx);
905: }
906: window_copy_copy_line(wp, &buf, &off, ey, 0, ex);
907: }
908:
1.26 nicm 909: /* Don't bother if no data. */
910: if (off == 0) {
911: xfree(buf);
912: return;
913: }
914: off--; /* remove final \n */
1.1 nicm 915:
916: /* Add the buffer to the stack. */
917: limit = options_get_number(&c->session->options, "buffer-limit");
1.26 nicm 918: paste_add(&c->session->buffers, buf, off, limit);
1.1 nicm 919: }
920:
921: void
922: window_copy_copy_line(struct window_pane *wp,
923: char **buf, size_t *off, u_int sy, u_int sx, u_int ex)
924: {
1.16 nicm 925: struct grid *gd = wp->base.grid;
1.35 nicm 926: const struct grid_cell *gc;
927: const struct grid_utf8 *gu;
1.16 nicm 928: struct grid_line *gl;
1.32 nicm 929: u_int i, xx, wrapped = 0;
930: size_t size;
1.1 nicm 931:
932: if (sx > ex)
933: return;
934:
1.16 nicm 935: /*
936: * Work out if the line was wrapped at the screen edge and all of it is
937: * on screen.
938: */
939: gl = &gd->linedata[sy];
1.35 nicm 940: if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
1.16 nicm 941: wrapped = 1;
942:
943: /* If the line was wrapped, don't strip spaces (use the full length). */
944: if (wrapped)
945: xx = gl->cellsize;
946: else
947: xx = window_copy_find_length(wp, sy);
1.1 nicm 948: if (ex > xx)
949: ex = xx;
950: if (sx > xx)
951: sx = xx;
952:
953: if (sx < ex) {
954: for (i = sx; i < ex; i++) {
1.16 nicm 955: gc = grid_peek_cell(gd, i, sy);
1.1 nicm 956: if (gc->flags & GRID_FLAG_PADDING)
957: continue;
958: if (!(gc->flags & GRID_FLAG_UTF8)) {
959: *buf = xrealloc(*buf, 1, (*off) + 1);
960: (*buf)[(*off)++] = gc->data;
961: } else {
1.16 nicm 962: gu = grid_peek_utf8(gd, i, sy);
1.32 nicm 963: size = grid_utf8_size(gu);
964: *buf = xrealloc(*buf, 1, (*off) + size);
965: *off += grid_utf8_copy(gu, *buf + *off, size);
1.1 nicm 966: }
967: }
968: }
969:
1.16 nicm 970: /* Only add a newline if the line wasn't wrapped. */
1.35 nicm 971: if (!wrapped) {
1.16 nicm 972: *buf = xrealloc(*buf, 1, (*off) + 1);
973: (*buf)[(*off)++] = '\n';
974: }
1.1 nicm 975: }
976:
977: int
1.41 ! nicm 978: window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set)
1.1 nicm 979: {
980: const struct grid_cell *gc;
981:
982: gc = grid_peek_cell(wp->base.grid, px, py);
983: if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8))
984: return (0);
985: if (gc->data == 0x00 || gc->data == 0x7f)
986: return (0);
1.41 ! nicm 987: return (strchr(set, gc->data) != NULL);
1.1 nicm 988: }
989:
990: u_int
991: window_copy_find_length(struct window_pane *wp, u_int py)
992: {
993: const struct grid_cell *gc;
994: u_int px;
995:
1.4 nicm 996: /*
997: * If the pane has been resized, its grid can contain old overlong
998: * lines. grid_peek_cell does not allow accessing cells beyond the
999: * width of the grid, and screen_write_copy treats them as spaces, so
1000: * ignore them here too.
1001: */
1.15 nicm 1002: px = wp->base.grid->linedata[py].cellsize;
1.4 nicm 1003: if (px > screen_size_x(&wp->base))
1004: px = screen_size_x(&wp->base);
1.1 nicm 1005: while (px > 0) {
1006: gc = grid_peek_cell(wp->base.grid, px - 1, py);
1007: if (gc->flags & GRID_FLAG_UTF8)
1008: break;
1009: if (gc->data != ' ')
1010: break;
1011: px--;
1012: }
1013: return (px);
1014: }
1015:
1016: void
1.5 nicm 1017: window_copy_cursor_start_of_line(struct window_pane *wp)
1018: {
1019: struct window_copy_mode_data *data = wp->modedata;
1020:
1.18 nicm 1021: window_copy_update_cursor(wp, 0, data->cy);
1.5 nicm 1022: if (window_copy_update_selection(wp))
1023: window_copy_redraw_lines(wp, data->cy, 1);
1.6 nicm 1024: }
1025:
1026: void
1027: window_copy_cursor_back_to_indentation(struct window_pane *wp)
1028: {
1029: struct window_copy_mode_data *data = wp->modedata;
1030: u_int px, py, xx;
1031: const struct grid_cell *gc;
1032:
1033: px = 0;
1034: py = screen_hsize(&wp->base) + data->cy - data->oy;
1035: xx = window_copy_find_length(wp, py);
1036:
1037: while (px < xx) {
1038: gc = grid_peek_cell(wp->base.grid, px, py);
1039: if (gc->flags & GRID_FLAG_UTF8)
1040: break;
1041: if (gc->data != ' ')
1042: break;
1043: px++;
1044: }
1045:
1.18 nicm 1046: window_copy_update_cursor(wp, px, data->cy);
1047: if (window_copy_update_selection(wp))
1048: window_copy_redraw_lines(wp, data->cy, 1);
1.5 nicm 1049: }
1050:
1051: void
1052: window_copy_cursor_end_of_line(struct window_pane *wp)
1053: {
1054: struct window_copy_mode_data *data = wp->modedata;
1055: u_int px, py;
1056:
1057: py = screen_hsize(&wp->base) + data->cy - data->oy;
1058: px = window_copy_find_length(wp, py);
1059:
1.18 nicm 1060: window_copy_update_cursor(wp, px, data->cy);
1061: if (window_copy_update_selection(wp))
1062: window_copy_redraw_lines(wp, data->cy, 1);
1.5 nicm 1063: }
1064:
1065: void
1.1 nicm 1066: window_copy_cursor_left(struct window_pane *wp)
1067: {
1068: struct window_copy_mode_data *data = wp->modedata;
1069:
1070: if (data->cx == 0) {
1.28 nicm 1071: window_copy_cursor_up(wp, 0);
1.18 nicm 1072: window_copy_cursor_end_of_line(wp);
1.1 nicm 1073: } else {
1.18 nicm 1074: window_copy_update_cursor(wp, data->cx - 1, data->cy);
1.1 nicm 1075: if (window_copy_update_selection(wp))
1076: window_copy_redraw_lines(wp, data->cy, 1);
1077: }
1078: }
1079:
1080: void
1081: window_copy_cursor_right(struct window_pane *wp)
1082: {
1083: struct window_copy_mode_data *data = wp->modedata;
1084: u_int px, py;
1085:
1086: py = screen_hsize(&wp->base) + data->cy - data->oy;
1087: px = window_copy_find_length(wp, py);
1088:
1089: if (data->cx >= px) {
1090: window_copy_cursor_start_of_line(wp);
1.28 nicm 1091: window_copy_cursor_down(wp, 0);
1.1 nicm 1092: } else {
1.18 nicm 1093: window_copy_update_cursor(wp, data->cx + 1, data->cy);
1.1 nicm 1094: if (window_copy_update_selection(wp))
1095: window_copy_redraw_lines(wp, data->cy, 1);
1096: }
1097: }
1098:
1099: void
1.28 nicm 1100: window_copy_cursor_up(struct window_pane *wp, int scroll_only)
1.1 nicm 1101: {
1102: struct window_copy_mode_data *data = wp->modedata;
1.36 nicm 1103: struct screen *s = &data->screen;
1.1 nicm 1104: u_int ox, oy, px, py;
1105:
1106: oy = screen_hsize(&wp->base) + data->cy - data->oy;
1107: ox = window_copy_find_length(wp, oy);
1.25 nicm 1108: if (ox != 0) {
1109: data->lastcx = data->cx;
1110: data->lastsx = ox;
1111: }
1.1 nicm 1112:
1.25 nicm 1113: data->cx = data->lastcx;
1.28 nicm 1114: if (scroll_only || data->cy == 0) {
1.1 nicm 1115: window_copy_scroll_down(wp, 1);
1.36 nicm 1116: if (scroll_only) {
1117: if (data->cy == screen_size_y(s) - 1)
1118: window_copy_redraw_lines(wp, data->cy, 1);
1119: else
1120: window_copy_redraw_lines(wp, data->cy, 2);
1121: }
1.28 nicm 1122: } else {
1.18 nicm 1123: window_copy_update_cursor(wp, data->cx, data->cy - 1);
1.36 nicm 1124: if (window_copy_update_selection(wp)) {
1125: if (data->cy == screen_size_y(s) - 1)
1126: window_copy_redraw_lines(wp, data->cy, 1);
1127: else
1128: window_copy_redraw_lines(wp, data->cy, 2);
1129: }
1.1 nicm 1130: }
1131:
1132: py = screen_hsize(&wp->base) + data->cy - data->oy;
1133: px = window_copy_find_length(wp, py);
1.25 nicm 1134: if (data->cx >= data->lastsx || data->cx > px)
1.1 nicm 1135: window_copy_cursor_end_of_line(wp);
1136: }
1137:
1138: void
1.28 nicm 1139: window_copy_cursor_down(struct window_pane *wp, int scroll_only)
1.1 nicm 1140: {
1141: struct window_copy_mode_data *data = wp->modedata;
1142: struct screen *s = &data->screen;
1143: u_int ox, oy, px, py;
1144:
1145: oy = screen_hsize(&wp->base) + data->cy - data->oy;
1146: ox = window_copy_find_length(wp, oy);
1.25 nicm 1147: if (ox != 0) {
1148: data->lastcx = data->cx;
1149: data->lastsx = ox;
1150: }
1.1 nicm 1151:
1.25 nicm 1152: data->cx = data->lastcx;
1.28 nicm 1153: if (scroll_only || data->cy == screen_size_y(s) - 1) {
1.1 nicm 1154: window_copy_scroll_up(wp, 1);
1.31 nicm 1155: if (scroll_only && data->cy > 0)
1.28 nicm 1156: window_copy_redraw_lines(wp, data->cy - 1, 2);
1157: } else {
1.18 nicm 1158: window_copy_update_cursor(wp, data->cx, data->cy + 1);
1.1 nicm 1159: if (window_copy_update_selection(wp))
1160: window_copy_redraw_lines(wp, data->cy - 1, 2);
1161: }
1162:
1163: py = screen_hsize(&wp->base) + data->cy - data->oy;
1164: px = window_copy_find_length(wp, py);
1.25 nicm 1165: if (data->cx >= data->lastsx || data->cx > px)
1.1 nicm 1166: window_copy_cursor_end_of_line(wp);
1167: }
1168:
1169: void
1.41 ! nicm 1170: window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
1.40 nicm 1171: {
1172: struct window_copy_mode_data *data = wp->modedata;
1173: struct screen *base_s = &wp->base;
1174: u_int px, py, xx, yy;
1175:
1176: px = data->cx;
1177: py = screen_hsize(base_s) + data->cy - data->oy;
1178: xx = window_copy_find_length(wp, py);
1179: yy = screen_hsize(base_s) + screen_size_y(base_s) - 1;
1180:
1181: /* Are we in a word? Skip it! */
1.41 ! nicm 1182: while (!window_copy_in_set(wp, px, py, separators))
1.40 nicm 1183: px++;
1184:
1185: /* Find the start of a word. */
1.41 ! nicm 1186: while (px > xx || window_copy_in_set(wp, px, py, separators)) {
1.40 nicm 1187: /* Past the end of the line? Nothing but spaces. */
1188: if (px > xx) {
1189: if (py == yy)
1190: return;
1191: window_copy_cursor_down(wp, 0);
1192: px = 0;
1193:
1194: py = screen_hsize(base_s) + data->cy - data->oy;
1195: xx = window_copy_find_length(wp, py);
1196: }
1197: px++;
1198: }
1199:
1200: window_copy_update_cursor(wp, px, data->cy);
1201: if (window_copy_update_selection(wp))
1202: window_copy_redraw_lines(wp, data->cy, 1);
1203: }
1204:
1205: void
1.41 ! nicm 1206: window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators)
1.1 nicm 1207: {
1208: struct window_copy_mode_data *data = wp->modedata;
1.39 nicm 1209: struct screen *base_s = &wp->base;
1210: u_int px, py, xx, yy;
1.1 nicm 1211:
1.18 nicm 1212: px = data->cx;
1.39 nicm 1213: py = screen_hsize(base_s) + data->cy - data->oy;
1.1 nicm 1214: xx = window_copy_find_length(wp, py);
1.39 nicm 1215: yy = screen_hsize(base_s) + screen_size_y(base_s) - 1;
1.1 nicm 1216:
1.39 nicm 1217: /* Are we on spaces? Skip 'em! */
1.41 ! nicm 1218: while (px > xx || window_copy_in_set(wp, px, py, separators)) {
1.39 nicm 1219: /* Nothing but spaces past the end of the line, so move down. */
1220: if (px > xx) {
1221: if (py == yy)
1222: return;
1223: window_copy_cursor_down(wp, 0);
1224: px = 0;
1.1 nicm 1225:
1.39 nicm 1226: py = screen_hsize(base_s) + data->cy - data->oy;
1227: xx = window_copy_find_length(wp, py);
1.1 nicm 1228: }
1.39 nicm 1229: px++;
1230: }
1.1 nicm 1231:
1.39 nicm 1232: /* Find the end of this word. */
1.41 ! nicm 1233: while (!window_copy_in_set(wp, px, py, separators))
1.1 nicm 1234: px++;
1.18 nicm 1235:
1236: window_copy_update_cursor(wp, px, data->cy);
1237: if (window_copy_update_selection(wp))
1238: window_copy_redraw_lines(wp, data->cy, 1);
1.1 nicm 1239: }
1240:
1.8 nicm 1241: /* Move to the previous place where a word begins. */
1.1 nicm 1242: void
1.41 ! nicm 1243: window_copy_cursor_previous_word(struct window_pane *wp, const char *separators)
1.1 nicm 1244: {
1245: struct window_copy_mode_data *data = wp->modedata;
1.8 nicm 1246: u_int px, py;
1.1 nicm 1247:
1.18 nicm 1248: px = data->cx;
1.1 nicm 1249: py = screen_hsize(&wp->base) + data->cy - data->oy;
1250:
1.8 nicm 1251: /* Move back to the previous word character. */
1.1 nicm 1252: for (;;) {
1.8 nicm 1253: if (px > 0) {
1254: px--;
1.41 ! nicm 1255: if (!window_copy_in_set(wp, px, py, separators))
1.1 nicm 1256: break;
1.8 nicm 1257: } else {
1258: if (data->cy == 0 &&
1259: (screen_hsize(&wp->base) == 0 ||
1260: data->oy >= screen_hsize(&wp->base) - 1))
1261: goto out;
1.28 nicm 1262: window_copy_cursor_up(wp, 0);
1.1 nicm 1263:
1.39 nicm 1264: py = screen_hsize(&wp->base) + data->cy - data->oy;
1.8 nicm 1265: px = window_copy_find_length(wp, py);
1.1 nicm 1266: }
1.8 nicm 1267: }
1.1 nicm 1268:
1.8 nicm 1269: /* Move back to the beginning of this word. */
1.41 ! nicm 1270: while (px > 0 && !window_copy_in_set(wp, px - 1, py, separators))
1.1 nicm 1271: px--;
1.8 nicm 1272:
1.1 nicm 1273: out:
1.18 nicm 1274: window_copy_update_cursor(wp, px, data->cy);
1275: if (window_copy_update_selection(wp))
1276: window_copy_redraw_lines(wp, data->cy, 1);
1.1 nicm 1277: }
1278:
1279: void
1280: window_copy_scroll_up(struct window_pane *wp, u_int ny)
1281: {
1282: struct window_copy_mode_data *data = wp->modedata;
1283: struct screen *s = &data->screen;
1284: struct screen_write_ctx ctx;
1285:
1286: if (data->oy < ny)
1287: ny = data->oy;
1288: if (ny == 0)
1289: return;
1290: data->oy -= ny;
1291: window_copy_update_selection(wp);
1292:
1293: screen_write_start(&ctx, wp, NULL);
1294: screen_write_cursormove(&ctx, 0, 0);
1295: screen_write_deleteline(&ctx, ny);
1296: window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, ny);
1297: window_copy_write_line(wp, &ctx, 0);
1.31 nicm 1298: if (screen_size_y(s) > 1)
1299: window_copy_write_line(wp, &ctx, 1);
1300: if (screen_size_y(s) > 3)
1301: window_copy_write_line(wp, &ctx, screen_size_y(s) - 2);
1.1 nicm 1302: if (s->sel.flag && screen_size_y(s) > ny)
1303: window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1);
1304: screen_write_cursormove(&ctx, data->cx, data->cy);
1305: screen_write_stop(&ctx);
1306: }
1307:
1308: void
1309: window_copy_scroll_down(struct window_pane *wp, u_int ny)
1310: {
1311: struct window_copy_mode_data *data = wp->modedata;
1312: struct screen *s = &data->screen;
1313: struct screen_write_ctx ctx;
1314:
1315: if (ny > screen_hsize(&wp->base))
1316: return;
1317:
1318: if (data->oy > screen_hsize(&wp->base) - ny)
1319: ny = screen_hsize(&wp->base) - data->oy;
1320: if (ny == 0)
1321: return;
1322: data->oy += ny;
1323: window_copy_update_selection(wp);
1324:
1325: screen_write_start(&ctx, wp, NULL);
1326: screen_write_cursormove(&ctx, 0, 0);
1327: screen_write_insertline(&ctx, ny);
1328: window_copy_write_lines(wp, &ctx, 0, ny);
1329: if (s->sel.flag && screen_size_y(s) > ny)
1330: window_copy_write_line(wp, &ctx, ny);
1331: else if (ny == 1) /* nuke position */
1332: window_copy_write_line(wp, &ctx, 1);
1333: screen_write_cursormove(&ctx, data->cx, data->cy);
1334: screen_write_stop(&ctx);
1335: }