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