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