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