Annotation of src/usr.bin/tmux/window-copy.c, Revision 1.117
1.117 ! nicm 1: /* $OpenBSD: window-copy.c,v 1.116 2014/10/08 17:35:58 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.97 nicm 21: #include <ctype.h>
1.21 nicm 22: #include <stdlib.h>
1.1 nicm 23: #include <string.h>
24:
25: #include "tmux.h"
26:
27: struct screen *window_copy_init(struct window_pane *);
28: void window_copy_free(struct window_pane *);
29: void window_copy_resize(struct window_pane *, u_int, u_int);
1.56 nicm 30: void window_copy_key(struct window_pane *, struct session *, int);
1.21 nicm 31: int window_copy_key_input(struct window_pane *, int);
1.50 nicm 32: int window_copy_key_numeric_prefix(struct window_pane *, int);
1.1 nicm 33: void window_copy_mouse(
1.56 nicm 34: struct window_pane *, struct session *, struct mouse_event *);
1.1 nicm 35:
36: void window_copy_redraw_lines(struct window_pane *, u_int, u_int);
37: void window_copy_redraw_screen(struct window_pane *);
38: void window_copy_write_line(
1.35 nicm 39: struct window_pane *, struct screen_write_ctx *, u_int);
1.1 nicm 40: void window_copy_write_lines(
1.35 nicm 41: struct window_pane *, struct screen_write_ctx *, u_int, u_int);
1.1 nicm 42:
1.21 nicm 43: void window_copy_scroll_to(struct window_pane *, u_int, u_int);
44: int window_copy_search_compare(
1.97 nicm 45: struct grid *, u_int, u_int, struct grid *, u_int, int);
1.21 nicm 46: int window_copy_search_lr(
1.97 nicm 47: struct grid *, struct grid *, u_int *, u_int, u_int, u_int, int);
1.21 nicm 48: int window_copy_search_rl(
1.97 nicm 49: struct grid *, struct grid *, u_int *, u_int, u_int, u_int, int);
1.21 nicm 50: void window_copy_search_up(struct window_pane *, const char *);
51: void window_copy_search_down(struct window_pane *, const char *);
52: void window_copy_goto_line(struct window_pane *, const char *);
1.18 nicm 53: void window_copy_update_cursor(struct window_pane *, u_int, u_int);
1.1 nicm 54: void window_copy_start_selection(struct window_pane *);
1.96 nicm 55: int window_copy_update_selection(struct window_pane *, int);
1.89 nicm 56: void *window_copy_get_selection(struct window_pane *, size_t *);
1.108 nicm 57: void window_copy_copy_buffer(struct window_pane *, const char *, void *,
58: size_t);
59: void window_copy_copy_pipe(struct window_pane *, struct session *,
60: const char *, const char *);
61: void window_copy_copy_selection(struct window_pane *, const char *);
62: void window_copy_append_selection(struct window_pane *, const char *);
1.47 nicm 63: void window_copy_clear_selection(struct window_pane *);
1.109 nicm 64: void window_copy_copy_line(struct window_pane *, char **, size_t *, u_int,
65: u_int, u_int);
1.41 nicm 66: int window_copy_in_set(struct window_pane *, u_int, u_int, const char *);
1.1 nicm 67: u_int window_copy_find_length(struct window_pane *, u_int);
68: void window_copy_cursor_start_of_line(struct window_pane *);
1.6 nicm 69: void window_copy_cursor_back_to_indentation(struct window_pane *);
1.1 nicm 70: void window_copy_cursor_end_of_line(struct window_pane *);
1.95 nicm 71: void window_copy_other_end(struct window_pane *);
1.1 nicm 72: void window_copy_cursor_left(struct window_pane *);
73: void window_copy_cursor_right(struct window_pane *);
1.28 nicm 74: void window_copy_cursor_up(struct window_pane *, int);
75: void window_copy_cursor_down(struct window_pane *, int);
1.52 nicm 76: void window_copy_cursor_jump(struct window_pane *);
77: void window_copy_cursor_jump_back(struct window_pane *);
1.76 nicm 78: void window_copy_cursor_jump_to(struct window_pane *);
79: void window_copy_cursor_jump_to_back(struct window_pane *);
1.41 nicm 80: void window_copy_cursor_next_word(struct window_pane *, const char *);
81: void window_copy_cursor_next_word_end(struct window_pane *, const char *);
82: void window_copy_cursor_previous_word(struct window_pane *, const char *);
1.1 nicm 83: void window_copy_scroll_up(struct window_pane *, u_int);
84: void window_copy_scroll_down(struct window_pane *, u_int);
1.42 nicm 85: void window_copy_rectangle_toggle(struct window_pane *);
1.1 nicm 86:
87: const struct window_mode window_copy_mode = {
88: window_copy_init,
89: window_copy_free,
90: window_copy_resize,
91: window_copy_key,
92: window_copy_mouse,
93: NULL,
94: };
95:
1.21 nicm 96: enum window_copy_input_type {
97: WINDOW_COPY_OFF,
1.109 nicm 98: WINDOW_COPY_NAMEDBUFFER,
1.50 nicm 99: WINDOW_COPY_NUMERICPREFIX,
1.21 nicm 100: WINDOW_COPY_SEARCHUP,
101: WINDOW_COPY_SEARCHDOWN,
1.52 nicm 102: WINDOW_COPY_JUMPFORWARD,
103: WINDOW_COPY_JUMPBACK,
1.76 nicm 104: WINDOW_COPY_JUMPTOFORWARD,
105: WINDOW_COPY_JUMPTOBACK,
1.21 nicm 106: WINDOW_COPY_GOTOLINE,
107: };
108:
1.54 nicm 109: /*
110: * Copy-mode's visible screen (the "screen" field) is filled from one of
111: * two sources: the original contents of the pane (used when we
112: * actually enter via the "copy-mode" command, to copy the contents of
113: * the current pane), or else a series of lines containing the output
114: * from an output-writing tmux command (such as any of the "show-*" or
115: * "list-*" commands).
116: *
117: * In either case, the full content of the copy-mode grid is pointed at
118: * by the "backing" field, and is copied into "screen" as needed (that
119: * is, when scrolling occurs). When copy-mode is backed by a pane,
120: * backing points directly at that pane's screen structure (&wp->base);
121: * when backed by a list of output-lines from a command, it points at
122: * a newly-allocated screen structure (which is deallocated when the
123: * mode ends).
124: */
1.1 nicm 125: struct window_copy_mode_data {
126: struct screen screen;
127:
1.54 nicm 128: struct screen *backing;
129: int backing_written; /* backing display has started */
130:
1.21 nicm 131: struct mode_key_data mdata;
132:
133: u_int oy;
134:
135: u_int selx;
136: u_int sely;
1.1 nicm 137:
1.42 nicm 138: u_int rectflag; /* are we in rectangle copy mode? */
139:
1.21 nicm 140: u_int cx;
141: u_int cy;
1.1 nicm 142:
1.25 nicm 143: u_int lastcx; /* position in last line with content */
144: u_int lastsx; /* size of last line with content */
145:
1.21 nicm 146: enum window_copy_input_type inputtype;
147: const char *inputprompt;
1.76 nicm 148: char *inputstr;
1.1 nicm 149:
1.74 nicm 150: int numprefix;
1.50 nicm 151:
1.21 nicm 152: enum window_copy_input_type searchtype;
153: char *searchstr;
1.52 nicm 154:
155: enum window_copy_input_type jumptype;
156: char jumpchar;
1.1 nicm 157: };
158:
159: struct screen *
160: window_copy_init(struct window_pane *wp)
161: {
162: struct window_copy_mode_data *data;
163: struct screen *s;
1.10 nicm 164: int keys;
1.1 nicm 165:
166: wp->modedata = data = xmalloc(sizeof *data);
167: data->oy = 0;
1.54 nicm 168: data->cx = 0;
169: data->cy = 0;
1.1 nicm 170:
1.25 nicm 171: data->lastcx = 0;
172: data->lastsx = 0;
173:
1.54 nicm 174: data->backing_written = 0;
175:
1.42 nicm 176: data->rectflag = 0;
177:
1.21 nicm 178: data->inputtype = WINDOW_COPY_OFF;
179: data->inputprompt = NULL;
180: data->inputstr = xstrdup("");
1.74 nicm 181: data->numprefix = -1;
1.21 nicm 182:
183: data->searchtype = WINDOW_COPY_OFF;
184: data->searchstr = NULL;
185:
1.61 nicm 186: if (wp->fd != -1)
187: bufferevent_disable(wp->event, EV_READ|EV_WRITE);
1.46 nicm 188:
1.52 nicm 189: data->jumptype = WINDOW_COPY_OFF;
190: data->jumpchar = '\0';
191:
1.1 nicm 192: s = &data->screen;
193: screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
1.13 nicm 194: if (options_get_number(&wp->window->options, "mode-mouse"))
1.65 nicm 195: s->mode |= MODE_MOUSE_STANDARD;
1.1 nicm 196:
1.10 nicm 197: keys = options_get_number(&wp->window->options, "mode-keys");
198: if (keys == MODEKEY_EMACS)
1.12 nicm 199: mode_key_init(&data->mdata, &mode_key_tree_emacs_copy);
1.10 nicm 200: else
1.12 nicm 201: mode_key_init(&data->mdata, &mode_key_tree_vi_copy);
1.112 nicm 202: s->sel.modekeys = keys;
1.1 nicm 203:
1.54 nicm 204: data->backing = NULL;
205:
206: return (s);
207: }
208:
209: void
210: window_copy_init_from_pane(struct window_pane *wp)
211: {
212: struct window_copy_mode_data *data = wp->modedata;
213: struct screen *s = &data->screen;
214: struct screen_write_ctx ctx;
215: u_int i;
216:
217: if (wp->mode != &window_copy_mode)
218: fatalx("not in copy mode");
219:
220: data->backing = &wp->base;
221: data->cx = data->backing->cx;
222: data->cy = data->backing->cy;
223:
1.1 nicm 224: s->cx = data->cx;
225: s->cy = data->cy;
226:
227: screen_write_start(&ctx, NULL, s);
228: for (i = 0; i < screen_size_y(s); i++)
229: window_copy_write_line(wp, &ctx, i);
230: screen_write_cursormove(&ctx, data->cx, data->cy);
231: screen_write_stop(&ctx);
1.54 nicm 232: }
1.1 nicm 233:
1.54 nicm 234: void
235: window_copy_init_for_output(struct window_pane *wp)
236: {
237: struct window_copy_mode_data *data = wp->modedata;
238:
239: data->backing = xmalloc(sizeof *data->backing);
240: screen_init(data->backing, screen_size_x(&wp->base),
241: screen_size_y(&wp->base), UINT_MAX);
242: data->backing->mode &= ~MODE_WRAP;
1.1 nicm 243: }
244:
245: void
246: window_copy_free(struct window_pane *wp)
247: {
248: struct window_copy_mode_data *data = wp->modedata;
1.46 nicm 249:
1.61 nicm 250: if (wp->fd != -1)
251: bufferevent_enable(wp->event, EV_READ|EV_WRITE);
1.1 nicm 252:
1.81 nicm 253: free(data->searchstr);
254: free(data->inputstr);
1.21 nicm 255:
1.54 nicm 256: if (data->backing != &wp->base) {
257: screen_free(data->backing);
1.81 nicm 258: free(data->backing);
1.54 nicm 259: }
1.1 nicm 260: screen_free(&data->screen);
1.21 nicm 261:
1.81 nicm 262: free(data);
1.1 nicm 263: }
264:
265: void
1.54 nicm 266: window_copy_add(struct window_pane *wp, const char *fmt, ...)
267: {
268: va_list ap;
269:
270: va_start(ap, fmt);
271: window_copy_vadd(wp, fmt, ap);
272: va_end(ap);
273: }
274:
275: void
276: window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap)
277: {
278: struct window_copy_mode_data *data = wp->modedata;
279: struct screen *backing = data->backing;
280: struct screen_write_ctx back_ctx, ctx;
281: struct grid_cell gc;
282: int utf8flag;
283: u_int old_hsize;
284:
285: if (backing == &wp->base)
286: return;
287:
288: utf8flag = options_get_number(&wp->window->options, "utf8");
289: memcpy(&gc, &grid_default_cell, sizeof gc);
290:
291: old_hsize = screen_hsize(data->backing);
292: screen_write_start(&back_ctx, NULL, backing);
293: if (data->backing_written) {
294: /*
295: * On the second or later line, do a CRLF before writing
296: * (so it's on a new line).
297: */
298: screen_write_carriagereturn(&back_ctx);
299: screen_write_linefeed(&back_ctx, 0);
300: } else
301: data->backing_written = 1;
302: screen_write_vnputs(&back_ctx, 0, &gc, utf8flag, fmt, ap);
303: screen_write_stop(&back_ctx);
304:
305: data->oy += screen_hsize(data->backing) - old_hsize;
306:
307: screen_write_start(&ctx, wp, &data->screen);
308:
309: /*
310: * If the history has changed, draw the top line.
311: * (If there's any history at all, it has changed.)
312: */
313: if (screen_hsize(data->backing))
314: window_copy_redraw_lines(wp, 0, 1);
315:
316: /* Write the line, if it's visible. */
317: if (backing->cy + data->oy < screen_size_y(backing))
318: window_copy_redraw_lines(wp, backing->cy, 1);
319:
320: screen_write_stop(&ctx);
321: }
322:
323: void
1.1 nicm 324: window_copy_pageup(struct window_pane *wp)
325: {
326: struct window_copy_mode_data *data = wp->modedata;
327: struct screen *s = &data->screen;
1.19 nicm 328: u_int n;
1.1 nicm 329:
1.19 nicm 330: n = 1;
331: if (screen_size_y(s) > 2)
332: n = screen_size_y(s) - 2;
1.54 nicm 333: if (data->oy + n > screen_hsize(data->backing))
334: data->oy = screen_hsize(data->backing);
1.1 nicm 335: else
1.19 nicm 336: data->oy += n;
1.96 nicm 337: window_copy_update_selection(wp, 1);
1.1 nicm 338: window_copy_redraw_screen(wp);
339: }
340:
341: void
342: window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
343: {
344: struct window_copy_mode_data *data = wp->modedata;
345: struct screen *s = &data->screen;
346: struct screen_write_ctx ctx;
347:
1.87 nicm 348: screen_resize(s, sx, sy, 0);
1.54 nicm 349: if (data->backing != &wp->base)
1.87 nicm 350: screen_resize(data->backing, sx, sy, 0);
1.35 nicm 351:
1.18 nicm 352: if (data->cy > sy - 1)
353: data->cy = sy - 1;
354: if (data->cx > sx)
355: data->cx = sx;
1.63 nicm 356: if (data->oy > screen_hsize(data->backing))
357: data->oy = screen_hsize(data->backing);
1.18 nicm 358:
1.47 nicm 359: window_copy_clear_selection(wp);
1.18 nicm 360:
1.1 nicm 361: screen_write_start(&ctx, NULL, s);
362: window_copy_write_lines(wp, &ctx, 0, screen_size_y(s) - 1);
363: screen_write_stop(&ctx);
1.18 nicm 364:
1.17 nicm 365: window_copy_redraw_screen(wp);
1.1 nicm 366: }
367:
368: void
1.56 nicm 369: window_copy_key(struct window_pane *wp, struct session *sess, int key)
1.1 nicm 370: {
1.48 nicm 371: const char *word_separators;
1.1 nicm 372: struct window_copy_mode_data *data = wp->modedata;
373: struct screen *s = &data->screen;
1.74 nicm 374: u_int n;
375: int np, keys;
1.43 nicm 376: enum mode_key_cmd cmd;
1.89 nicm 377: const char *arg;
1.21 nicm 378:
1.50 nicm 379: np = data->numprefix;
1.74 nicm 380: if (np <= 0)
1.50 nicm 381: np = 1;
382:
1.67 nicm 383: if (data->inputtype == WINDOW_COPY_JUMPFORWARD ||
1.76 nicm 384: data->inputtype == WINDOW_COPY_JUMPBACK ||
385: data->inputtype == WINDOW_COPY_JUMPTOFORWARD ||
386: data->inputtype == WINDOW_COPY_JUMPTOBACK) {
1.52 nicm 387: /* Ignore keys with modifiers. */
1.59 nicm 388: if ((key & KEYC_MASK_MOD) == 0) {
1.52 nicm 389: data->jumpchar = key;
390: if (data->inputtype == WINDOW_COPY_JUMPFORWARD) {
391: for (; np != 0; np--)
392: window_copy_cursor_jump(wp);
1.76 nicm 393: } else if (data->inputtype == WINDOW_COPY_JUMPBACK) {
1.52 nicm 394: for (; np != 0; np--)
395: window_copy_cursor_jump_back(wp);
1.76 nicm 396: } else if (data->inputtype == WINDOW_COPY_JUMPTOFORWARD) {
397: for (; np != 0; np--)
398: window_copy_cursor_jump_to(wp);
399: } else if (data->inputtype == WINDOW_COPY_JUMPTOBACK) {
400: for (; np != 0; np--)
401: window_copy_cursor_jump_to_back(wp);
1.52 nicm 402: }
403: }
404: data->jumptype = data->inputtype;
405: data->inputtype = WINDOW_COPY_OFF;
406: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
407: return;
1.67 nicm 408: } else if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) {
1.50 nicm 409: if (window_copy_key_numeric_prefix(wp, key) == 0)
410: return;
411: data->inputtype = WINDOW_COPY_OFF;
412: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
413: } else if (data->inputtype != WINDOW_COPY_OFF) {
1.21 nicm 414: if (window_copy_key_input(wp, key) != 0)
415: goto input_off;
416: return;
417: }
1.1 nicm 418:
1.89 nicm 419: cmd = mode_key_lookup(&data->mdata, key, &arg);
1.43 nicm 420: switch (cmd) {
1.103 nicm 421: case MODEKEYCOPY_APPENDSELECTION:
422: if (sess != NULL) {
1.108 nicm 423: window_copy_append_selection(wp, NULL);
1.103 nicm 424: window_pane_reset_mode(wp);
425: return;
426: }
427: break;
1.11 nicm 428: case MODEKEYCOPY_CANCEL:
1.51 nicm 429: window_pane_reset_mode(wp);
430: return;
1.95 nicm 431: case MODEKEYCOPY_OTHEREND:
1.113 nicm 432: if (np % 2)
1.95 nicm 433: window_copy_other_end(wp);
434: break;
1.10 nicm 435: case MODEKEYCOPY_LEFT:
1.50 nicm 436: for (; np != 0; np--)
437: window_copy_cursor_left(wp);
438: break;
1.10 nicm 439: case MODEKEYCOPY_RIGHT:
1.50 nicm 440: for (; np != 0; np--)
441: window_copy_cursor_right(wp);
442: break;
1.10 nicm 443: case MODEKEYCOPY_UP:
1.50 nicm 444: for (; np != 0; np--)
445: window_copy_cursor_up(wp, 0);
446: break;
1.10 nicm 447: case MODEKEYCOPY_DOWN:
1.50 nicm 448: for (; np != 0; np--)
449: window_copy_cursor_down(wp, 0);
450: break;
1.28 nicm 451: case MODEKEYCOPY_SCROLLUP:
1.50 nicm 452: for (; np != 0; np--)
453: window_copy_cursor_up(wp, 1);
1.28 nicm 454: break;
455: case MODEKEYCOPY_SCROLLDOWN:
1.50 nicm 456: for (; np != 0; np--)
457: window_copy_cursor_down(wp, 1);
1.28 nicm 458: break;
1.10 nicm 459: case MODEKEYCOPY_PREVIOUSPAGE:
1.50 nicm 460: for (; np != 0; np--)
461: window_copy_pageup(wp);
1.1 nicm 462: break;
1.10 nicm 463: case MODEKEYCOPY_NEXTPAGE:
1.19 nicm 464: n = 1;
465: if (screen_size_y(s) > 2)
466: n = screen_size_y(s) - 2;
1.50 nicm 467: for (; np != 0; np--) {
468: if (data->oy < n)
469: data->oy = 0;
470: else
471: data->oy -= n;
472: }
1.96 nicm 473: window_copy_update_selection(wp, 1);
1.20 nicm 474: window_copy_redraw_screen(wp);
475: break;
476: case MODEKEYCOPY_HALFPAGEUP:
477: n = screen_size_y(s) / 2;
1.50 nicm 478: for (; np != 0; np--) {
1.54 nicm 479: if (data->oy + n > screen_hsize(data->backing))
480: data->oy = screen_hsize(data->backing);
1.50 nicm 481: else
482: data->oy += n;
483: }
1.96 nicm 484: window_copy_update_selection(wp, 1);
1.20 nicm 485: window_copy_redraw_screen(wp);
486: break;
487: case MODEKEYCOPY_HALFPAGEDOWN:
488: n = screen_size_y(s) / 2;
1.50 nicm 489: for (; np != 0; np--) {
490: if (data->oy < n)
491: data->oy = 0;
492: else
493: data->oy -= n;
494: }
1.96 nicm 495: window_copy_update_selection(wp, 1);
1.30 nicm 496: window_copy_redraw_screen(wp);
497: break;
498: case MODEKEYCOPY_TOPLINE:
499: data->cx = 0;
500: data->cy = 0;
1.96 nicm 501: window_copy_update_selection(wp, 1);
1.30 nicm 502: window_copy_redraw_screen(wp);
503: break;
504: case MODEKEYCOPY_MIDDLELINE:
505: data->cx = 0;
506: data->cy = (screen_size_y(s) - 1) / 2;
1.96 nicm 507: window_copy_update_selection(wp, 1);
1.30 nicm 508: window_copy_redraw_screen(wp);
509: break;
510: case MODEKEYCOPY_BOTTOMLINE:
511: data->cx = 0;
512: data->cy = screen_size_y(s) - 1;
1.96 nicm 513: window_copy_update_selection(wp, 1);
1.37 nicm 514: window_copy_redraw_screen(wp);
515: break;
516: case MODEKEYCOPY_HISTORYTOP:
517: data->cx = 0;
518: data->cy = 0;
1.54 nicm 519: data->oy = screen_hsize(data->backing);
1.96 nicm 520: window_copy_update_selection(wp, 1);
1.37 nicm 521: window_copy_redraw_screen(wp);
522: break;
523: case MODEKEYCOPY_HISTORYBOTTOM:
524: data->cx = 0;
525: data->cy = screen_size_y(s) - 1;
526: data->oy = 0;
1.96 nicm 527: window_copy_update_selection(wp, 1);
1.1 nicm 528: window_copy_redraw_screen(wp);
529: break;
1.10 nicm 530: case MODEKEYCOPY_STARTSELECTION:
1.35 nicm 531: window_copy_start_selection(wp);
1.7 nicm 532: window_copy_redraw_screen(wp);
1.71 nicm 533: break;
534: case MODEKEYCOPY_COPYLINE:
535: case MODEKEYCOPY_SELECTLINE:
536: window_copy_cursor_start_of_line(wp);
537: /* FALLTHROUGH */
538: case MODEKEYCOPY_COPYENDOFLINE:
539: window_copy_start_selection(wp);
540: for (; np > 1; np--)
541: window_copy_cursor_down(wp, 0);
542: window_copy_cursor_end_of_line(wp);
543: window_copy_redraw_screen(wp);
544:
545: /* If a copy command then copy the selection and exit. */
546: if (sess != NULL &&
547: (cmd == MODEKEYCOPY_COPYLINE ||
548: cmd == MODEKEYCOPY_COPYENDOFLINE)) {
1.108 nicm 549: window_copy_copy_selection(wp, NULL);
1.71 nicm 550: window_pane_reset_mode(wp);
551: return;
552: }
1.1 nicm 553: break;
1.10 nicm 554: case MODEKEYCOPY_CLEARSELECTION:
1.47 nicm 555: window_copy_clear_selection(wp);
1.1 nicm 556: window_copy_redraw_screen(wp);
557: break;
1.89 nicm 558: case MODEKEYCOPY_COPYPIPE:
559: if (sess != NULL) {
1.108 nicm 560: window_copy_copy_pipe(wp, sess, NULL, arg);
1.89 nicm 561: window_pane_reset_mode(wp);
562: return;
563: }
564: break;
1.10 nicm 565: case MODEKEYCOPY_COPYSELECTION:
1.56 nicm 566: if (sess != NULL) {
1.108 nicm 567: window_copy_copy_selection(wp, NULL);
1.1 nicm 568: window_pane_reset_mode(wp);
1.51 nicm 569: return;
1.1 nicm 570: }
571: break;
1.10 nicm 572: case MODEKEYCOPY_STARTOFLINE:
1.1 nicm 573: window_copy_cursor_start_of_line(wp);
574: break;
1.10 nicm 575: case MODEKEYCOPY_BACKTOINDENTATION:
1.6 nicm 576: window_copy_cursor_back_to_indentation(wp);
577: break;
1.10 nicm 578: case MODEKEYCOPY_ENDOFLINE:
1.1 nicm 579: window_copy_cursor_end_of_line(wp);
580: break;
1.41 nicm 581: case MODEKEYCOPY_NEXTSPACE:
1.50 nicm 582: for (; np != 0; np--)
583: window_copy_cursor_next_word(wp, " ");
1.41 nicm 584: break;
585: case MODEKEYCOPY_NEXTSPACEEND:
1.50 nicm 586: for (; np != 0; np--)
587: window_copy_cursor_next_word_end(wp, " ");
1.41 nicm 588: break;
1.10 nicm 589: case MODEKEYCOPY_NEXTWORD:
1.48 nicm 590: word_separators =
1.75 nicm 591: options_get_string(&sess->options, "word-separators");
1.50 nicm 592: for (; np != 0; np--)
593: window_copy_cursor_next_word(wp, word_separators);
1.1 nicm 594: break;
1.40 nicm 595: case MODEKEYCOPY_NEXTWORDEND:
1.48 nicm 596: word_separators =
1.75 nicm 597: options_get_string(&sess->options, "word-separators");
1.50 nicm 598: for (; np != 0; np--)
599: window_copy_cursor_next_word_end(wp, word_separators);
1.41 nicm 600: break;
601: case MODEKEYCOPY_PREVIOUSSPACE:
1.50 nicm 602: for (; np != 0; np--)
603: window_copy_cursor_previous_word(wp, " ");
1.40 nicm 604: break;
1.10 nicm 605: case MODEKEYCOPY_PREVIOUSWORD:
1.48 nicm 606: word_separators =
1.75 nicm 607: options_get_string(&sess->options, "word-separators");
1.50 nicm 608: for (; np != 0; np--)
609: window_copy_cursor_previous_word(wp, word_separators);
1.1 nicm 610: break;
1.52 nicm 611: case MODEKEYCOPY_JUMP:
612: data->inputtype = WINDOW_COPY_JUMPFORWARD;
613: data->inputprompt = "Jump Forward";
614: *data->inputstr = '\0';
615: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
616: return; /* skip numprefix reset */
617: case MODEKEYCOPY_JUMPAGAIN:
618: if (data->jumptype == WINDOW_COPY_JUMPFORWARD) {
619: for (; np != 0; np--)
620: window_copy_cursor_jump(wp);
621: } else if (data->jumptype == WINDOW_COPY_JUMPBACK) {
622: for (; np != 0; np--)
623: window_copy_cursor_jump_back(wp);
1.76 nicm 624: } else if (data->jumptype == WINDOW_COPY_JUMPTOFORWARD) {
625: for (; np != 0; np--)
626: window_copy_cursor_jump_to(wp);
627: } else if (data->jumptype == WINDOW_COPY_JUMPTOBACK) {
628: for (; np != 0; np--)
629: window_copy_cursor_jump_to_back(wp);
1.52 nicm 630: }
631: break;
632: case MODEKEYCOPY_JUMPREVERSE:
633: if (data->jumptype == WINDOW_COPY_JUMPFORWARD) {
634: for (; np != 0; np--)
635: window_copy_cursor_jump_back(wp);
636: } else if (data->jumptype == WINDOW_COPY_JUMPBACK) {
637: for (; np != 0; np--)
638: window_copy_cursor_jump(wp);
1.76 nicm 639: } else if (data->jumptype == WINDOW_COPY_JUMPTOFORWARD) {
640: for (; np != 0; np--)
641: window_copy_cursor_jump_to_back(wp);
642: } else if (data->jumptype == WINDOW_COPY_JUMPTOBACK) {
643: for (; np != 0; np--)
644: window_copy_cursor_jump_to(wp);
1.52 nicm 645: }
646: break;
647: case MODEKEYCOPY_JUMPBACK:
648: data->inputtype = WINDOW_COPY_JUMPBACK;
649: data->inputprompt = "Jump Back";
650: *data->inputstr = '\0';
651: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
652: return; /* skip numprefix reset */
1.76 nicm 653: case MODEKEYCOPY_JUMPTO:
654: data->inputtype = WINDOW_COPY_JUMPTOFORWARD;
655: data->inputprompt = "Jump To";
656: *data->inputstr = '\0';
657: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
658: return; /* skip numprefix reset */
659: case MODEKEYCOPY_JUMPTOBACK:
660: data->inputtype = WINDOW_COPY_JUMPTOBACK;
661: data->inputprompt = "Jump To Back";
662: *data->inputstr = '\0';
663: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
664: return; /* skip numprefix reset */
1.21 nicm 665: case MODEKEYCOPY_SEARCHUP:
666: data->inputtype = WINDOW_COPY_SEARCHUP;
667: data->inputprompt = "Search Up";
668: goto input_on;
669: case MODEKEYCOPY_SEARCHDOWN:
670: data->inputtype = WINDOW_COPY_SEARCHDOWN;
671: data->inputprompt = "Search Down";
672: goto input_on;
673: case MODEKEYCOPY_SEARCHAGAIN:
1.43 nicm 674: case MODEKEYCOPY_SEARCHREVERSE:
1.21 nicm 675: switch (data->searchtype) {
676: case WINDOW_COPY_OFF:
677: case WINDOW_COPY_GOTOLINE:
1.52 nicm 678: case WINDOW_COPY_JUMPFORWARD:
679: case WINDOW_COPY_JUMPBACK:
1.76 nicm 680: case WINDOW_COPY_JUMPTOFORWARD:
681: case WINDOW_COPY_JUMPTOBACK:
1.109 nicm 682: case WINDOW_COPY_NAMEDBUFFER:
1.50 nicm 683: case WINDOW_COPY_NUMERICPREFIX:
1.21 nicm 684: break;
685: case WINDOW_COPY_SEARCHUP:
1.50 nicm 686: if (cmd == MODEKEYCOPY_SEARCHAGAIN) {
687: for (; np != 0; np--) {
688: window_copy_search_up(
689: wp, data->searchstr);
690: }
691: } else {
692: for (; np != 0; np--) {
693: window_copy_search_down(
694: wp, data->searchstr);
695: }
696: }
1.21 nicm 697: break;
698: case WINDOW_COPY_SEARCHDOWN:
1.50 nicm 699: if (cmd == MODEKEYCOPY_SEARCHAGAIN) {
700: for (; np != 0; np--) {
701: window_copy_search_down(
702: wp, data->searchstr);
703: }
704: } else {
705: for (; np != 0; np--) {
706: window_copy_search_up(
707: wp, data->searchstr);
708: }
709: }
1.21 nicm 710: break;
711: }
712: break;
713: case MODEKEYCOPY_GOTOLINE:
714: data->inputtype = WINDOW_COPY_GOTOLINE;
715: data->inputprompt = "Goto Line";
716: *data->inputstr = '\0';
717: goto input_on;
1.109 nicm 718: case MODEKEYCOPY_STARTNAMEDBUFFER:
719: data->inputtype = WINDOW_COPY_NAMEDBUFFER;
720: data->inputprompt = "Buffer";
721: *data->inputstr = '\0';
722: goto input_on;
1.50 nicm 723: case MODEKEYCOPY_STARTNUMBERPREFIX:
1.59 nicm 724: key &= KEYC_MASK_KEY;
1.50 nicm 725: if (key >= '0' && key <= '9') {
726: data->inputtype = WINDOW_COPY_NUMERICPREFIX;
727: data->numprefix = 0;
728: window_copy_key_numeric_prefix(wp, key);
729: return;
730: }
731: break;
1.42 nicm 732: case MODEKEYCOPY_RECTANGLETOGGLE:
733: window_copy_rectangle_toggle(wp);
1.50 nicm 734: break;
1.21 nicm 735: default:
736: break;
737: }
738:
1.74 nicm 739: data->numprefix = -1;
1.21 nicm 740: return;
741:
742: input_on:
743: keys = options_get_number(&wp->window->options, "mode-keys");
744: if (keys == MODEKEY_EMACS)
745: mode_key_init(&data->mdata, &mode_key_tree_emacs_edit);
746: else
747: mode_key_init(&data->mdata, &mode_key_tree_vi_edit);
748:
749: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
750: return;
751:
752: input_off:
753: keys = options_get_number(&wp->window->options, "mode-keys");
754: if (keys == MODEKEY_EMACS)
755: mode_key_init(&data->mdata, &mode_key_tree_emacs_copy);
756: else
757: mode_key_init(&data->mdata, &mode_key_tree_vi_copy);
758:
759: data->inputtype = WINDOW_COPY_OFF;
760: data->inputprompt = NULL;
761:
762: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
763: }
764:
765: int
766: window_copy_key_input(struct window_pane *wp, int key)
767: {
768: struct window_copy_mode_data *data = wp->modedata;
769: struct screen *s = &data->screen;
1.100 nicm 770: size_t inputlen, n;
1.74 nicm 771: int np;
1.100 nicm 772: struct paste_buffer *pb;
773: u_char ch;
1.21 nicm 774:
1.89 nicm 775: switch (mode_key_lookup(&data->mdata, key, NULL)) {
1.21 nicm 776: case MODEKEYEDIT_CANCEL:
1.74 nicm 777: data->numprefix = -1;
1.21 nicm 778: return (-1);
779: case MODEKEYEDIT_BACKSPACE:
780: inputlen = strlen(data->inputstr);
781: if (inputlen > 0)
782: data->inputstr[inputlen - 1] = '\0';
1.22 nicm 783: break;
784: case MODEKEYEDIT_DELETELINE:
785: *data->inputstr = '\0';
1.21 nicm 786: break;
1.100 nicm 787: case MODEKEYEDIT_PASTE:
1.107 nicm 788: if ((pb = paste_get_top()) == NULL)
1.100 nicm 789: break;
790: for (n = 0; n < pb->size; n++) {
791: ch = (u_char) pb->data[n];
792: if (ch < 32 || ch == 127)
793: break;
794: }
795: inputlen = strlen(data->inputstr);
796:
1.116 nicm 797: data->inputstr = xrealloc(data->inputstr, inputlen + n + 1);
1.100 nicm 798: memcpy(data->inputstr + inputlen, pb->data, n);
799: data->inputstr[inputlen + n] = '\0';
800: break;
1.21 nicm 801: case MODEKEYEDIT_ENTER:
1.50 nicm 802: np = data->numprefix;
1.74 nicm 803: if (np <= 0)
1.50 nicm 804: np = 1;
805:
1.21 nicm 806: switch (data->inputtype) {
807: case WINDOW_COPY_OFF:
1.52 nicm 808: case WINDOW_COPY_JUMPFORWARD:
809: case WINDOW_COPY_JUMPBACK:
1.76 nicm 810: case WINDOW_COPY_JUMPTOFORWARD:
811: case WINDOW_COPY_JUMPTOBACK:
1.50 nicm 812: case WINDOW_COPY_NUMERICPREFIX:
1.21 nicm 813: break;
814: case WINDOW_COPY_SEARCHUP:
1.50 nicm 815: for (; np != 0; np--)
816: window_copy_search_up(wp, data->inputstr);
1.21 nicm 817: data->searchtype = data->inputtype;
818: data->searchstr = xstrdup(data->inputstr);
819: break;
820: case WINDOW_COPY_SEARCHDOWN:
1.50 nicm 821: for (; np != 0; np--)
822: window_copy_search_down(wp, data->inputstr);
1.21 nicm 823: data->searchtype = data->inputtype;
824: data->searchstr = xstrdup(data->inputstr);
825: break;
1.109 nicm 826: case WINDOW_COPY_NAMEDBUFFER:
827: window_copy_copy_selection(wp, data->inputstr);
828: *data->inputstr = '\0';
829: window_pane_reset_mode(wp);
830: return (0);
1.21 nicm 831: case WINDOW_COPY_GOTOLINE:
832: window_copy_goto_line(wp, data->inputstr);
833: *data->inputstr = '\0';
834: break;
835: }
1.74 nicm 836: data->numprefix = -1;
1.21 nicm 837: return (1);
838: case MODEKEY_OTHER:
839: if (key < 32 || key > 126)
840: break;
841: inputlen = strlen(data->inputstr) + 2;
1.35 nicm 842:
1.116 nicm 843: data->inputstr = xrealloc(data->inputstr, inputlen);
1.21 nicm 844: data->inputstr[inputlen - 2] = key;
845: data->inputstr[inputlen - 1] = '\0';
846: break;
1.1 nicm 847: default:
848: break;
849: }
1.21 nicm 850:
851: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
852: return (0);
1.1 nicm 853: }
854:
1.50 nicm 855: int
856: window_copy_key_numeric_prefix(struct window_pane *wp, int key)
857: {
858: struct window_copy_mode_data *data = wp->modedata;
859: struct screen *s = &data->screen;
860:
1.59 nicm 861: key &= KEYC_MASK_KEY;
1.50 nicm 862: if (key < '0' || key > '9')
1.80 nicm 863: return (1);
1.50 nicm 864:
1.74 nicm 865: if (data->numprefix >= 100) /* no more than three digits */
1.80 nicm 866: return (0);
1.50 nicm 867: data->numprefix = data->numprefix * 10 + key - '0';
868:
869: window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
1.80 nicm 870: return (0);
1.50 nicm 871: }
872:
1.1 nicm 873: void
1.29 nicm 874: window_copy_mouse(
1.68 nicm 875: struct window_pane *wp, struct session *sess, struct mouse_event *m)
1.1 nicm 876: {
877: struct window_copy_mode_data *data = wp->modedata;
878: struct screen *s = &data->screen;
1.79 nicm 879: u_int i;
1.57 nicm 880:
1.29 nicm 881: if (m->x >= screen_size_x(s))
1.1 nicm 882: return;
1.29 nicm 883: if (m->y >= screen_size_y(s))
1.1 nicm 884: return;
885:
1.57 nicm 886: /* If mouse wheel (buttons 4 and 5), scroll. */
1.84 nicm 887: if (m->event == MOUSE_EVENT_WHEEL) {
1.104 nicm 888: for (i = 0; i < m->scroll; i++) {
889: if (m->wheel == MOUSE_WHEEL_UP)
1.85 nicm 890: window_copy_cursor_up(wp, 1);
1.104 nicm 891: else {
1.85 nicm 892: window_copy_cursor_down(wp, 1);
1.104 nicm 893:
894: /*
895: * We reached the bottom, leave copy mode, but
896: * only if no selection is in progress.
897: */
898: if (data->oy == 0 && !s->sel.flag)
899: goto reset_mode;
900: }
1.57 nicm 901: }
902: return;
903: }
904:
905: /*
906: * If already reading motion, move the cursor while buttons are still
907: * pressed, or stop the selection on their release.
908: */
1.70 nicm 909: if (s->mode & MODE_MOUSE_BUTTON) {
1.84 nicm 910: if (~m->event & MOUSE_EVENT_UP) {
1.57 nicm 911: window_copy_update_cursor(wp, m->x, m->y);
1.96 nicm 912: if (window_copy_update_selection(wp, 1))
1.57 nicm 913: window_copy_redraw_screen(wp);
1.68 nicm 914: return;
1.57 nicm 915: }
1.68 nicm 916: goto reset_mode;
1.57 nicm 917: }
918:
1.65 nicm 919: /* Otherwise if other buttons pressed, start selection and motion. */
1.84 nicm 920: if (~m->event & MOUSE_EVENT_UP) {
1.65 nicm 921: s->mode &= ~MODE_MOUSE_STANDARD;
1.70 nicm 922: s->mode |= MODE_MOUSE_BUTTON;
1.57 nicm 923:
924: window_copy_update_cursor(wp, m->x, m->y);
925: window_copy_start_selection(wp);
1.35 nicm 926: window_copy_redraw_screen(wp);
1.68 nicm 927: }
928:
929: return;
930:
931: reset_mode:
1.70 nicm 932: s->mode &= ~MODE_MOUSE_BUTTON;
1.68 nicm 933: s->mode |= MODE_MOUSE_STANDARD;
934: if (sess != NULL) {
1.108 nicm 935: window_copy_copy_selection(wp, NULL);
1.68 nicm 936: window_pane_reset_mode(wp);
1.57 nicm 937: }
1.1 nicm 938: }
939:
940: void
1.21 nicm 941: window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py)
942: {
943: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 944: struct grid *gd = data->backing->grid;
1.21 nicm 945: u_int offset, gap;
946:
947: data->cx = px;
948:
949: gap = gd->sy / 4;
950: if (py < gd->sy) {
951: offset = 0;
952: data->cy = py;
953: } else if (py > gd->hsize + gd->sy - gap) {
954: offset = gd->hsize;
955: data->cy = py - gd->hsize;
956: } else {
957: offset = py + gap - gd->sy;
958: data->cy = py - offset;
959: }
1.35 nicm 960: data->oy = gd->hsize - offset;
1.21 nicm 961:
1.96 nicm 962: window_copy_update_selection(wp, 1);
1.21 nicm 963: window_copy_redraw_screen(wp);
964: }
965:
966: int
967: window_copy_search_compare(
1.97 nicm 968: struct grid *gd, u_int px, u_int py, struct grid *sgd, u_int spx, int cis)
1.21 nicm 969: {
970: const struct grid_cell *gc, *sgc;
1.86 nicm 971: struct utf8_data ud, sud;
1.21 nicm 972:
973: gc = grid_peek_cell(gd, px, py);
1.86 nicm 974: grid_cell_get(gc, &ud);
1.21 nicm 975: sgc = grid_peek_cell(sgd, spx, 0);
1.86 nicm 976: grid_cell_get(sgc, &sud);
1.35 nicm 977:
1.86 nicm 978: if (ud.size != sud.size || ud.width != sud.width)
1.21 nicm 979: return (0);
1.97 nicm 980:
981: if (cis && ud.size == 1)
982: return (tolower(ud.data[0]) == sud.data[0]);
983:
1.86 nicm 984: return (memcmp(ud.data, sud.data, ud.size) == 0);
1.21 nicm 985: }
986:
987: int
988: window_copy_search_lr(struct grid *gd,
1.97 nicm 989: struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
1.21 nicm 990: {
991: u_int ax, bx, px;
1.97 nicm 992: int matched;
1.21 nicm 993:
994: for (ax = first; ax < last; ax++) {
995: if (ax + sgd->sx >= gd->sx)
996: break;
997: for (bx = 0; bx < sgd->sx; bx++) {
998: px = ax + bx;
1.97 nicm 999: matched = window_copy_search_compare(gd, px, py, sgd,
1000: bx, cis);
1001: if (!matched)
1.21 nicm 1002: break;
1003: }
1004: if (bx == sgd->sx) {
1005: *ppx = ax;
1006: return (1);
1007: }
1008: }
1009: return (0);
1010: }
1011:
1012: int
1013: window_copy_search_rl(struct grid *gd,
1.97 nicm 1014: struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
1.21 nicm 1015: {
1016: u_int ax, bx, px;
1.97 nicm 1017: int matched;
1.21 nicm 1018:
1019: for (ax = last + 1; ax > first; ax--) {
1.24 nicm 1020: if (gd->sx - (ax - 1) < sgd->sx)
1021: continue;
1.21 nicm 1022: for (bx = 0; bx < sgd->sx; bx++) {
1023: px = ax - 1 + bx;
1.97 nicm 1024: matched = window_copy_search_compare(gd, px, py, sgd,
1025: bx, cis);
1026: if (!matched)
1.21 nicm 1027: break;
1028: }
1029: if (bx == sgd->sx) {
1030: *ppx = ax - 1;
1031: return (1);
1032: }
1033: }
1034: return (0);
1035: }
1036:
1037: void
1038: window_copy_search_up(struct window_pane *wp, const char *searchstr)
1039: {
1040: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1041: struct screen *s = data->backing, ss;
1.21 nicm 1042: struct screen_write_ctx ctx;
1043: struct grid *gd = s->grid, *sgd;
1044: struct grid_cell gc;
1045: size_t searchlen;
1046: u_int i, last, fx, fy, px;
1.97 nicm 1047: int utf8flag, n, wrapped, wrapflag, cis;
1048: const char *ptr;
1.21 nicm 1049:
1050: if (*searchstr == '\0')
1051: return;
1052: utf8flag = options_get_number(&wp->window->options, "utf8");
1.78 nicm 1053: wrapflag = options_get_number(&wp->window->options, "wrap-search");
1.21 nicm 1054: searchlen = screen_write_strlen(utf8flag, "%s", searchstr);
1055:
1056: screen_init(&ss, searchlen, 1, 0);
1057: screen_write_start(&ctx, NULL, &ss);
1058: memcpy(&gc, &grid_default_cell, sizeof gc);
1059: screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr);
1060: screen_write_stop(&ctx);
1061:
1062: fx = data->cx;
1063: fy = gd->hsize - data->oy + data->cy;
1064:
1065: if (fx == 0) {
1066: if (fy == 0)
1067: return;
1068: fx = gd->sx - 1;
1069: fy--;
1070: } else
1071: fx--;
1072: n = wrapped = 0;
1073:
1.97 nicm 1074: cis = 1;
1075: for (ptr = searchstr; *ptr != '\0'; ptr++) {
1.98 deraadt 1076: if (*ptr != tolower((u_char)*ptr)) {
1.97 nicm 1077: cis = 0;
1078: break;
1079: }
1080: }
1081:
1.21 nicm 1082: retry:
1083: sgd = ss.grid;
1084: for (i = fy + 1; i > 0; i--) {
1085: last = screen_size_x(s);
1086: if (i == fy + 1)
1087: last = fx;
1.97 nicm 1088: n = window_copy_search_rl(gd, sgd, &px, i - 1, 0, last, cis);
1.21 nicm 1089: if (n) {
1090: window_copy_scroll_to(wp, px, i - 1);
1091: break;
1092: }
1093: }
1.78 nicm 1094: if (wrapflag && !n && !wrapped) {
1.21 nicm 1095: fx = gd->sx - 1;
1096: fy = gd->hsize + gd->sy - 1;
1097: wrapped = 1;
1098: goto retry;
1099: }
1100:
1101: screen_free(&ss);
1102: }
1103:
1104: void
1105: window_copy_search_down(struct window_pane *wp, const char *searchstr)
1106: {
1107: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1108: struct screen *s = data->backing, ss;
1.21 nicm 1109: struct screen_write_ctx ctx;
1110: struct grid *gd = s->grid, *sgd;
1111: struct grid_cell gc;
1112: size_t searchlen;
1113: u_int i, first, fx, fy, px;
1.97 nicm 1114: int utf8flag, n, wrapped, wrapflag, cis;
1115: const char *ptr;
1.21 nicm 1116:
1117: if (*searchstr == '\0')
1118: return;
1119: utf8flag = options_get_number(&wp->window->options, "utf8");
1.78 nicm 1120: wrapflag = options_get_number(&wp->window->options, "wrap-search");
1.21 nicm 1121: searchlen = screen_write_strlen(utf8flag, "%s", searchstr);
1122:
1123: screen_init(&ss, searchlen, 1, 0);
1124: screen_write_start(&ctx, NULL, &ss);
1125: memcpy(&gc, &grid_default_cell, sizeof gc);
1126: screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr);
1127: screen_write_stop(&ctx);
1128:
1129: fx = data->cx;
1130: fy = gd->hsize - data->oy + data->cy;
1131:
1132: if (fx == gd->sx - 1) {
1133: if (fy == gd->hsize + gd->sy)
1134: return;
1135: fx = 0;
1136: fy++;
1137: } else
1138: fx++;
1139: n = wrapped = 0;
1140:
1.97 nicm 1141: cis = 1;
1142: for (ptr = searchstr; *ptr != '\0'; ptr++) {
1.98 deraadt 1143: if (*ptr != tolower((u_char)*ptr)) {
1.97 nicm 1144: cis = 0;
1145: break;
1146: }
1147: }
1148:
1.21 nicm 1149: retry:
1150: sgd = ss.grid;
1.83 nicm 1151: for (i = fy + 1; i < gd->hsize + gd->sy + 1; i++) {
1.21 nicm 1152: first = 0;
1153: if (i == fy + 1)
1154: first = fx;
1.97 nicm 1155: n = window_copy_search_lr(gd, sgd, &px, i - 1, first, gd->sx,
1156: cis);
1.21 nicm 1157: if (n) {
1158: window_copy_scroll_to(wp, px, i - 1);
1159: break;
1160: }
1161: }
1.78 nicm 1162: if (wrapflag && !n && !wrapped) {
1.21 nicm 1163: fx = 0;
1164: fy = 0;
1165: wrapped = 1;
1166: goto retry;
1167: }
1168:
1169: screen_free(&ss);
1170: }
1171:
1172: void
1173: window_copy_goto_line(struct window_pane *wp, const char *linestr)
1174: {
1175: struct window_copy_mode_data *data = wp->modedata;
1176: const char *errstr;
1177: u_int lineno;
1178:
1.54 nicm 1179: lineno = strtonum(linestr, 0, screen_hsize(data->backing), &errstr);
1.21 nicm 1180: if (errstr != NULL)
1181: return;
1.35 nicm 1182:
1.21 nicm 1183: data->oy = lineno;
1.96 nicm 1184: window_copy_update_selection(wp, 1);
1.21 nicm 1185: window_copy_redraw_screen(wp);
1186: }
1187:
1188: void
1.18 nicm 1189: window_copy_write_line(
1190: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
1.1 nicm 1191: {
1192: struct window_copy_mode_data *data = wp->modedata;
1193: struct screen *s = &data->screen;
1.27 nicm 1194: struct options *oo = &wp->window->options;
1.1 nicm 1195: struct grid_cell gc;
1.100 nicm 1196: char hdr[512];
1197: size_t last, xoff = 0, size = 0, limit;
1.21 nicm 1198:
1.101 nicm 1199: style_apply(&gc, oo, "mode-style");
1.1 nicm 1200:
1.21 nicm 1201: last = screen_size_y(s) - 1;
1.1 nicm 1202: if (py == 0) {
1203: size = xsnprintf(hdr, sizeof hdr,
1.54 nicm 1204: "[%u/%u]", data->oy, screen_hsize(data->backing));
1.62 nicm 1205: if (size > screen_size_x(s))
1206: size = screen_size_x(s);
1.1 nicm 1207: screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
1208: screen_write_puts(ctx, &gc, "%s", hdr);
1.21 nicm 1209: } else if (py == last && data->inputtype != WINDOW_COPY_OFF) {
1.100 nicm 1210: limit = sizeof hdr;
1.105 nicm 1211: if (limit > screen_size_x(s) + 1)
1212: limit = screen_size_x(s) + 1;
1.50 nicm 1213: if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) {
1.100 nicm 1214: xoff = size = xsnprintf(hdr, limit,
1.50 nicm 1215: "Repeat: %u", data->numprefix);
1216: } else {
1.100 nicm 1217: xoff = size = xsnprintf(hdr, limit,
1.50 nicm 1218: "%s: %s", data->inputprompt, data->inputstr);
1219: }
1.21 nicm 1220: screen_write_cursormove(ctx, 0, last);
1221: screen_write_puts(ctx, &gc, "%s", hdr);
1.1 nicm 1222: } else
1223: size = 0;
1224:
1.105 nicm 1225: if (size < screen_size_x(s)) {
1226: screen_write_cursormove(ctx, xoff, py);
1227: screen_write_copy(ctx, data->backing, xoff,
1228: (screen_hsize(data->backing) - data->oy) + py,
1229: screen_size_x(s) - size, 1);
1230: }
1.18 nicm 1231:
1232: if (py == data->cy && data->cx == screen_size_x(s)) {
1233: memcpy(&gc, &grid_default_cell, sizeof gc);
1234: screen_write_cursormove(ctx, screen_size_x(s) - 1, py);
1235: screen_write_putc(ctx, &gc, '$');
1236: }
1.1 nicm 1237: }
1238:
1239: void
1240: window_copy_write_lines(
1241: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py, u_int ny)
1242: {
1243: u_int yy;
1244:
1245: for (yy = py; yy < py + ny; yy++)
1246: window_copy_write_line(wp, ctx, py);
1247: }
1248:
1249: void
1250: window_copy_redraw_lines(struct window_pane *wp, u_int py, u_int ny)
1251: {
1252: struct window_copy_mode_data *data = wp->modedata;
1253: struct screen_write_ctx ctx;
1254: u_int i;
1255:
1256: screen_write_start(&ctx, wp, NULL);
1257: for (i = py; i < py + ny; i++)
1258: window_copy_write_line(wp, &ctx, i);
1259: screen_write_cursormove(&ctx, data->cx, data->cy);
1260: screen_write_stop(&ctx);
1261: }
1262:
1263: void
1264: window_copy_redraw_screen(struct window_pane *wp)
1265: {
1266: struct window_copy_mode_data *data = wp->modedata;
1267:
1268: window_copy_redraw_lines(wp, 0, screen_size_y(&data->screen));
1269: }
1270:
1271: void
1.18 nicm 1272: window_copy_update_cursor(struct window_pane *wp, u_int cx, u_int cy)
1.1 nicm 1273: {
1274: struct window_copy_mode_data *data = wp->modedata;
1.18 nicm 1275: struct screen *s = &data->screen;
1.1 nicm 1276: struct screen_write_ctx ctx;
1.18 nicm 1277: u_int old_cx, old_cy;
1.1 nicm 1278:
1.18 nicm 1279: old_cx = data->cx; old_cy = data->cy;
1280: data->cx = cx; data->cy = cy;
1281: if (old_cx == screen_size_x(s))
1282: window_copy_redraw_lines(wp, old_cy, 1);
1283: if (data->cx == screen_size_x(s))
1284: window_copy_redraw_lines(wp, data->cy, 1);
1285: else {
1286: screen_write_start(&ctx, wp, NULL);
1287: screen_write_cursormove(&ctx, data->cx, data->cy);
1288: screen_write_stop(&ctx);
1289: }
1.1 nicm 1290: }
1291:
1292: void
1293: window_copy_start_selection(struct window_pane *wp)
1294: {
1295: struct window_copy_mode_data *data = wp->modedata;
1296: struct screen *s = &data->screen;
1297:
1.18 nicm 1298: data->selx = data->cx;
1.54 nicm 1299: data->sely = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 1300:
1301: s->sel.flag = 1;
1.96 nicm 1302: window_copy_update_selection(wp, 1);
1.1 nicm 1303: }
1304:
1305: int
1.96 nicm 1306: window_copy_update_selection(struct window_pane *wp, int may_redraw)
1.1 nicm 1307: {
1308: struct window_copy_mode_data *data = wp->modedata;
1309: struct screen *s = &data->screen;
1.27 nicm 1310: struct options *oo = &wp->window->options;
1.1 nicm 1311: struct grid_cell gc;
1.42 nicm 1312: u_int sx, sy, ty, cy;
1.1 nicm 1313:
1314: if (!s->sel.flag)
1315: return (0);
1316:
1317: /* Set colours. */
1.101 nicm 1318: style_apply(&gc, oo, "mode-style");
1.1 nicm 1319:
1.18 nicm 1320: /* Find top of screen. */
1.54 nicm 1321: ty = screen_hsize(data->backing) - data->oy;
1.1 nicm 1322:
1323: /* Adjust the selection. */
1324: sx = data->selx;
1325: sy = data->sely;
1.18 nicm 1326: if (sy < ty) { /* above screen */
1.42 nicm 1327: if (!data->rectflag)
1328: sx = 0;
1.1 nicm 1329: sy = 0;
1.18 nicm 1330: } else if (sy > ty + screen_size_y(s) - 1) { /* below screen */
1.42 nicm 1331: if (!data->rectflag)
1332: sx = screen_size_x(s) - 1;
1.1 nicm 1333: sy = screen_size_y(s) - 1;
1.18 nicm 1334: } else
1.1 nicm 1335: sy -= ty;
1336: sy = screen_hsize(s) + sy;
1337:
1.42 nicm 1338: screen_set_selection(s,
1339: sx, sy, data->cx, screen_hsize(s) + data->cy, data->rectflag, &gc);
1340:
1.96 nicm 1341: if (data->rectflag && may_redraw) {
1.42 nicm 1342: /*
1343: * Can't rely on the caller to redraw the right lines for
1344: * rectangle selection - find the highest line and the number
1345: * of lines, and redraw just past that in both directions
1346: */
1347: cy = data->cy;
1348: if (sy < cy)
1349: window_copy_redraw_lines(wp, sy, cy - sy + 1);
1350: else
1351: window_copy_redraw_lines(wp, cy, sy - cy + 1);
1352: }
1353:
1.1 nicm 1354: return (1);
1355: }
1356:
1.89 nicm 1357: void *
1358: window_copy_get_selection(struct window_pane *wp, size_t *len)
1.1 nicm 1359: {
1360: struct window_copy_mode_data *data = wp->modedata;
1361: struct screen *s = &data->screen;
1362: char *buf;
1.42 nicm 1363: size_t off;
1.111 nicm 1364: u_int i, xx, yy, sx, sy, ex, ey, ey_last;
1.42 nicm 1365: u_int firstsx, lastex, restex, restsx;
1.69 nicm 1366: int keys;
1.1 nicm 1367:
1368: if (!s->sel.flag)
1.89 nicm 1369: return (NULL);
1.1 nicm 1370:
1371: buf = xmalloc(1);
1372: off = 0;
1373:
1374: *buf = '\0';
1375:
1376: /*
1377: * The selection extends from selx,sely to (adjusted) cx,cy on
1378: * the base screen.
1379: */
1380:
1381: /* Find start and end. */
1.18 nicm 1382: xx = data->cx;
1.54 nicm 1383: yy = screen_hsize(data->backing) + data->cy - data->oy;
1.2 nicm 1384: if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
1.1 nicm 1385: sx = xx; sy = yy;
1386: ex = data->selx; ey = data->sely;
1387: } else {
1388: sx = data->selx; sy = data->sely;
1389: ex = xx; ey = yy;
1390: }
1391:
1392: /* Trim ex to end of line. */
1.111 nicm 1393: ey_last = window_copy_find_length(wp, ey);
1394: if (ex > ey_last)
1395: ex = ey_last;
1.1 nicm 1396:
1.42 nicm 1397: /*
1398: * Deal with rectangle-copy if necessary; four situations: start of
1399: * first line (firstsx), end of last line (lastex), start (restsx) and
1400: * end (restex) of all other lines.
1401: */
1402: xx = screen_size_x(s);
1.69 nicm 1403:
1404: /*
1405: * Behave according to mode-keys. If it is emacs, copy like emacs,
1406: * keeping the top-left-most character, and dropping the
1407: * bottom-right-most, regardless of copy direction. If it is vi, also
1408: * keep bottom-right-most character.
1409: */
1410: keys = options_get_number(&wp->window->options, "mode-keys");
1.42 nicm 1411: if (data->rectflag) {
1412: /*
1413: * Need to ignore the column with the cursor in it, which for
1414: * rectangular copy means knowing which side the cursor is on.
1415: */
1416: if (data->selx < data->cx) {
1417: /* Selection start is on the left. */
1.69 nicm 1418: if (keys == MODEKEY_EMACS) {
1419: lastex = data->cx;
1420: restex = data->cx;
1421: }
1422: else {
1423: lastex = data->cx + 1;
1424: restex = data->cx + 1;
1425: }
1.42 nicm 1426: firstsx = data->selx;
1427: restsx = data->selx;
1428: } else {
1429: /* Cursor is on the left. */
1430: lastex = data->selx + 1;
1431: restex = data->selx + 1;
1.64 nicm 1432: firstsx = data->cx;
1433: restsx = data->cx;
1.42 nicm 1434: }
1435: } else {
1.69 nicm 1436: if (keys == MODEKEY_EMACS)
1437: lastex = ex;
1.74 nicm 1438: else
1.69 nicm 1439: lastex = ex + 1;
1.42 nicm 1440: restex = xx;
1441: firstsx = sx;
1442: restsx = 0;
1443: }
1444:
1.1 nicm 1445: /* Copy the lines. */
1.110 nicm 1446: for (i = sy; i <= ey; i++) {
1447: window_copy_copy_line(wp, &buf, &off, i,
1448: (i == sy ? firstsx : restsx),
1449: (i == ey ? lastex : restex));
1.1 nicm 1450: }
1451:
1.26 nicm 1452: /* Don't bother if no data. */
1453: if (off == 0) {
1.81 nicm 1454: free(buf);
1.89 nicm 1455: return (NULL);
1.26 nicm 1456: }
1.111 nicm 1457: if (keys == MODEKEY_EMACS || lastex <= ey_last)
1458: off -= 1; /* remove final \n (unless at end in vi mode) */
1459: *len = off;
1.89 nicm 1460: return (buf);
1461: }
1462:
1463: void
1.108 nicm 1464: window_copy_copy_buffer(struct window_pane *wp, const char *bufname, void *buf,
1465: size_t len)
1.89 nicm 1466: {
1.91 nicm 1467: struct screen_write_ctx ctx;
1.72 nicm 1468:
1.91 nicm 1469: if (options_get_number(&global_options, "set-clipboard")) {
1470: screen_write_start(&ctx, wp, NULL);
1471: screen_write_setselection(&ctx, buf, len);
1472: screen_write_stop(&ctx);
1473: }
1.1 nicm 1474:
1.108 nicm 1475: if (paste_set(buf, len, bufname, NULL) != 0)
1.102 nicm 1476: free(buf);
1.89 nicm 1477: }
1478:
1479: void
1.108 nicm 1480: window_copy_copy_pipe(struct window_pane *wp, struct session *sess,
1481: const char *bufname, const char *arg)
1.89 nicm 1482: {
1.90 nicm 1483: void *buf;
1484: size_t len;
1485: struct job *job;
1486:
1.89 nicm 1487:
1488: buf = window_copy_get_selection(wp, &len);
1489: if (buf == NULL)
1490: return;
1491:
1.90 nicm 1492: job = job_run(arg, sess, NULL, NULL, NULL);
1493: bufferevent_write(job->event, buf, len);
1.89 nicm 1494:
1.108 nicm 1495: window_copy_copy_buffer(wp, bufname, buf, len);
1.89 nicm 1496: }
1497:
1498: void
1.108 nicm 1499: window_copy_copy_selection(struct window_pane *wp, const char *bufname)
1.89 nicm 1500: {
1.114 nicm 1501: void *buf;
1502: size_t len;
1.89 nicm 1503:
1504: buf = window_copy_get_selection(wp, &len);
1505: if (buf == NULL)
1506: return;
1507:
1.108 nicm 1508: window_copy_copy_buffer(wp, bufname, buf, len);
1.103 nicm 1509: }
1510:
1511: void
1.108 nicm 1512: window_copy_append_selection(struct window_pane *wp, const char *bufname)
1.103 nicm 1513: {
1.108 nicm 1514: char *buf;
1515: struct paste_buffer *pb;
1516: size_t len;
1517: struct screen_write_ctx ctx;
1.103 nicm 1518:
1519: buf = window_copy_get_selection(wp, &len);
1520: if (buf == NULL)
1521: return;
1522:
1523: if (options_get_number(&global_options, "set-clipboard")) {
1524: screen_write_start(&ctx, wp, NULL);
1525: screen_write_setselection(&ctx, buf, len);
1526: screen_write_stop(&ctx);
1527: }
1528:
1.108 nicm 1529: if (bufname == NULL || *bufname == '\0') {
1530: pb = paste_get_top();
1531: if (pb != NULL)
1532: bufname = pb->name;
1533: } else
1534: pb = paste_get_name(bufname);
1.103 nicm 1535: if (pb != NULL) {
1.116 nicm 1536: buf = xrealloc(buf, len + pb->size);
1.103 nicm 1537: memmove(buf + pb->size, buf, len);
1538: memcpy(buf, pb->data, pb->size);
1539: len += pb->size;
1540: }
1.108 nicm 1541: if (paste_set(buf, len, bufname, NULL) != 0)
1.103 nicm 1542: free(buf);
1.1 nicm 1543: }
1544:
1545: void
1546: window_copy_copy_line(struct window_pane *wp,
1547: char **buf, size_t *off, u_int sy, u_int sx, u_int ex)
1548: {
1.54 nicm 1549: struct window_copy_mode_data *data = wp->modedata;
1550: struct grid *gd = data->backing->grid;
1551: const struct grid_cell *gc;
1552: struct grid_line *gl;
1.86 nicm 1553: struct utf8_data ud;
1.54 nicm 1554: u_int i, xx, wrapped = 0;
1.115 nicm 1555: const char *s;
1.1 nicm 1556:
1557: if (sx > ex)
1558: return;
1559:
1.16 nicm 1560: /*
1561: * Work out if the line was wrapped at the screen edge and all of it is
1562: * on screen.
1563: */
1564: gl = &gd->linedata[sy];
1.35 nicm 1565: if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
1.16 nicm 1566: wrapped = 1;
1567:
1568: /* If the line was wrapped, don't strip spaces (use the full length). */
1569: if (wrapped)
1570: xx = gl->cellsize;
1571: else
1572: xx = window_copy_find_length(wp, sy);
1.1 nicm 1573: if (ex > xx)
1574: ex = xx;
1575: if (sx > xx)
1576: sx = xx;
1577:
1578: if (sx < ex) {
1579: for (i = sx; i < ex; i++) {
1.16 nicm 1580: gc = grid_peek_cell(gd, i, sy);
1.1 nicm 1581: if (gc->flags & GRID_FLAG_PADDING)
1582: continue;
1.86 nicm 1583: grid_cell_get(gc, &ud);
1.115 nicm 1584: if (ud.size == 1 && (gc->attr & GRID_ATTR_CHARSET)) {
1585: s = tty_acs_get(NULL, ud.data[0]);
1586: if (s != NULL && strlen(s) <= sizeof ud.data) {
1587: ud.size = strlen(s);
1.117 ! nicm 1588: memcpy(ud.data, s, ud.size);
1.115 nicm 1589: }
1590: }
1.86 nicm 1591:
1.116 nicm 1592: *buf = xrealloc(*buf, (*off) + ud.size);
1.86 nicm 1593: memcpy(*buf + *off, ud.data, ud.size);
1594: *off += ud.size;
1.1 nicm 1595: }
1596: }
1597:
1.16 nicm 1598: /* Only add a newline if the line wasn't wrapped. */
1.44 nicm 1599: if (!wrapped || ex != xx) {
1.116 nicm 1600: *buf = xrealloc(*buf, (*off) + 1);
1.16 nicm 1601: (*buf)[(*off)++] = '\n';
1602: }
1.1 nicm 1603: }
1604:
1.47 nicm 1605: void
1606: window_copy_clear_selection(struct window_pane *wp)
1607: {
1608: struct window_copy_mode_data *data = wp->modedata;
1609: u_int px, py;
1610:
1611: screen_clear_selection(&data->screen);
1612:
1.54 nicm 1613: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 1614: px = window_copy_find_length(wp, py);
1615: if (data->cx > px)
1616: window_copy_update_cursor(wp, px, data->cy);
1617: }
1618:
1.1 nicm 1619: int
1.41 nicm 1620: window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set)
1.1 nicm 1621: {
1.54 nicm 1622: struct window_copy_mode_data *data = wp->modedata;
1623: const struct grid_cell *gc;
1.86 nicm 1624: struct utf8_data ud;
1.1 nicm 1625:
1.54 nicm 1626: gc = grid_peek_cell(data->backing->grid, px, py);
1.86 nicm 1627: grid_cell_get(gc, &ud);
1628: if (ud.size != 1 || gc->flags & GRID_FLAG_PADDING)
1.1 nicm 1629: return (0);
1.86 nicm 1630: if (*ud.data == 0x00 || *ud.data == 0x7f)
1.1 nicm 1631: return (0);
1.86 nicm 1632: return (strchr(set, *ud.data) != NULL);
1.1 nicm 1633: }
1634:
1635: u_int
1636: window_copy_find_length(struct window_pane *wp, u_int py)
1637: {
1.54 nicm 1638: struct window_copy_mode_data *data = wp->modedata;
1639: struct screen *s = data->backing;
1640: const struct grid_cell *gc;
1.86 nicm 1641: struct utf8_data ud;
1.54 nicm 1642: u_int px;
1.1 nicm 1643:
1.4 nicm 1644: /*
1645: * If the pane has been resized, its grid can contain old overlong
1646: * lines. grid_peek_cell does not allow accessing cells beyond the
1647: * width of the grid, and screen_write_copy treats them as spaces, so
1648: * ignore them here too.
1649: */
1.54 nicm 1650: px = s->grid->linedata[py].cellsize;
1651: if (px > screen_size_x(s))
1652: px = screen_size_x(s);
1.1 nicm 1653: while (px > 0) {
1.54 nicm 1654: gc = grid_peek_cell(s->grid, px - 1, py);
1.86 nicm 1655: grid_cell_get(gc, &ud);
1656: if (ud.size != 1 || *ud.data != ' ')
1.1 nicm 1657: break;
1658: px--;
1659: }
1660: return (px);
1661: }
1662:
1663: void
1.5 nicm 1664: window_copy_cursor_start_of_line(struct window_pane *wp)
1665: {
1666: struct window_copy_mode_data *data = wp->modedata;
1.58 nicm 1667: struct screen *back_s = data->backing;
1668: struct grid *gd = back_s->grid;
1669: u_int py;
1670:
1671: if (data->cx == 0) {
1672: py = screen_hsize(back_s) + data->cy - data->oy;
1673: while (py > 0 && gd->linedata[py-1].flags & GRID_LINE_WRAPPED) {
1674: window_copy_cursor_up(wp, 0);
1675: py = screen_hsize(back_s) + data->cy - data->oy;
1676: }
1677: }
1.18 nicm 1678: window_copy_update_cursor(wp, 0, data->cy);
1.96 nicm 1679: if (window_copy_update_selection(wp, 1))
1.5 nicm 1680: window_copy_redraw_lines(wp, data->cy, 1);
1.6 nicm 1681: }
1682:
1683: void
1684: window_copy_cursor_back_to_indentation(struct window_pane *wp)
1685: {
1686: struct window_copy_mode_data *data = wp->modedata;
1687: u_int px, py, xx;
1688: const struct grid_cell *gc;
1.86 nicm 1689: struct utf8_data ud;
1.6 nicm 1690:
1691: px = 0;
1.54 nicm 1692: py = screen_hsize(data->backing) + data->cy - data->oy;
1.6 nicm 1693: xx = window_copy_find_length(wp, py);
1694:
1695: while (px < xx) {
1.54 nicm 1696: gc = grid_peek_cell(data->backing->grid, px, py);
1.86 nicm 1697: grid_cell_get(gc, &ud);
1698: if (ud.size != 1 || *ud.data != ' ')
1.6 nicm 1699: break;
1700: px++;
1701: }
1702:
1.18 nicm 1703: window_copy_update_cursor(wp, px, data->cy);
1.96 nicm 1704: if (window_copy_update_selection(wp, 1))
1.18 nicm 1705: window_copy_redraw_lines(wp, data->cy, 1);
1.5 nicm 1706: }
1707:
1708: void
1709: window_copy_cursor_end_of_line(struct window_pane *wp)
1710: {
1711: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1712: struct screen *back_s = data->backing;
1713: struct grid *gd = back_s->grid;
1.5 nicm 1714: u_int px, py;
1715:
1.54 nicm 1716: py = screen_hsize(back_s) + data->cy - data->oy;
1.5 nicm 1717: px = window_copy_find_length(wp, py);
1718:
1.49 nicm 1719: if (data->cx == px) {
1720: if (data->screen.sel.flag && data->rectflag)
1.54 nicm 1721: px = screen_size_x(back_s);
1.49 nicm 1722: if (gd->linedata[py].flags & GRID_LINE_WRAPPED) {
1723: while (py < gd->sy + gd->hsize &&
1724: gd->linedata[py].flags & GRID_LINE_WRAPPED) {
1725: window_copy_cursor_down(wp, 0);
1.54 nicm 1726: py = screen_hsize(back_s)
1727: + data->cy - data->oy;
1.49 nicm 1728: }
1729: px = window_copy_find_length(wp, py);
1730: }
1731: }
1.18 nicm 1732: window_copy_update_cursor(wp, px, data->cy);
1.49 nicm 1733:
1.96 nicm 1734: if (window_copy_update_selection(wp, 1))
1.18 nicm 1735: window_copy_redraw_lines(wp, data->cy, 1);
1.95 nicm 1736: }
1737:
1738: void
1739: window_copy_other_end(struct window_pane *wp)
1740: {
1741: struct window_copy_mode_data *data = wp->modedata;
1742: struct screen *s = &data->screen;
1743: u_int selx, sely, cx, cy, yy;
1744:
1745: if (!s->sel.flag)
1746: return;
1747:
1748: selx = data->selx;
1749: sely = data->sely;
1750: cx = data->cx;
1751: cy = data->cy;
1752: yy = screen_hsize(data->backing) + data->cy - data->oy;
1753:
1754: data->selx = cx;
1755: data->sely = yy;
1756: data->cx = selx;
1757:
1758: if (sely < screen_hsize(data->backing) - data->oy) {
1759: data->oy = screen_hsize(data->backing) - sely;
1760: data->cy = 0;
1761: } else if (sely > screen_hsize(data->backing) - data->oy + screen_size_y(s)) {
1762: data->oy = screen_hsize(data->backing) - sely + screen_size_y(s) - 1;
1763: data->cy = screen_size_y(s) - 1;
1764:
1765: } else
1766: data->cy = cy + sely - yy;
1767:
1768: window_copy_redraw_screen(wp);
1.5 nicm 1769: }
1770:
1771: void
1.1 nicm 1772: window_copy_cursor_left(struct window_pane *wp)
1773: {
1774: struct window_copy_mode_data *data = wp->modedata;
1775:
1776: if (data->cx == 0) {
1.28 nicm 1777: window_copy_cursor_up(wp, 0);
1.18 nicm 1778: window_copy_cursor_end_of_line(wp);
1.1 nicm 1779: } else {
1.18 nicm 1780: window_copy_update_cursor(wp, data->cx - 1, data->cy);
1.96 nicm 1781: if (window_copy_update_selection(wp, 1))
1.1 nicm 1782: window_copy_redraw_lines(wp, data->cy, 1);
1783: }
1784: }
1785:
1786: void
1787: window_copy_cursor_right(struct window_pane *wp)
1788: {
1789: struct window_copy_mode_data *data = wp->modedata;
1790: u_int px, py;
1791:
1.47 nicm 1792: if (data->screen.sel.flag && data->rectflag)
1793: px = screen_size_x(&data->screen);
1794: else {
1.54 nicm 1795: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 1796: px = window_copy_find_length(wp, py);
1797: }
1.1 nicm 1798:
1799: if (data->cx >= px) {
1800: window_copy_cursor_start_of_line(wp);
1.28 nicm 1801: window_copy_cursor_down(wp, 0);
1.1 nicm 1802: } else {
1.18 nicm 1803: window_copy_update_cursor(wp, data->cx + 1, data->cy);
1.96 nicm 1804: if (window_copy_update_selection(wp, 1))
1.1 nicm 1805: window_copy_redraw_lines(wp, data->cy, 1);
1806: }
1807: }
1808:
1809: void
1.28 nicm 1810: window_copy_cursor_up(struct window_pane *wp, int scroll_only)
1.1 nicm 1811: {
1812: struct window_copy_mode_data *data = wp->modedata;
1.36 nicm 1813: struct screen *s = &data->screen;
1.1 nicm 1814: u_int ox, oy, px, py;
1815:
1.54 nicm 1816: oy = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 1817: ox = window_copy_find_length(wp, oy);
1.77 nicm 1818: if (data->cx != ox) {
1.25 nicm 1819: data->lastcx = data->cx;
1820: data->lastsx = ox;
1821: }
1.1 nicm 1822:
1.25 nicm 1823: data->cx = data->lastcx;
1.28 nicm 1824: if (scroll_only || data->cy == 0) {
1.1 nicm 1825: window_copy_scroll_down(wp, 1);
1.36 nicm 1826: if (scroll_only) {
1827: if (data->cy == screen_size_y(s) - 1)
1828: window_copy_redraw_lines(wp, data->cy, 1);
1829: else
1830: window_copy_redraw_lines(wp, data->cy, 2);
1831: }
1.28 nicm 1832: } else {
1.18 nicm 1833: window_copy_update_cursor(wp, data->cx, data->cy - 1);
1.96 nicm 1834: if (window_copy_update_selection(wp, 1)) {
1.36 nicm 1835: if (data->cy == screen_size_y(s) - 1)
1836: window_copy_redraw_lines(wp, data->cy, 1);
1837: else
1838: window_copy_redraw_lines(wp, data->cy, 2);
1839: }
1.1 nicm 1840: }
1841:
1.47 nicm 1842: if (!data->screen.sel.flag || !data->rectflag) {
1.54 nicm 1843: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 1844: px = window_copy_find_length(wp, py);
1.49 nicm 1845: if ((data->cx >= data->lastsx && data->cx != px) ||
1846: data->cx > px)
1.47 nicm 1847: window_copy_cursor_end_of_line(wp);
1848: }
1.1 nicm 1849: }
1850:
1851: void
1.28 nicm 1852: window_copy_cursor_down(struct window_pane *wp, int scroll_only)
1.1 nicm 1853: {
1854: struct window_copy_mode_data *data = wp->modedata;
1855: struct screen *s = &data->screen;
1856: u_int ox, oy, px, py;
1857:
1.54 nicm 1858: oy = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 1859: ox = window_copy_find_length(wp, oy);
1.77 nicm 1860: if (data->cx != ox) {
1.25 nicm 1861: data->lastcx = data->cx;
1862: data->lastsx = ox;
1863: }
1.1 nicm 1864:
1.25 nicm 1865: data->cx = data->lastcx;
1.28 nicm 1866: if (scroll_only || data->cy == screen_size_y(s) - 1) {
1.1 nicm 1867: window_copy_scroll_up(wp, 1);
1.31 nicm 1868: if (scroll_only && data->cy > 0)
1.28 nicm 1869: window_copy_redraw_lines(wp, data->cy - 1, 2);
1870: } else {
1.18 nicm 1871: window_copy_update_cursor(wp, data->cx, data->cy + 1);
1.96 nicm 1872: if (window_copy_update_selection(wp, 1))
1.1 nicm 1873: window_copy_redraw_lines(wp, data->cy - 1, 2);
1874: }
1875:
1.47 nicm 1876: if (!data->screen.sel.flag || !data->rectflag) {
1.54 nicm 1877: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 1878: px = window_copy_find_length(wp, py);
1.49 nicm 1879: if ((data->cx >= data->lastsx && data->cx != px) ||
1880: data->cx > px)
1.47 nicm 1881: window_copy_cursor_end_of_line(wp);
1.52 nicm 1882: }
1883: }
1884:
1885: void
1886: window_copy_cursor_jump(struct window_pane *wp)
1887: {
1888: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1889: struct screen *back_s = data->backing;
1.52 nicm 1890: const struct grid_cell *gc;
1.86 nicm 1891: struct utf8_data ud;
1.67 nicm 1892: u_int px, py, xx;
1.52 nicm 1893:
1894: px = data->cx + 1;
1.54 nicm 1895: py = screen_hsize(back_s) + data->cy - data->oy;
1.52 nicm 1896: xx = window_copy_find_length(wp, py);
1897:
1898: while (px < xx) {
1.54 nicm 1899: gc = grid_peek_cell(back_s->grid, px, py);
1.86 nicm 1900: grid_cell_get(gc, &ud);
1901: if (!(gc->flags & GRID_FLAG_PADDING) &&
1902: ud.size == 1 && *ud.data == data->jumpchar) {
1.52 nicm 1903: window_copy_update_cursor(wp, px, data->cy);
1.96 nicm 1904: if (window_copy_update_selection(wp, 1))
1.52 nicm 1905: window_copy_redraw_lines(wp, data->cy, 1);
1906: return;
1907: }
1908: px++;
1909: }
1910: }
1911:
1912: void
1913: window_copy_cursor_jump_back(struct window_pane *wp)
1914: {
1915: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1916: struct screen *back_s = data->backing;
1.52 nicm 1917: const struct grid_cell *gc;
1.86 nicm 1918: struct utf8_data ud;
1.67 nicm 1919: u_int px, py;
1.52 nicm 1920:
1921: px = data->cx;
1.54 nicm 1922: py = screen_hsize(back_s) + data->cy - data->oy;
1.52 nicm 1923:
1924: if (px > 0)
1925: px--;
1926:
1927: for (;;) {
1.54 nicm 1928: gc = grid_peek_cell(back_s->grid, px, py);
1.86 nicm 1929: grid_cell_get(gc, &ud);
1930: if (!(gc->flags & GRID_FLAG_PADDING) &&
1931: ud.size == 1 && *ud.data == data->jumpchar) {
1.52 nicm 1932: window_copy_update_cursor(wp, px, data->cy);
1.96 nicm 1933: if (window_copy_update_selection(wp, 1))
1.76 nicm 1934: window_copy_redraw_lines(wp, data->cy, 1);
1935: return;
1936: }
1937: if (px == 0)
1938: break;
1939: px--;
1940: }
1941: }
1942:
1943: void
1944: window_copy_cursor_jump_to(struct window_pane *wp)
1945: {
1946: struct window_copy_mode_data *data = wp->modedata;
1947: struct screen *back_s = data->backing;
1948: const struct grid_cell *gc;
1.86 nicm 1949: struct utf8_data ud;
1.76 nicm 1950: u_int px, py, xx;
1951:
1952: px = data->cx + 1;
1953: py = screen_hsize(back_s) + data->cy - data->oy;
1954: xx = window_copy_find_length(wp, py);
1955:
1956: while (px < xx) {
1957: gc = grid_peek_cell(back_s->grid, px, py);
1.86 nicm 1958: grid_cell_get(gc, &ud);
1959: if (!(gc->flags & GRID_FLAG_PADDING) &&
1960: ud.size == 1 && *ud.data == data->jumpchar) {
1.76 nicm 1961: window_copy_update_cursor(wp, px - 1, data->cy);
1.96 nicm 1962: if (window_copy_update_selection(wp, 1))
1.76 nicm 1963: window_copy_redraw_lines(wp, data->cy, 1);
1964: return;
1965: }
1966: px++;
1967: }
1968: }
1969:
1970: void
1971: window_copy_cursor_jump_to_back(struct window_pane *wp)
1972: {
1973: struct window_copy_mode_data *data = wp->modedata;
1974: struct screen *back_s = data->backing;
1975: const struct grid_cell *gc;
1.86 nicm 1976: struct utf8_data ud;
1.76 nicm 1977: u_int px, py;
1978:
1979: px = data->cx;
1980: py = screen_hsize(back_s) + data->cy - data->oy;
1981:
1982: if (px > 0)
1983: px--;
1984:
1985: for (;;) {
1986: gc = grid_peek_cell(back_s->grid, px, py);
1.86 nicm 1987: grid_cell_get(gc, &ud);
1988: if (!(gc->flags & GRID_FLAG_PADDING) &&
1989: ud.size == 1 && *ud.data == data->jumpchar) {
1.76 nicm 1990: window_copy_update_cursor(wp, px + 1, data->cy);
1.96 nicm 1991: if (window_copy_update_selection(wp, 1))
1.52 nicm 1992: window_copy_redraw_lines(wp, data->cy, 1);
1993: return;
1994: }
1995: if (px == 0)
1996: break;
1997: px--;
1.47 nicm 1998: }
1.1 nicm 1999: }
2000:
2001: void
1.41 nicm 2002: window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
1.40 nicm 2003: {
2004: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 2005: struct screen *back_s = data->backing;
1.40 nicm 2006: u_int px, py, xx, yy;
1.48 nicm 2007: int expected = 0;
1.40 nicm 2008:
2009: px = data->cx;
1.54 nicm 2010: py = screen_hsize(back_s) + data->cy - data->oy;
1.40 nicm 2011: xx = window_copy_find_length(wp, py);
1.54 nicm 2012: yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
1.40 nicm 2013:
1.48 nicm 2014: /*
2015: * First skip past any nonword characters and then any word characters.
2016: *
2017: * expected is initially set to 0 for the former and then 1 for the
2018: * latter.
2019: */
2020: do {
2021: while (px > xx ||
2022: window_copy_in_set(wp, px, py, separators) == expected) {
2023: /* Move down if we're past the end of the line. */
2024: if (px > xx) {
2025: if (py == yy)
2026: return;
2027: window_copy_cursor_down(wp, 0);
2028: px = 0;
2029:
1.54 nicm 2030: py = screen_hsize(back_s) + data->cy - data->oy;
1.48 nicm 2031: xx = window_copy_find_length(wp, py);
2032: } else
2033: px++;
2034: }
2035: expected = !expected;
2036: } while (expected == 1);
1.40 nicm 2037:
2038: window_copy_update_cursor(wp, px, data->cy);
1.96 nicm 2039: if (window_copy_update_selection(wp, 1))
1.40 nicm 2040: window_copy_redraw_lines(wp, data->cy, 1);
2041: }
2042:
2043: void
1.106 nicm 2044: window_copy_cursor_next_word_end(struct window_pane *wp,
2045: const char *separators)
1.1 nicm 2046: {
2047: struct window_copy_mode_data *data = wp->modedata;
1.92 nicm 2048: struct options *oo = &wp->window->options;
1.54 nicm 2049: struct screen *back_s = data->backing;
1.39 nicm 2050: u_int px, py, xx, yy;
1.94 nicm 2051: int keys, expected = 1;
1.1 nicm 2052:
1.18 nicm 2053: px = data->cx;
1.54 nicm 2054: py = screen_hsize(back_s) + data->cy - data->oy;
1.1 nicm 2055: xx = window_copy_find_length(wp, py);
1.54 nicm 2056: yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
1.1 nicm 2057:
1.94 nicm 2058: keys = options_get_number(oo, "mode-keys");
2059: if (keys == MODEKEY_VI && !window_copy_in_set(wp, px, py, separators))
2060: px++;
2061:
1.48 nicm 2062: /*
2063: * First skip past any word characters, then any nonword characters.
2064: *
2065: * expected is initially set to 1 for the former and then 0 for the
2066: * latter.
2067: */
2068: do {
2069: while (px > xx ||
2070: window_copy_in_set(wp, px, py, separators) == expected) {
2071: /* Move down if we're past the end of the line. */
2072: if (px > xx) {
2073: if (py == yy)
2074: return;
2075: window_copy_cursor_down(wp, 0);
2076: px = 0;
2077:
1.54 nicm 2078: py = screen_hsize(back_s) + data->cy - data->oy;
1.48 nicm 2079: xx = window_copy_find_length(wp, py);
2080: } else
2081: px++;
2082: }
2083: expected = !expected;
2084: } while (expected == 0);
1.92 nicm 2085:
1.94 nicm 2086: if (keys == MODEKEY_VI && px != 0)
1.92 nicm 2087: px--;
1.18 nicm 2088:
2089: window_copy_update_cursor(wp, px, data->cy);
1.96 nicm 2090: if (window_copy_update_selection(wp, 1))
1.18 nicm 2091: window_copy_redraw_lines(wp, data->cy, 1);
1.1 nicm 2092: }
2093:
1.8 nicm 2094: /* Move to the previous place where a word begins. */
1.1 nicm 2095: void
1.106 nicm 2096: window_copy_cursor_previous_word(struct window_pane *wp,
2097: const char *separators)
1.1 nicm 2098: {
2099: struct window_copy_mode_data *data = wp->modedata;
1.8 nicm 2100: u_int px, py;
1.1 nicm 2101:
1.18 nicm 2102: px = data->cx;
1.54 nicm 2103: py = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 2104:
1.8 nicm 2105: /* Move back to the previous word character. */
1.1 nicm 2106: for (;;) {
1.8 nicm 2107: if (px > 0) {
2108: px--;
1.41 nicm 2109: if (!window_copy_in_set(wp, px, py, separators))
1.1 nicm 2110: break;
1.8 nicm 2111: } else {
2112: if (data->cy == 0 &&
1.54 nicm 2113: (screen_hsize(data->backing) == 0 ||
2114: data->oy >= screen_hsize(data->backing) - 1))
1.8 nicm 2115: goto out;
1.28 nicm 2116: window_copy_cursor_up(wp, 0);
1.1 nicm 2117:
1.54 nicm 2118: py = screen_hsize(data->backing) + data->cy - data->oy;
1.8 nicm 2119: px = window_copy_find_length(wp, py);
1.1 nicm 2120: }
1.8 nicm 2121: }
1.1 nicm 2122:
1.8 nicm 2123: /* Move back to the beginning of this word. */
1.41 nicm 2124: while (px > 0 && !window_copy_in_set(wp, px - 1, py, separators))
1.1 nicm 2125: px--;
1.8 nicm 2126:
1.1 nicm 2127: out:
1.18 nicm 2128: window_copy_update_cursor(wp, px, data->cy);
1.96 nicm 2129: if (window_copy_update_selection(wp, 1))
1.18 nicm 2130: window_copy_redraw_lines(wp, data->cy, 1);
1.1 nicm 2131: }
2132:
2133: void
2134: window_copy_scroll_up(struct window_pane *wp, u_int ny)
2135: {
2136: struct window_copy_mode_data *data = wp->modedata;
2137: struct screen *s = &data->screen;
2138: struct screen_write_ctx ctx;
2139:
2140: if (data->oy < ny)
2141: ny = data->oy;
2142: if (ny == 0)
2143: return;
2144: data->oy -= ny;
2145:
1.96 nicm 2146: window_copy_update_selection(wp, 0);
2147:
1.1 nicm 2148: screen_write_start(&ctx, wp, NULL);
2149: screen_write_cursormove(&ctx, 0, 0);
2150: screen_write_deleteline(&ctx, ny);
2151: window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, ny);
2152: window_copy_write_line(wp, &ctx, 0);
1.31 nicm 2153: if (screen_size_y(s) > 1)
2154: window_copy_write_line(wp, &ctx, 1);
2155: if (screen_size_y(s) > 3)
2156: window_copy_write_line(wp, &ctx, screen_size_y(s) - 2);
1.96 nicm 2157: if (s->sel.flag && screen_size_y(s) > ny)
1.1 nicm 2158: window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1);
2159: screen_write_cursormove(&ctx, data->cx, data->cy);
2160: screen_write_stop(&ctx);
2161: }
2162:
2163: void
2164: window_copy_scroll_down(struct window_pane *wp, u_int ny)
2165: {
2166: struct window_copy_mode_data *data = wp->modedata;
2167: struct screen *s = &data->screen;
2168: struct screen_write_ctx ctx;
2169:
1.54 nicm 2170: if (ny > screen_hsize(data->backing))
1.1 nicm 2171: return;
2172:
1.54 nicm 2173: if (data->oy > screen_hsize(data->backing) - ny)
2174: ny = screen_hsize(data->backing) - data->oy;
1.1 nicm 2175: if (ny == 0)
2176: return;
2177: data->oy += ny;
2178:
1.96 nicm 2179: window_copy_update_selection(wp, 0);
2180:
1.1 nicm 2181: screen_write_start(&ctx, wp, NULL);
2182: screen_write_cursormove(&ctx, 0, 0);
2183: screen_write_insertline(&ctx, ny);
2184: window_copy_write_lines(wp, &ctx, 0, ny);
1.96 nicm 2185: if (s->sel.flag && screen_size_y(s) > ny)
1.1 nicm 2186: window_copy_write_line(wp, &ctx, ny);
1.96 nicm 2187: else if (ny == 1) /* nuke position */
1.1 nicm 2188: window_copy_write_line(wp, &ctx, 1);
2189: screen_write_cursormove(&ctx, data->cx, data->cy);
2190: screen_write_stop(&ctx);
2191: }
1.42 nicm 2192:
2193: void
2194: window_copy_rectangle_toggle(struct window_pane *wp)
2195: {
2196: struct window_copy_mode_data *data = wp->modedata;
1.47 nicm 2197: u_int px, py;
1.42 nicm 2198:
2199: data->rectflag = !data->rectflag;
1.47 nicm 2200:
1.54 nicm 2201: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 2202: px = window_copy_find_length(wp, py);
2203: if (data->cx > px)
2204: window_copy_update_cursor(wp, px, data->cy);
1.42 nicm 2205:
1.96 nicm 2206: window_copy_update_selection(wp, 1);
1.42 nicm 2207: window_copy_redraw_screen(wp);
2208: }