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