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