Annotation of src/usr.bin/tmux/window-copy.c, Revision 1.338
1.338 ! nicm 1: /* $OpenBSD: window-copy.c,v 1.337 2022/07/22 07:14:07 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.244 nicm 22: #include <regex.h>
1.21 nicm 23: #include <stdlib.h>
1.1 nicm 24: #include <string.h>
1.280 nicm 25: #include <time.h>
1.1 nicm 26:
27: #include "tmux.h"
28:
1.299 nicm 29: struct window_copy_mode_data;
30:
1.208 nicm 31: static const char *window_copy_key_table(struct window_mode_entry *);
32: static void window_copy_command(struct window_mode_entry *, struct client *,
1.205 nicm 33: struct session *, struct winlink *, struct args *,
34: struct mouse_event *);
1.208 nicm 35: static struct screen *window_copy_init(struct window_mode_entry *,
1.177 nicm 36: struct cmd_find_state *, struct args *);
1.210 nicm 37: static struct screen *window_copy_view_init(struct window_mode_entry *,
38: struct cmd_find_state *, struct args *);
1.208 nicm 39: static void window_copy_free(struct window_mode_entry *);
40: static void window_copy_resize(struct window_mode_entry *, u_int, u_int);
41: static void window_copy_formats(struct window_mode_entry *,
42: struct format_tree *);
43: static void window_copy_pageup1(struct window_mode_entry *, int);
44: static int window_copy_pagedown(struct window_mode_entry *, int, int);
45: static void window_copy_next_paragraph(struct window_mode_entry *);
46: static void window_copy_previous_paragraph(struct window_mode_entry *);
47: static void window_copy_redraw_selection(struct window_mode_entry *, u_int);
48: static void window_copy_redraw_lines(struct window_mode_entry *, u_int,
49: u_int);
50: static void window_copy_redraw_screen(struct window_mode_entry *);
51: static void window_copy_write_line(struct window_mode_entry *,
1.157 nicm 52: struct screen_write_ctx *, u_int);
1.208 nicm 53: static void window_copy_write_lines(struct window_mode_entry *,
1.157 nicm 54: struct screen_write_ctx *, u_int, u_int);
1.299 nicm 55: static char *window_copy_match_at_cursor(struct window_copy_mode_data *);
1.296 nicm 56: static void window_copy_scroll_to(struct window_mode_entry *, u_int, u_int,
57: int);
1.157 nicm 58: static int window_copy_search_compare(struct grid *, u_int, u_int,
59: struct grid *, u_int, int);
60: static int window_copy_search_lr(struct grid *, struct grid *, u_int *,
61: u_int, u_int, u_int, int);
62: static int window_copy_search_rl(struct grid *, struct grid *, u_int *,
63: u_int, u_int, u_int, int);
1.299 nicm 64: static int window_copy_last_regex(struct grid *, u_int, u_int, u_int,
65: u_int, u_int *, u_int *, const char *, const regex_t *,
66: int);
1.321 nicm 67: static int window_copy_search_mark_at(struct window_copy_mode_data *,
68: u_int, u_int, u_int *);
1.244 nicm 69: static char *window_copy_stringify(struct grid *, u_int, u_int, u_int,
70: char *, u_int *);
1.299 nicm 71: static void window_copy_cstrtocellpos(struct grid *, u_int, u_int *,
72: u_int *, const char *);
1.208 nicm 73: static int window_copy_search_marks(struct window_mode_entry *,
1.296 nicm 74: struct screen *, int, int);
1.208 nicm 75: static void window_copy_clear_marks(struct window_mode_entry *);
1.157 nicm 76: static int window_copy_is_lowercase(const char *);
1.317 nicm 77: static void window_copy_search_back_overlap(struct grid *, regex_t *,
78: u_int *, u_int *, u_int *, u_int);
1.208 nicm 79: static int window_copy_search_jump(struct window_mode_entry *,
80: struct grid *, struct grid *, u_int, u_int, u_int, int, int,
1.321 nicm 81: int, int);
82: static int window_copy_search(struct window_mode_entry *, int, int);
83: static int window_copy_search_up(struct window_mode_entry *, int);
84: static int window_copy_search_down(struct window_mode_entry *, int);
1.208 nicm 85: static void window_copy_goto_line(struct window_mode_entry *, const char *);
86: static void window_copy_update_cursor(struct window_mode_entry *, u_int,
87: u_int);
88: static void window_copy_start_selection(struct window_mode_entry *);
89: static int window_copy_adjust_selection(struct window_mode_entry *,
90: u_int *, u_int *);
1.252 nicm 91: static int window_copy_set_selection(struct window_mode_entry *, int, int);
92: static int window_copy_update_selection(struct window_mode_entry *, int,
93: int);
94: static void window_copy_synchronize_cursor(struct window_mode_entry *, int);
1.208 nicm 95: static void *window_copy_get_selection(struct window_mode_entry *, size_t *);
1.215 nicm 96: static void window_copy_copy_buffer(struct window_mode_entry *,
97: const char *, void *, size_t);
1.314 nicm 98: static void window_copy_pipe(struct window_mode_entry *,
99: struct session *, const char *);
1.208 nicm 100: static void window_copy_copy_pipe(struct window_mode_entry *,
1.215 nicm 101: struct session *, const char *, const char *);
102: static void window_copy_copy_selection(struct window_mode_entry *,
103: const char *);
1.208 nicm 104: static void window_copy_append_selection(struct window_mode_entry *);
105: static void window_copy_clear_selection(struct window_mode_entry *);
106: static void window_copy_copy_line(struct window_mode_entry *, char **,
107: size_t *, u_int, u_int, u_int);
108: static int window_copy_in_set(struct window_mode_entry *, u_int, u_int,
1.157 nicm 109: const char *);
1.208 nicm 110: static u_int window_copy_find_length(struct window_mode_entry *, u_int);
111: static void window_copy_cursor_start_of_line(struct window_mode_entry *);
112: static void window_copy_cursor_back_to_indentation(
113: struct window_mode_entry *);
114: static void window_copy_cursor_end_of_line(struct window_mode_entry *);
115: static void window_copy_other_end(struct window_mode_entry *);
116: static void window_copy_cursor_left(struct window_mode_entry *);
1.305 nicm 117: static void window_copy_cursor_right(struct window_mode_entry *, int);
1.208 nicm 118: static void window_copy_cursor_up(struct window_mode_entry *, int);
119: static void window_copy_cursor_down(struct window_mode_entry *, int);
120: static void window_copy_cursor_jump(struct window_mode_entry *);
121: static void window_copy_cursor_jump_back(struct window_mode_entry *);
122: static void window_copy_cursor_jump_to(struct window_mode_entry *);
123: static void window_copy_cursor_jump_to_back(struct window_mode_entry *);
124: static void window_copy_cursor_next_word(struct window_mode_entry *,
1.157 nicm 125: const char *);
1.247 nicm 126: static void window_copy_cursor_next_word_end_pos(struct window_mode_entry *,
127: const char *, u_int *, u_int *);
1.208 nicm 128: static void window_copy_cursor_next_word_end(struct window_mode_entry *,
1.255 nicm 129: const char *, int);
1.247 nicm 130: static void window_copy_cursor_previous_word_pos(struct window_mode_entry *,
1.323 nicm 131: const char *, u_int *, u_int *);
1.208 nicm 132: static void window_copy_cursor_previous_word(struct window_mode_entry *,
1.229 nicm 133: const char *, int);
1.208 nicm 134: static void window_copy_scroll_up(struct window_mode_entry *, u_int);
135: static void window_copy_scroll_down(struct window_mode_entry *, u_int);
1.313 nicm 136: static void window_copy_rectangle_set(struct window_mode_entry *, int);
1.157 nicm 137: static void window_copy_move_mouse(struct mouse_event *);
138: static void window_copy_drag_update(struct client *, struct mouse_event *);
1.217 nicm 139: static void window_copy_drag_release(struct client *, struct mouse_event *);
1.288 nicm 140: static void window_copy_jump_to_mark(struct window_mode_entry *);
1.315 nicm 141: static void window_copy_acquire_cursor_up(struct window_mode_entry *,
142: u_int, u_int, u_int, u_int, u_int);
143: static void window_copy_acquire_cursor_down(struct window_mode_entry *,
144: u_int, u_int, u_int, u_int, u_int, u_int, int);
1.1 nicm 145:
146: const struct window_mode window_copy_mode = {
1.173 nicm 147: .name = "copy-mode",
148:
1.155 nicm 149: .init = window_copy_init,
150: .free = window_copy_free,
151: .resize = window_copy_resize,
152: .key_table = window_copy_key_table,
153: .command = window_copy_command,
1.206 nicm 154: .formats = window_copy_formats,
1.1 nicm 155: };
156:
1.210 nicm 157: const struct window_mode window_view_mode = {
158: .name = "view-mode",
159:
160: .init = window_copy_view_init,
161: .free = window_copy_free,
162: .resize = window_copy_resize,
163: .key_table = window_copy_key_table,
164: .command = window_copy_command,
165: .formats = window_copy_formats,
166: };
167:
1.155 nicm 168: enum {
1.21 nicm 169: WINDOW_COPY_OFF,
170: WINDOW_COPY_SEARCHUP,
171: WINDOW_COPY_SEARCHDOWN,
1.52 nicm 172: WINDOW_COPY_JUMPFORWARD,
1.155 nicm 173: WINDOW_COPY_JUMPBACKWARD,
1.76 nicm 174: WINDOW_COPY_JUMPTOFORWARD,
1.155 nicm 175: WINDOW_COPY_JUMPTOBACKWARD,
1.21 nicm 176: };
177:
1.161 nicm 178: enum {
179: WINDOW_COPY_REL_POS_ABOVE,
180: WINDOW_COPY_REL_POS_ON_SCREEN,
181: WINDOW_COPY_REL_POS_BELOW,
182: };
183:
1.213 nicm 184: enum window_copy_cmd_action {
185: WINDOW_COPY_CMD_NOTHING,
186: WINDOW_COPY_CMD_REDRAW,
187: WINDOW_COPY_CMD_CANCEL,
188: };
189:
1.295 nicm 190: enum window_copy_cmd_clear {
191: WINDOW_COPY_CMD_CLEAR_ALWAYS,
192: WINDOW_COPY_CMD_CLEAR_NEVER,
193: WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
194: };
195:
1.213 nicm 196: struct window_copy_cmd_state {
197: struct window_mode_entry *wme;
198: struct args *args;
199: struct mouse_event *m;
1.215 nicm 200:
1.213 nicm 201: struct client *c;
202: struct session *s;
1.215 nicm 203: struct winlink *wl;
1.213 nicm 204: };
205:
1.54 nicm 206: /*
1.161 nicm 207: * Copy mode's visible screen (the "screen" field) is filled from one of two
208: * sources: the original contents of the pane (used when we actually enter via
209: * the "copy-mode" command, to copy the contents of the current pane), or else
210: * a series of lines containing the output from an output-writing tmux command
211: * (such as any of the "show-*" or "list-*" commands).
1.54 nicm 212: *
1.161 nicm 213: * In either case, the full content of the copy-mode grid is pointed at by the
214: * "backing" field, and is copied into "screen" as needed (that is, when
215: * scrolling occurs). When copy-mode is backed by a pane, backing points
216: * directly at that pane's screen structure (&wp->base); when backed by a list
217: * of output-lines from a command, it points at a newly-allocated screen
218: * structure (which is deallocated when the mode ends).
1.54 nicm 219: */
1.1 nicm 220: struct window_copy_mode_data {
1.155 nicm 221: struct screen screen;
1.1 nicm 222:
1.155 nicm 223: struct screen *backing;
224: int backing_written; /* backing display started */
1.334 nicm 225: struct screen *writing;
226: struct input_ctx *ictx;
1.54 nicm 227:
1.266 nicm 228: int viewmode; /* view mode entered */
229:
1.192 nicm 230: u_int oy; /* number of lines scrolled up */
1.21 nicm 231:
1.192 nicm 232: u_int selx; /* beginning of selection */
1.155 nicm 233: u_int sely;
1.21 nicm 234:
1.192 nicm 235: u_int endselx; /* end of selection */
1.161 nicm 236: u_int endsely;
237:
238: enum {
239: CURSORDRAG_NONE, /* selection is independent of cursor */
240: CURSORDRAG_ENDSEL, /* end is synchronized with cursor */
241: CURSORDRAG_SEL, /* start is synchronized with cursor */
242: } cursordrag;
243:
1.192 nicm 244: int modekeys;
245: enum {
246: LINE_SEL_NONE,
247: LINE_SEL_LEFT_RIGHT,
248: LINE_SEL_RIGHT_LEFT,
249: } lineflag; /* line selection mode */
1.155 nicm 250: int rectflag; /* in rectangle copy mode? */
251: int scroll_exit; /* exit on scroll to end? */
1.249 nicm 252: int hide_position; /* hide position marker */
1.1 nicm 253:
1.247 nicm 254: enum {
255: SEL_CHAR, /* select one char at a time */
256: SEL_WORD, /* select one word at a time */
257: SEL_LINE, /* select one line at a time */
258: } selflag;
259:
1.323 nicm 260: const char *separators; /* word separators */
1.247 nicm 261:
262: u_int dx; /* drag start position */
263: u_int dy;
264:
265: u_int selrx; /* selection reset positions */
266: u_int selry;
267: u_int endselrx;
268: u_int endselry;
269:
1.155 nicm 270: u_int cx;
271: u_int cy;
1.42 nicm 272:
1.192 nicm 273: u_int lastcx; /* position in last line w/ content */
274: u_int lastsx; /* size of last line w/ content */
1.1 nicm 275:
1.288 nicm 276: u_int mx; /* mark position */
277: u_int my;
278: int showmark;
279:
1.155 nicm 280: int searchtype;
1.321 nicm 281: int searchdirection;
1.259 nicm 282: int searchregex;
1.155 nicm 283: char *searchstr;
1.282 nicm 284: u_char *searchmark;
1.284 nicm 285: int searchcount;
286: int searchmore;
1.308 nicm 287: int searchall;
1.163 nicm 288: int searchx;
289: int searchy;
290: int searcho;
1.282 nicm 291: u_char searchgen;
1.25 nicm 292:
1.263 nicm 293: int timeout; /* search has timed out */
1.284 nicm 294: #define WINDOW_COPY_SEARCH_TIMEOUT 10000
295: #define WINDOW_COPY_SEARCH_ALL_TIMEOUT 200
1.263 nicm 296:
1.315 nicm 297: int jumptype;
298: struct utf8_data *jumpchar;
1.217 nicm 299:
300: struct event dragtimer;
301: #define WINDOW_COPY_DRAG_REPEAT_TIME 50000
1.1 nicm 302: };
303:
1.217 nicm 304: static void
305: window_copy_scroll_timer(__unused int fd, __unused short events, void *arg)
306: {
307: struct window_mode_entry *wme = arg;
308: struct window_pane *wp = wme->wp;
309: struct window_copy_mode_data *data = wme->data;
310: struct timeval tv = {
311: .tv_usec = WINDOW_COPY_DRAG_REPEAT_TIME
312: };
313:
314: evtimer_del(&data->dragtimer);
315:
316: if (TAILQ_FIRST(&wp->modes) != wme)
317: return;
318:
319: if (data->cy == 0) {
320: evtimer_add(&data->dragtimer, &tv);
321: window_copy_cursor_up(wme, 1);
322: } else if (data->cy == screen_size_y(&data->screen) - 1) {
323: evtimer_add(&data->dragtimer, &tv);
324: window_copy_cursor_down(wme, 1);
325: }
326: }
327:
1.266 nicm 328: static struct screen *
1.274 nicm 329: window_copy_clone_screen(struct screen *src, struct screen *hint, u_int *cx,
1.279 nicm 330: u_int *cy, int trim)
1.266 nicm 331: {
1.274 nicm 332: struct screen *dst;
333: const struct grid_line *gl;
1.285 nicm 334: u_int sy, wx, wy;
335: int reflow;
1.266 nicm 336:
337: dst = xcalloc(1, sizeof *dst);
1.270 nicm 338:
339: sy = screen_hsize(src) + screen_size_y(src);
1.279 nicm 340: if (trim) {
341: while (sy > screen_hsize(src)) {
342: gl = grid_peek_line(src->grid, sy - 1);
343: if (gl->cellused != 0)
344: break;
345: sy--;
346: }
1.274 nicm 347: }
1.278 nicm 348: log_debug("%s: target screen is %ux%u, source %ux%u", __func__,
349: screen_size_x(src), sy, screen_size_x(hint),
350: screen_hsize(src) + screen_size_y(src));
1.274 nicm 351: screen_init(dst, screen_size_x(src), sy, screen_hlimit(src));
1.285 nicm 352:
353: /*
354: * Ensure history is on for the backing grid so lines are not deleted
355: * during resizing.
356: */
357: dst->grid->flags |= GRID_HISTORY;
1.274 nicm 358: grid_duplicate_lines(dst->grid, 0, src->grid, 0, sy);
1.270 nicm 359:
1.274 nicm 360: dst->grid->sy = sy - screen_hsize(src);
361: dst->grid->hsize = screen_hsize(src);
362: dst->grid->hscrolled = src->grid->hscrolled;
1.278 nicm 363: if (src->cy > dst->grid->sy - 1) {
364: dst->cx = 0;
365: dst->cy = dst->grid->sy - 1;
366: } else {
367: dst->cx = src->cx;
368: dst->cy = src->cy;
369: }
1.266 nicm 370:
1.285 nicm 371: if (cx != NULL && cy != NULL) {
372: *cx = dst->cx;
373: *cy = screen_hsize(dst) + dst->cy;
374: reflow = (screen_size_x(hint) != screen_size_x(dst));
375: }
376: else
377: reflow = 0;
378: if (reflow)
379: grid_wrap_position(dst->grid, *cx, *cy, &wx, &wy);
1.274 nicm 380: screen_resize_cursor(dst, screen_size_x(hint), screen_size_y(hint), 1,
1.285 nicm 381: 0, 0);
382: if (reflow)
383: grid_unwrap_position(dst->grid, cx, cy, wx, wy);
1.266 nicm 384:
385: return (dst);
386: }
387:
1.210 nicm 388: static struct window_copy_mode_data *
389: window_copy_common_init(struct window_mode_entry *wme)
1.1 nicm 390: {
1.208 nicm 391: struct window_pane *wp = wme->wp;
1.1 nicm 392: struct window_copy_mode_data *data;
1.210 nicm 393: struct screen *base = &wp->base;
1.1 nicm 394:
1.208 nicm 395: wme->data = data = xcalloc(1, sizeof *data);
1.1 nicm 396:
1.161 nicm 397: data->cursordrag = CURSORDRAG_NONE;
1.193 nicm 398: data->lineflag = LINE_SEL_NONE;
1.250 nicm 399: data->selflag = SEL_CHAR;
1.42 nicm 400:
1.174 nicm 401: if (wp->searchstr != NULL) {
402: data->searchtype = WINDOW_COPY_SEARCHUP;
1.259 nicm 403: data->searchregex = wp->searchregex;
1.174 nicm 404: data->searchstr = xstrdup(wp->searchstr);
405: } else {
406: data->searchtype = WINDOW_COPY_OFF;
1.259 nicm 407: data->searchregex = 0;
1.174 nicm 408: data->searchstr = NULL;
409: }
1.163 nicm 410: data->searchx = data->searchy = data->searcho = -1;
1.308 nicm 411: data->searchall = 1;
1.21 nicm 412:
1.52 nicm 413: data->jumptype = WINDOW_COPY_OFF;
1.315 nicm 414: data->jumpchar = NULL;
1.52 nicm 415:
1.210 nicm 416: screen_init(&data->screen, screen_size_x(base), screen_size_y(base), 0);
1.192 nicm 417: data->modekeys = options_get_number(wp->window->options, "mode-keys");
1.1 nicm 418:
1.217 nicm 419: evtimer_set(&data->dragtimer, window_copy_scroll_timer, wme);
420:
1.210 nicm 421: return (data);
1.54 nicm 422: }
423:
1.210 nicm 424: static struct screen *
425: window_copy_init(struct window_mode_entry *wme,
426: __unused struct cmd_find_state *fs, struct args *args)
1.54 nicm 427: {
1.270 nicm 428: struct window_pane *wp = wme->swp;
1.210 nicm 429: struct window_copy_mode_data *data;
1.274 nicm 430: struct screen *base = &wp->base;
1.210 nicm 431: struct screen_write_ctx ctx;
1.274 nicm 432: u_int i, cx, cy;
1.54 nicm 433:
1.210 nicm 434: data = window_copy_common_init(wme);
1.279 nicm 435: data->backing = window_copy_clone_screen(base, &data->screen, &cx, &cy,
436: wme->swp != wme->wp);
1.210 nicm 437:
1.285 nicm 438: data->cx = cx;
1.274 nicm 439: if (cy < screen_hsize(data->backing)) {
1.272 nicm 440: data->cy = 0;
1.274 nicm 441: data->oy = screen_hsize(data->backing) - cy;
442: } else {
1.285 nicm 443: data->cy = cy - screen_hsize(data->backing);
1.274 nicm 444: data->oy = 0;
445: }
1.54 nicm 446:
1.210 nicm 447: data->scroll_exit = args_has(args, 'e');
1.249 nicm 448: data->hide_position = args_has(args, 'H');
1.1 nicm 449:
1.210 nicm 450: data->screen.cx = data->cx;
451: data->screen.cy = data->cy;
1.288 nicm 452: data->mx = data->cx;
453: data->my = screen_hsize(data->backing) + data->cy - data->oy;
454: data->showmark = 0;
1.210 nicm 455:
1.283 nicm 456: screen_write_start(&ctx, &data->screen);
1.210 nicm 457: for (i = 0; i < screen_size_y(&data->screen); i++)
1.208 nicm 458: window_copy_write_line(wme, &ctx, i);
1.212 nicm 459: screen_write_cursormove(&ctx, data->cx, data->cy, 0);
1.1 nicm 460: screen_write_stop(&ctx);
1.210 nicm 461:
462: return (&data->screen);
1.54 nicm 463: }
1.1 nicm 464:
1.210 nicm 465: static struct screen *
466: window_copy_view_init(struct window_mode_entry *wme,
467: __unused struct cmd_find_state *fs, __unused struct args *args)
1.54 nicm 468: {
1.210 nicm 469: struct window_pane *wp = wme->wp;
1.208 nicm 470: struct window_copy_mode_data *data;
1.210 nicm 471: struct screen *base = &wp->base;
1.334 nicm 472: u_int sx = screen_size_x(base);
1.54 nicm 473:
1.210 nicm 474: data = window_copy_common_init(wme);
1.266 nicm 475: data->viewmode = 1;
1.208 nicm 476:
1.334 nicm 477: data->backing = xmalloc(sizeof *data->backing);
478: screen_init(data->backing, sx, screen_size_y(base), UINT_MAX);
479: data->writing = xmalloc(sizeof *data->writing);
480: screen_init(data->writing, sx, screen_size_y(base), 0);
481: data->ictx = input_init(NULL, NULL, NULL);
1.288 nicm 482: data->mx = data->cx;
483: data->my = screen_hsize(data->backing) + data->cy - data->oy;
484: data->showmark = 0;
1.207 nicm 485:
1.210 nicm 486: return (&data->screen);
1.1 nicm 487: }
488:
1.157 nicm 489: static void
1.208 nicm 490: window_copy_free(struct window_mode_entry *wme)
1.1 nicm 491: {
1.208 nicm 492: struct window_copy_mode_data *data = wme->data;
1.46 nicm 493:
1.217 nicm 494: evtimer_del(&data->dragtimer);
495:
1.162 nicm 496: free(data->searchmark);
1.81 nicm 497: free(data->searchstr);
1.315 nicm 498: free(data->jumpchar);
1.21 nicm 499:
1.334 nicm 500: if (data->writing != NULL) {
501: screen_free(data->writing);
502: free(data->writing);
503: }
504: if (data->ictx != NULL)
505: input_free(data->ictx);
1.266 nicm 506: screen_free(data->backing);
507: free(data->backing);
508:
1.1 nicm 509: screen_free(&data->screen);
1.81 nicm 510: free(data);
1.1 nicm 511: }
512:
513: void
1.334 nicm 514: window_copy_add(struct window_pane *wp, int parse, const char *fmt, ...)
1.54 nicm 515: {
516: va_list ap;
517:
518: va_start(ap, fmt);
1.334 nicm 519: window_copy_vadd(wp, parse, fmt, ap);
1.54 nicm 520: va_end(ap);
521: }
522:
1.334 nicm 523: static void
524: window_copy_init_ctx_cb(__unused struct screen_write_ctx *ctx,
525: struct tty_ctx *ttyctx)
526: {
527: memcpy(&ttyctx->defaults, &grid_default_cell, sizeof ttyctx->defaults);
528: ttyctx->palette = NULL;
529: ttyctx->redraw_cb = NULL;
530: ttyctx->set_client_cb = NULL;
531: ttyctx->arg = NULL;
532: }
533:
1.54 nicm 534: void
1.334 nicm 535: window_copy_vadd(struct window_pane *wp, int parse, const char *fmt, va_list ap)
1.54 nicm 536: {
1.211 nicm 537: struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
1.208 nicm 538: struct window_copy_mode_data *data = wme->data;
1.54 nicm 539: struct screen *backing = data->backing;
1.334 nicm 540: struct screen *writing = data->writing;
541: struct screen_write_ctx writing_ctx, backing_ctx, ctx;
1.54 nicm 542: struct grid_cell gc;
1.119 nicm 543: u_int old_hsize, old_cy;
1.334 nicm 544: u_int sx = screen_size_x(backing);
545: char *text;
1.54 nicm 546:
1.334 nicm 547: if (parse) {
548: vasprintf(&text, fmt, ap);
549: screen_write_start(&writing_ctx, writing);
550: screen_write_reset(&writing_ctx);
551: input_parse_screen(data->ictx, writing, window_copy_init_ctx_cb,
552: data, text, strlen(text));
553: free(text);
554: }
1.54 nicm 555:
556: old_hsize = screen_hsize(data->backing);
1.334 nicm 557: screen_write_start(&backing_ctx, backing);
1.54 nicm 558: if (data->backing_written) {
559: /*
560: * On the second or later line, do a CRLF before writing
561: * (so it's on a new line).
562: */
1.334 nicm 563: screen_write_carriagereturn(&backing_ctx);
564: screen_write_linefeed(&backing_ctx, 0, 8);
1.54 nicm 565: } else
566: data->backing_written = 1;
1.119 nicm 567: old_cy = backing->cy;
1.334 nicm 568: if (parse)
569: screen_write_fast_copy(&backing_ctx, writing, 0, 0, sx, 1);
570: else {
571: memcpy(&gc, &grid_default_cell, sizeof gc);
572: screen_write_vnputs(&backing_ctx, 0, &gc, fmt, ap);
573: }
574: screen_write_stop(&backing_ctx);
1.54 nicm 575:
576: data->oy += screen_hsize(data->backing) - old_hsize;
577:
1.283 nicm 578: screen_write_start_pane(&ctx, wp, &data->screen);
1.54 nicm 579:
580: /*
581: * If the history has changed, draw the top line.
582: * (If there's any history at all, it has changed.)
583: */
584: if (screen_hsize(data->backing))
1.208 nicm 585: window_copy_redraw_lines(wme, 0, 1);
1.54 nicm 586:
1.119 nicm 587: /* Write the new lines. */
1.208 nicm 588: window_copy_redraw_lines(wme, old_cy, backing->cy - old_cy + 1);
1.54 nicm 589:
590: screen_write_stop(&ctx);
591: }
592:
593: void
1.149 nicm 594: window_copy_pageup(struct window_pane *wp, int half_page)
1.1 nicm 595: {
1.211 nicm 596: window_copy_pageup1(TAILQ_FIRST(&wp->modes), half_page);
1.208 nicm 597: }
598:
599: static void
600: window_copy_pageup1(struct window_mode_entry *wme, int half_page)
601: {
602: struct window_copy_mode_data *data = wme->data;
1.1 nicm 603: struct screen *s = &data->screen;
1.162 nicm 604: u_int n, ox, oy, px, py;
1.147 nicm 605:
606: oy = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 607: ox = window_copy_find_length(wme, oy);
1.147 nicm 608:
609: if (data->cx != ox) {
610: data->lastcx = data->cx;
611: data->lastsx = ox;
612: }
613: data->cx = data->lastcx;
1.1 nicm 614:
1.19 nicm 615: n = 1;
1.149 nicm 616: if (screen_size_y(s) > 2) {
617: if (half_page)
618: n = screen_size_y(s) / 2;
619: else
620: n = screen_size_y(s) - 2;
621: }
1.147 nicm 622:
1.195 nicm 623: if (data->oy + n > screen_hsize(data->backing)) {
1.54 nicm 624: data->oy = screen_hsize(data->backing);
1.195 nicm 625: if (data->cy < n)
626: data->cy = 0;
627: else
628: data->cy -= n;
629: } else
1.19 nicm 630: data->oy += n;
1.147 nicm 631:
1.192 nicm 632: if (data->screen.sel == NULL || !data->rectflag) {
1.162 nicm 633: py = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 634: px = window_copy_find_length(wme, py);
1.162 nicm 635: if ((data->cx >= data->lastsx && data->cx != px) ||
636: data->cx > px)
1.208 nicm 637: window_copy_cursor_end_of_line(wme);
1.147 nicm 638: }
639:
1.264 nicm 640: if (data->searchmark != NULL && !data->timeout)
1.296 nicm 641: window_copy_search_marks(wme, NULL, data->searchregex, 1);
1.252 nicm 642: window_copy_update_selection(wme, 1, 0);
1.208 nicm 643: window_copy_redraw_screen(wme);
1.147 nicm 644: }
645:
1.166 nicm 646: static int
1.208 nicm 647: window_copy_pagedown(struct window_mode_entry *wme, int half_page,
648: int scroll_exit)
1.147 nicm 649: {
1.208 nicm 650: struct window_copy_mode_data *data = wme->data;
1.147 nicm 651: struct screen *s = &data->screen;
1.161 nicm 652: u_int n, ox, oy, px, py;
1.147 nicm 653:
654: oy = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 655: ox = window_copy_find_length(wme, oy);
1.147 nicm 656:
657: if (data->cx != ox) {
658: data->lastcx = data->cx;
659: data->lastsx = ox;
660: }
661: data->cx = data->lastcx;
662:
663: n = 1;
1.149 nicm 664: if (screen_size_y(s) > 2) {
665: if (half_page)
666: n = screen_size_y(s) / 2;
667: else
668: n = screen_size_y(s) - 2;
669: }
1.147 nicm 670:
1.195 nicm 671: if (data->oy < n) {
1.147 nicm 672: data->oy = 0;
1.195 nicm 673: if (data->cy + (n - data->oy) >= screen_size_y(data->backing))
674: data->cy = screen_size_y(data->backing) - 1;
675: else
676: data->cy += n - data->oy;
677: } else
1.147 nicm 678: data->oy -= n;
679:
1.192 nicm 680: if (data->screen.sel == NULL || !data->rectflag) {
1.161 nicm 681: py = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 682: px = window_copy_find_length(wme, py);
1.161 nicm 683: if ((data->cx >= data->lastsx && data->cx != px) ||
684: data->cx > px)
1.208 nicm 685: window_copy_cursor_end_of_line(wme);
1.147 nicm 686: }
687:
1.186 nicm 688: if (scroll_exit && data->oy == 0)
1.166 nicm 689: return (1);
1.264 nicm 690: if (data->searchmark != NULL && !data->timeout)
1.296 nicm 691: window_copy_search_marks(wme, NULL, data->searchregex, 1);
1.252 nicm 692: window_copy_update_selection(wme, 1, 0);
1.208 nicm 693: window_copy_redraw_screen(wme);
1.166 nicm 694: return (0);
1.1 nicm 695: }
696:
1.157 nicm 697: static void
1.208 nicm 698: window_copy_previous_paragraph(struct window_mode_entry *wme)
1.148 nicm 699: {
1.208 nicm 700: struct window_copy_mode_data *data = wme->data;
1.151 nicm 701: u_int oy;
1.148 nicm 702:
703: oy = screen_hsize(data->backing) + data->cy - data->oy;
704:
1.208 nicm 705: while (oy > 0 && window_copy_find_length(wme, oy) == 0)
1.148 nicm 706: oy--;
707:
1.208 nicm 708: while (oy > 0 && window_copy_find_length(wme, oy) > 0)
1.148 nicm 709: oy--;
710:
1.296 nicm 711: window_copy_scroll_to(wme, 0, oy, 0);
1.148 nicm 712: }
713:
1.157 nicm 714: static void
1.208 nicm 715: window_copy_next_paragraph(struct window_mode_entry *wme)
1.148 nicm 716: {
1.208 nicm 717: struct window_copy_mode_data *data = wme->data;
1.148 nicm 718: struct screen *s = &data->screen;
719: u_int maxy, ox, oy;
720:
721: oy = screen_hsize(data->backing) + data->cy - data->oy;
722: maxy = screen_hsize(data->backing) + screen_size_y(s) - 1;
723:
1.208 nicm 724: while (oy < maxy && window_copy_find_length(wme, oy) == 0)
1.148 nicm 725: oy++;
726:
1.208 nicm 727: while (oy < maxy && window_copy_find_length(wme, oy) > 0)
1.148 nicm 728: oy++;
729:
1.208 nicm 730: ox = window_copy_find_length(wme, oy);
1.296 nicm 731: window_copy_scroll_to(wme, ox, oy, 0);
1.148 nicm 732: }
733:
1.256 nicm 734: char *
735: window_copy_get_word(struct window_pane *wp, u_int x, u_int y)
736: {
737: struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
738: struct window_copy_mode_data *data = wme->data;
739: struct grid *gd = data->screen.grid;
740:
741: return (format_grid_word(gd, x, gd->hsize + y));
742: }
743:
744: char *
745: window_copy_get_line(struct window_pane *wp, u_int y)
746: {
747: struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
748: struct window_copy_mode_data *data = wme->data;
749: struct grid *gd = data->screen.grid;
750:
751: return (format_grid_line(gd, gd->hsize + y));
752: }
753:
1.316 nicm 754: static void *
1.299 nicm 755: window_copy_cursor_word_cb(struct format_tree *ft)
756: {
757: struct window_pane *wp = format_get_pane(ft);
758: struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
759: struct window_copy_mode_data *data = wme->data;
760:
761: return (window_copy_get_word(wp, data->cx, data->cy));
762: }
763:
1.316 nicm 764: static void *
1.299 nicm 765: window_copy_cursor_line_cb(struct format_tree *ft)
766: {
767: struct window_pane *wp = format_get_pane(ft);
768: struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
769: struct window_copy_mode_data *data = wme->data;
770:
771: return (window_copy_get_line(wp, data->cy));
772: }
773:
1.316 nicm 774: static void *
1.299 nicm 775: window_copy_search_match_cb(struct format_tree *ft)
776: {
777: struct window_pane *wp = format_get_pane(ft);
778: struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
779: struct window_copy_mode_data *data = wme->data;
780:
781: return (window_copy_match_at_cursor(data));
782: }
783:
1.157 nicm 784: static void
1.208 nicm 785: window_copy_formats(struct window_mode_entry *wme, struct format_tree *ft)
1.206 nicm 786: {
1.208 nicm 787: struct window_copy_mode_data *data = wme->data;
1.206 nicm 788:
789: format_add(ft, "scroll_position", "%d", data->oy);
790: format_add(ft, "rectangle_toggle", "%d", data->rectflag);
1.236 nicm 791:
792: format_add(ft, "copy_cursor_x", "%d", data->cx);
793: format_add(ft, "copy_cursor_y", "%d", data->cy);
794:
795: format_add(ft, "selection_present", "%d", data->screen.sel != NULL);
796: if (data->screen.sel != NULL) {
797: format_add(ft, "selection_start_x", "%d", data->selx);
798: format_add(ft, "selection_start_y", "%d", data->sely);
799: format_add(ft, "selection_end_x", "%d", data->endselx);
800: format_add(ft, "selection_end_y", "%d", data->endsely);
1.246 nicm 801: format_add(ft, "selection_active", "%d",
802: data->cursordrag != CURSORDRAG_NONE);
803: } else
804: format_add(ft, "selection_active", "%d", 0);
1.237 nicm 805:
1.299 nicm 806: format_add(ft, "search_present", "%d", data->searchmark != NULL);
807: format_add_cb(ft, "search_match", window_copy_search_match_cb);
1.237 nicm 808:
1.299 nicm 809: format_add_cb(ft, "copy_cursor_word", window_copy_cursor_word_cb);
810: format_add_cb(ft, "copy_cursor_line", window_copy_cursor_line_cb);
1.206 nicm 811: }
812:
813: static void
1.275 nicm 814: window_copy_size_changed(struct window_mode_entry *wme)
1.1 nicm 815: {
1.208 nicm 816: struct window_copy_mode_data *data = wme->data;
1.1 nicm 817: struct screen *s = &data->screen;
1.275 nicm 818: struct screen_write_ctx ctx;
819: int search = (data->searchmark != NULL);
1.35 nicm 820:
1.208 nicm 821: window_copy_clear_selection(wme);
1.228 nicm 822: window_copy_clear_marks(wme);
1.18 nicm 823:
1.283 nicm 824: screen_write_start(&ctx, s);
1.276 nicm 825: window_copy_write_lines(wme, &ctx, 0, screen_size_y(s));
1.1 nicm 826: screen_write_stop(&ctx);
1.18 nicm 827:
1.263 nicm 828: if (search && !data->timeout)
1.296 nicm 829: window_copy_search_marks(wme, NULL, data->searchregex, 0);
1.163 nicm 830: data->searchx = data->cx;
831: data->searchy = data->cy;
832: data->searcho = data->oy;
1.275 nicm 833: }
834:
835: static void
836: window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
837: {
838: struct window_copy_mode_data *data = wme->data;
839: struct screen *s = &data->screen;
1.285 nicm 840: struct grid *gd = data->backing->grid;
841: u_int cx, cy, wx, wy;
842: int reflow;
1.275 nicm 843:
844: screen_resize(s, sx, sy, 0);
1.285 nicm 845: cx = data->cx;
846: cy = gd->hsize + data->cy - data->oy;
847: reflow = (gd->sx != sx);
848: if (reflow)
849: grid_wrap_position(gd, cx, cy, &wx, &wy);
850: screen_resize_cursor(data->backing, sx, sy, 1, 0, 0);
851: if (reflow)
852: grid_unwrap_position(gd, &cx, &cy, wx, wy);
1.275 nicm 853:
1.285 nicm 854: data->cx = cx;
855: if (cy < gd->hsize) {
856: data->cy = 0;
857: data->oy = gd->hsize - cy;
858: } else {
859: data->cy = cy - gd->hsize;
860: data->oy = 0;
861: }
1.162 nicm 862:
1.275 nicm 863: window_copy_size_changed(wme);
1.208 nicm 864: window_copy_redraw_screen(wme);
1.1 nicm 865: }
866:
1.157 nicm 867: static const char *
1.208 nicm 868: window_copy_key_table(struct window_mode_entry *wme)
1.155 nicm 869: {
1.208 nicm 870: struct window_pane *wp = wme->wp;
871:
1.155 nicm 872: if (options_get_number(wp->window->options, "mode-keys") == MODEKEY_VI)
873: return ("copy-mode-vi");
874: return ("copy-mode");
875: }
876:
1.259 nicm 877: static int
878: window_copy_expand_search_string(struct window_copy_cmd_state *cs)
879: {
880: struct window_mode_entry *wme = cs->wme;
881: struct window_copy_mode_data *data = wme->data;
1.329 nicm 882: const char *ss = args_string(cs->args, 1);
1.259 nicm 883: char *expanded;
884:
1.329 nicm 885: if (ss == NULL || *ss == '\0')
886: return (0);
887:
888: if (args_has(cs->args, 'F')) {
889: expanded = format_single(NULL, ss, NULL, NULL, NULL, wme->wp);
890: if (*expanded == '\0') {
891: free(expanded);
892: return (0);
1.259 nicm 893: }
1.329 nicm 894: free(data->searchstr);
895: data->searchstr = expanded;
896: } else {
897: free(data->searchstr);
898: data->searchstr = xstrdup(ss);
1.259 nicm 899: }
900: return (1);
901: }
902:
1.213 nicm 903: static enum window_copy_cmd_action
904: window_copy_cmd_append_selection(struct window_copy_cmd_state *cs)
905: {
906: struct window_mode_entry *wme = cs->wme;
907: struct session *s = cs->s;
908:
909: if (s != NULL)
910: window_copy_append_selection(wme);
911: window_copy_clear_selection(wme);
912: return (WINDOW_COPY_CMD_REDRAW);
913: }
914:
915: static enum window_copy_cmd_action
916: window_copy_cmd_append_selection_and_cancel(struct window_copy_cmd_state *cs)
917: {
918: struct window_mode_entry *wme = cs->wme;
919: struct session *s = cs->s;
920:
921: if (s != NULL)
922: window_copy_append_selection(wme);
923: window_copy_clear_selection(wme);
924: return (WINDOW_COPY_CMD_CANCEL);
925: }
926:
927: static enum window_copy_cmd_action
928: window_copy_cmd_back_to_indentation(struct window_copy_cmd_state *cs)
929: {
930: struct window_mode_entry *wme = cs->wme;
931:
932: window_copy_cursor_back_to_indentation(wme);
933: return (WINDOW_COPY_CMD_NOTHING);
934: }
935:
936: static enum window_copy_cmd_action
937: window_copy_cmd_begin_selection(struct window_copy_cmd_state *cs)
938: {
939: struct window_mode_entry *wme = cs->wme;
940: struct client *c = cs->c;
941: struct mouse_event *m = cs->m;
942: struct window_copy_mode_data *data = wme->data;
943:
944: if (m != NULL) {
945: window_copy_start_drag(c, m);
946: return (WINDOW_COPY_CMD_NOTHING);
947: }
948:
949: data->lineflag = LINE_SEL_NONE;
1.252 nicm 950: data->selflag = SEL_CHAR;
1.213 nicm 951: window_copy_start_selection(wme);
952: return (WINDOW_COPY_CMD_REDRAW);
953: }
954:
955: static enum window_copy_cmd_action
956: window_copy_cmd_stop_selection(struct window_copy_cmd_state *cs)
957: {
958: struct window_mode_entry *wme = cs->wme;
959: struct window_copy_mode_data *data = wme->data;
960:
961: data->cursordrag = CURSORDRAG_NONE;
1.214 nicm 962: data->lineflag = LINE_SEL_NONE;
1.250 nicm 963: data->selflag = SEL_CHAR;
1.213 nicm 964: return (WINDOW_COPY_CMD_NOTHING);
965: }
966:
967: static enum window_copy_cmd_action
968: window_copy_cmd_bottom_line(struct window_copy_cmd_state *cs)
969: {
970: struct window_mode_entry *wme = cs->wme;
971: struct window_copy_mode_data *data = wme->data;
972:
973: data->cx = 0;
974: data->cy = screen_size_y(&data->screen) - 1;
975:
1.252 nicm 976: window_copy_update_selection(wme, 1, 0);
1.213 nicm 977: return (WINDOW_COPY_CMD_REDRAW);
978: }
979:
980: static enum window_copy_cmd_action
981: window_copy_cmd_cancel(__unused struct window_copy_cmd_state *cs)
982: {
983: return (WINDOW_COPY_CMD_CANCEL);
984: }
985:
986: static enum window_copy_cmd_action
987: window_copy_cmd_clear_selection(struct window_copy_cmd_state *cs)
988: {
989: struct window_mode_entry *wme = cs->wme;
990:
991: window_copy_clear_selection(wme);
992: return (WINDOW_COPY_CMD_REDRAW);
993: }
994:
995: static enum window_copy_cmd_action
1.326 nicm 996: window_copy_do_copy_end_of_line(struct window_copy_cmd_state *cs, int pipe,
997: int cancel)
1.213 nicm 998: {
1.326 nicm 999: struct window_mode_entry *wme = cs->wme;
1000: struct client *c = cs->c;
1001: struct session *s = cs->s;
1002: struct winlink *wl = cs->wl;
1003: struct window_pane *wp = wme->wp;
1.329 nicm 1004: u_int count = args_count(cs->args);
1.326 nicm 1005: u_int np = wme->prefix, ocx, ocy, ooy;
1006: struct window_copy_mode_data *data = wme->data;
1007: char *prefix = NULL, *command = NULL;
1.329 nicm 1008: const char *arg1 = args_string(cs->args, 1);
1009: const char *arg2 = args_string(cs->args, 2);
1.326 nicm 1010:
1011: if (pipe) {
1.329 nicm 1012: if (count == 3)
1013: prefix = format_single(NULL, arg2, c, s, wl, wp);
1014: if (s != NULL && count > 1 && *arg1 != '\0')
1015: command = format_single(NULL, arg1, c, s, wl, wp);
1.326 nicm 1016: } else {
1.329 nicm 1017: if (count == 2)
1018: prefix = format_single(NULL, arg1, c, s, wl, wp);
1.326 nicm 1019: }
1.325 nicm 1020:
1021: ocx = data->cx;
1022: ocy = data->cy;
1023: ooy = data->oy;
1024:
1025: window_copy_start_selection(wme);
1026: for (; np > 1; np--)
1027: window_copy_cursor_down(wme, 0);
1028: window_copy_cursor_end_of_line(wme);
1029:
1.326 nicm 1030: if (s != NULL) {
1031: if (pipe)
1032: window_copy_copy_pipe(wme, s, prefix, command);
1033: else
1034: window_copy_copy_selection(wme, prefix);
1035:
1036: if (cancel) {
1037: free(prefix);
1038: free(command);
1039: return (WINDOW_COPY_CMD_CANCEL);
1040: }
1041: }
1.325 nicm 1042: window_copy_clear_selection(wme);
1043:
1044: data->cx = ocx;
1045: data->cy = ocy;
1046: data->oy = ooy;
1047:
1048: free(prefix);
1.326 nicm 1049: free(command);
1.325 nicm 1050: return (WINDOW_COPY_CMD_REDRAW);
1051: }
1052:
1053: static enum window_copy_cmd_action
1.326 nicm 1054: window_copy_cmd_copy_end_of_line(struct window_copy_cmd_state *cs)
1055: {
1056: return (window_copy_do_copy_end_of_line(cs, 0, 0));
1057: }
1058:
1059: static enum window_copy_cmd_action
1.325 nicm 1060: window_copy_cmd_copy_end_of_line_and_cancel(struct window_copy_cmd_state *cs)
1061: {
1.326 nicm 1062: return (window_copy_do_copy_end_of_line(cs, 0, 1));
1063: }
1.215 nicm 1064:
1.326 nicm 1065: static enum window_copy_cmd_action
1066: window_copy_cmd_copy_pipe_end_of_line(struct window_copy_cmd_state *cs)
1067: {
1068: return (window_copy_do_copy_end_of_line(cs, 1, 0));
1069: }
1.213 nicm 1070:
1.326 nicm 1071: static enum window_copy_cmd_action
1072: window_copy_cmd_copy_pipe_end_of_line_and_cancel(
1073: struct window_copy_cmd_state *cs)
1074: {
1075: return (window_copy_do_copy_end_of_line(cs, 1, 1));
1.213 nicm 1076: }
1077:
1078: static enum window_copy_cmd_action
1.326 nicm 1079: window_copy_do_copy_line(struct window_copy_cmd_state *cs, int pipe, int cancel)
1.213 nicm 1080: {
1.326 nicm 1081: struct window_mode_entry *wme = cs->wme;
1082: struct client *c = cs->c;
1083: struct session *s = cs->s;
1084: struct winlink *wl = cs->wl;
1085: struct window_pane *wp = wme->wp;
1086: struct window_copy_mode_data *data = wme->data;
1.329 nicm 1087: u_int count = args_count(cs->args);
1.326 nicm 1088: u_int np = wme->prefix, ocx, ocy, ooy;
1089: char *prefix = NULL, *command = NULL;
1.329 nicm 1090: const char *arg1 = args_string(cs->args, 1);
1091: const char *arg2 = args_string(cs->args, 2);
1.325 nicm 1092:
1.326 nicm 1093: if (pipe) {
1.329 nicm 1094: if (count == 3)
1095: prefix = format_single(NULL, arg2, c, s, wl, wp);
1096: if (s != NULL && count > 1 && *arg1 != '\0')
1097: command = format_single(NULL, arg1, c, s, wl, wp);
1.326 nicm 1098: } else {
1.329 nicm 1099: if (count == 2)
1100: prefix = format_single(NULL, arg1, c, s, wl, wp);
1.326 nicm 1101: }
1.325 nicm 1102:
1103: ocx = data->cx;
1104: ocy = data->cy;
1105: ooy = data->oy;
1106:
1107: data->selflag = SEL_CHAR;
1108: window_copy_cursor_start_of_line(wme);
1109: window_copy_start_selection(wme);
1110: for (; np > 1; np--)
1111: window_copy_cursor_down(wme, 0);
1112: window_copy_cursor_end_of_line(wme);
1113:
1.326 nicm 1114: if (s != NULL) {
1115: if (pipe)
1116: window_copy_copy_pipe(wme, s, prefix, command);
1117: else
1118: window_copy_copy_selection(wme, prefix);
1119:
1120: if (cancel) {
1121: free(prefix);
1122: free(command);
1123: return (WINDOW_COPY_CMD_CANCEL);
1124: }
1125: }
1.325 nicm 1126: window_copy_clear_selection(wme);
1127:
1128: data->cx = ocx;
1129: data->cy = ocy;
1130: data->oy = ooy;
1131:
1132: free(prefix);
1.326 nicm 1133: free(command);
1.325 nicm 1134: return (WINDOW_COPY_CMD_REDRAW);
1135: }
1136:
1137: static enum window_copy_cmd_action
1.326 nicm 1138: window_copy_cmd_copy_line(struct window_copy_cmd_state *cs)
1139: {
1140: return (window_copy_do_copy_line(cs, 0, 0));
1141: }
1142:
1143: static enum window_copy_cmd_action
1.325 nicm 1144: window_copy_cmd_copy_line_and_cancel(struct window_copy_cmd_state *cs)
1145: {
1.326 nicm 1146: return (window_copy_do_copy_line(cs, 0, 1));
1147: }
1.215 nicm 1148:
1.326 nicm 1149: static enum window_copy_cmd_action
1150: window_copy_cmd_copy_pipe_line(struct window_copy_cmd_state *cs)
1151: {
1152: return (window_copy_do_copy_line(cs, 1, 0));
1153: }
1.213 nicm 1154:
1.326 nicm 1155: static enum window_copy_cmd_action
1156: window_copy_cmd_copy_pipe_line_and_cancel(struct window_copy_cmd_state *cs)
1157: {
1158: return (window_copy_do_copy_line(cs, 1, 1));
1.213 nicm 1159: }
1160:
1161: static enum window_copy_cmd_action
1.216 nicm 1162: window_copy_cmd_copy_selection_no_clear(struct window_copy_cmd_state *cs)
1.213 nicm 1163: {
1164: struct window_mode_entry *wme = cs->wme;
1.215 nicm 1165: struct client *c = cs->c;
1.213 nicm 1166: struct session *s = cs->s;
1.215 nicm 1167: struct winlink *wl = cs->wl;
1168: struct window_pane *wp = wme->wp;
1169: char *prefix = NULL;
1.329 nicm 1170: const char *arg1 = args_string(cs->args, 1);
1.215 nicm 1171:
1.329 nicm 1172: if (arg1 != NULL)
1173: prefix = format_single(NULL, arg1, c, s, wl, wp);
1.213 nicm 1174:
1175: if (s != NULL)
1.215 nicm 1176: window_copy_copy_selection(wme, prefix);
1177:
1178: free(prefix);
1.216 nicm 1179: return (WINDOW_COPY_CMD_NOTHING);
1180: }
1181:
1182: static enum window_copy_cmd_action
1183: window_copy_cmd_copy_selection(struct window_copy_cmd_state *cs)
1184: {
1185: struct window_mode_entry *wme = cs->wme;
1186:
1187: window_copy_cmd_copy_selection_no_clear(cs);
1188: window_copy_clear_selection(wme);
1.213 nicm 1189: return (WINDOW_COPY_CMD_REDRAW);
1190: }
1191:
1192: static enum window_copy_cmd_action
1193: window_copy_cmd_copy_selection_and_cancel(struct window_copy_cmd_state *cs)
1194: {
1195: struct window_mode_entry *wme = cs->wme;
1.215 nicm 1196:
1.216 nicm 1197: window_copy_cmd_copy_selection_no_clear(cs);
1.213 nicm 1198: window_copy_clear_selection(wme);
1199: return (WINDOW_COPY_CMD_CANCEL);
1200: }
1201:
1202: static enum window_copy_cmd_action
1203: window_copy_cmd_cursor_down(struct window_copy_cmd_state *cs)
1204: {
1205: struct window_mode_entry *wme = cs->wme;
1206: u_int np = wme->prefix;
1207:
1208: for (; np != 0; np--)
1209: window_copy_cursor_down(wme, 0);
1210: return (WINDOW_COPY_CMD_NOTHING);
1211: }
1212:
1213: static enum window_copy_cmd_action
1.234 nicm 1214: window_copy_cmd_cursor_down_and_cancel(struct window_copy_cmd_state *cs)
1215: {
1216: struct window_mode_entry *wme = cs->wme;
1217: struct window_copy_mode_data *data = wme->data;
1218: u_int np = wme->prefix, cy;
1219:
1220: cy = data->cy;
1221: for (; np != 0; np--)
1222: window_copy_cursor_down(wme, 0);
1223: if (cy == data->cy && data->oy == 0)
1224: return (WINDOW_COPY_CMD_CANCEL);
1225: return (WINDOW_COPY_CMD_NOTHING);
1226: }
1227:
1228: static enum window_copy_cmd_action
1.213 nicm 1229: window_copy_cmd_cursor_left(struct window_copy_cmd_state *cs)
1230: {
1231: struct window_mode_entry *wme = cs->wme;
1232: u_int np = wme->prefix;
1233:
1234: for (; np != 0; np--)
1235: window_copy_cursor_left(wme);
1236: return (WINDOW_COPY_CMD_NOTHING);
1237: }
1238:
1239: static enum window_copy_cmd_action
1240: window_copy_cmd_cursor_right(struct window_copy_cmd_state *cs)
1241: {
1242: struct window_mode_entry *wme = cs->wme;
1.324 nicm 1243: struct window_copy_mode_data *data = wme->data;
1.213 nicm 1244: u_int np = wme->prefix;
1245:
1.324 nicm 1246: for (; np != 0; np--) {
1247: window_copy_cursor_right(wme, data->screen.sel != NULL &&
1248: data->rectflag);
1249: }
1.213 nicm 1250: return (WINDOW_COPY_CMD_NOTHING);
1251: }
1252:
1253: static enum window_copy_cmd_action
1254: window_copy_cmd_cursor_up(struct window_copy_cmd_state *cs)
1255: {
1256: struct window_mode_entry *wme = cs->wme;
1257: u_int np = wme->prefix;
1258:
1259: for (; np != 0; np--)
1260: window_copy_cursor_up(wme, 0);
1261: return (WINDOW_COPY_CMD_NOTHING);
1262: }
1263:
1264: static enum window_copy_cmd_action
1265: window_copy_cmd_end_of_line(struct window_copy_cmd_state *cs)
1266: {
1267: struct window_mode_entry *wme = cs->wme;
1268:
1269: window_copy_cursor_end_of_line(wme);
1270: return (WINDOW_COPY_CMD_NOTHING);
1271: }
1272:
1273: static enum window_copy_cmd_action
1274: window_copy_cmd_halfpage_down(struct window_copy_cmd_state *cs)
1275: {
1276: struct window_mode_entry *wme = cs->wme;
1277: struct window_copy_mode_data *data = wme->data;
1278: u_int np = wme->prefix;
1279:
1280: for (; np != 0; np--) {
1281: if (window_copy_pagedown(wme, 1, data->scroll_exit))
1282: return (WINDOW_COPY_CMD_CANCEL);
1283: }
1284: return (WINDOW_COPY_CMD_NOTHING);
1285: }
1286:
1287: static enum window_copy_cmd_action
1288: window_copy_cmd_halfpage_down_and_cancel(struct window_copy_cmd_state *cs)
1289: {
1290:
1291: struct window_mode_entry *wme = cs->wme;
1292: u_int np = wme->prefix;
1293:
1294: for (; np != 0; np--) {
1295: if (window_copy_pagedown(wme, 1, 1))
1296: return (WINDOW_COPY_CMD_CANCEL);
1297: }
1298: return (WINDOW_COPY_CMD_NOTHING);
1299: }
1300:
1301: static enum window_copy_cmd_action
1302: window_copy_cmd_halfpage_up(struct window_copy_cmd_state *cs)
1303: {
1304: struct window_mode_entry *wme = cs->wme;
1305: u_int np = wme->prefix;
1306:
1307: for (; np != 0; np--)
1308: window_copy_pageup1(wme, 1);
1309: return (WINDOW_COPY_CMD_NOTHING);
1310: }
1311:
1312: static enum window_copy_cmd_action
1.333 nicm 1313: window_copy_cmd_toggle_position(struct window_copy_cmd_state *cs)
1314: {
1315: struct window_mode_entry *wme = cs->wme;
1316: struct window_copy_mode_data *data = wme->data;
1317:
1318: data->hide_position = !data->hide_position;
1319: return (WINDOW_COPY_CMD_REDRAW);
1320: }
1321:
1322: static enum window_copy_cmd_action
1.213 nicm 1323: window_copy_cmd_history_bottom(struct window_copy_cmd_state *cs)
1324: {
1325: struct window_mode_entry *wme = cs->wme;
1326: struct window_copy_mode_data *data = wme->data;
1.269 nicm 1327: struct screen *s = data->backing;
1.221 nicm 1328: u_int oy;
1329:
1.269 nicm 1330: oy = screen_hsize(s) + data->cy - data->oy;
1.221 nicm 1331: if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
1332: window_copy_other_end(wme);
1.213 nicm 1333:
1334: data->cy = screen_size_y(&data->screen) - 1;
1.269 nicm 1335: data->cx = window_copy_find_length(wme, screen_hsize(s) + data->cy);
1.213 nicm 1336: data->oy = 0;
1337:
1.264 nicm 1338: if (data->searchmark != NULL && !data->timeout)
1.296 nicm 1339: window_copy_search_marks(wme, NULL, data->searchregex, 1);
1.252 nicm 1340: window_copy_update_selection(wme, 1, 0);
1.213 nicm 1341: return (WINDOW_COPY_CMD_REDRAW);
1342: }
1343:
1344: static enum window_copy_cmd_action
1345: window_copy_cmd_history_top(struct window_copy_cmd_state *cs)
1346: {
1347: struct window_mode_entry *wme = cs->wme;
1348: struct window_copy_mode_data *data = wme->data;
1.221 nicm 1349: u_int oy;
1.213 nicm 1350:
1.221 nicm 1351: oy = screen_hsize(data->backing) + data->cy - data->oy;
1352: if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
1353: window_copy_other_end(wme);
1354:
1355: data->cy = 0;
1.213 nicm 1356: data->cx = 0;
1357: data->oy = screen_hsize(data->backing);
1358:
1.264 nicm 1359: if (data->searchmark != NULL && !data->timeout)
1.296 nicm 1360: window_copy_search_marks(wme, NULL, data->searchregex, 1);
1.252 nicm 1361: window_copy_update_selection(wme, 1, 0);
1.213 nicm 1362: return (WINDOW_COPY_CMD_REDRAW);
1363: }
1364:
1365: static enum window_copy_cmd_action
1366: window_copy_cmd_jump_again(struct window_copy_cmd_state *cs)
1367: {
1368: struct window_mode_entry *wme = cs->wme;
1369: struct window_copy_mode_data *data = wme->data;
1370: u_int np = wme->prefix;
1371:
1372: switch (data->jumptype) {
1373: case WINDOW_COPY_JUMPFORWARD:
1374: for (; np != 0; np--)
1375: window_copy_cursor_jump(wme);
1376: break;
1377: case WINDOW_COPY_JUMPBACKWARD:
1378: for (; np != 0; np--)
1379: window_copy_cursor_jump_back(wme);
1380: break;
1381: case WINDOW_COPY_JUMPTOFORWARD:
1382: for (; np != 0; np--)
1383: window_copy_cursor_jump_to(wme);
1384: break;
1385: case WINDOW_COPY_JUMPTOBACKWARD:
1386: for (; np != 0; np--)
1387: window_copy_cursor_jump_to_back(wme);
1388: break;
1389: }
1390: return (WINDOW_COPY_CMD_NOTHING);
1391: }
1392:
1393: static enum window_copy_cmd_action
1394: window_copy_cmd_jump_reverse(struct window_copy_cmd_state *cs)
1395: {
1396: struct window_mode_entry *wme = cs->wme;
1397: struct window_copy_mode_data *data = wme->data;
1398: u_int np = wme->prefix;
1399:
1400: switch (data->jumptype) {
1401: case WINDOW_COPY_JUMPFORWARD:
1402: for (; np != 0; np--)
1403: window_copy_cursor_jump_back(wme);
1404: break;
1405: case WINDOW_COPY_JUMPBACKWARD:
1406: for (; np != 0; np--)
1407: window_copy_cursor_jump(wme);
1408: break;
1409: case WINDOW_COPY_JUMPTOFORWARD:
1410: for (; np != 0; np--)
1411: window_copy_cursor_jump_to_back(wme);
1412: break;
1413: case WINDOW_COPY_JUMPTOBACKWARD:
1414: for (; np != 0; np--)
1415: window_copy_cursor_jump_to(wme);
1416: break;
1417: }
1418: return (WINDOW_COPY_CMD_NOTHING);
1419: }
1420:
1421: static enum window_copy_cmd_action
1422: window_copy_cmd_middle_line(struct window_copy_cmd_state *cs)
1423: {
1424: struct window_mode_entry *wme = cs->wme;
1425: struct window_copy_mode_data *data = wme->data;
1426:
1427: data->cx = 0;
1428: data->cy = (screen_size_y(&data->screen) - 1) / 2;
1429:
1.252 nicm 1430: window_copy_update_selection(wme, 1, 0);
1.213 nicm 1431: return (WINDOW_COPY_CMD_REDRAW);
1432: }
1433:
1434: static enum window_copy_cmd_action
1.218 nicm 1435: window_copy_cmd_previous_matching_bracket(struct window_copy_cmd_state *cs)
1436: {
1437: struct window_mode_entry *wme = cs->wme;
1438: u_int np = wme->prefix;
1439: struct window_copy_mode_data *data = wme->data;
1440: struct screen *s = data->backing;
1441: char open[] = "{[(", close[] = "}])";
1442: char tried, found, start, *cp;
1.219 nicm 1443: u_int px, py, xx, n;
1.218 nicm 1444: struct grid_cell gc;
1445: int failed;
1446:
1447: for (; np != 0; np--) {
1448: /* Get cursor position and line length. */
1449: px = data->cx;
1450: py = screen_hsize(s) + data->cy - data->oy;
1451: xx = window_copy_find_length(wme, py);
1452: if (xx == 0)
1453: break;
1454:
1455: /*
1456: * Get the current character. If not on a bracket, try the
1457: * previous. If still not, then behave like previous-word.
1458: */
1459: tried = 0;
1460: retry:
1461: grid_get_cell(s->grid, px, py, &gc);
1462: if (gc.data.size != 1 || (gc.flags & GRID_FLAG_PADDING))
1463: cp = NULL;
1464: else {
1465: found = *gc.data.data;
1466: cp = strchr(close, found);
1467: }
1468: if (cp == NULL) {
1469: if (data->modekeys == MODEKEY_EMACS) {
1470: if (!tried && px > 0) {
1471: px--;
1472: tried = 1;
1473: goto retry;
1474: }
1.323 nicm 1475: window_copy_cursor_previous_word(wme, close, 1);
1.218 nicm 1476: }
1477: continue;
1478: }
1479: start = open[cp - close];
1480:
1481: /* Walk backward until the matching bracket is reached. */
1482: n = 1;
1483: failed = 0;
1484: do {
1485: if (px == 0) {
1486: if (py == 0) {
1487: failed = 1;
1488: break;
1489: }
1490: do {
1491: py--;
1492: xx = window_copy_find_length(wme, py);
1493: } while (xx == 0 && py > 0);
1494: if (xx == 0 && py == 0) {
1495: failed = 1;
1496: break;
1497: }
1498: px = xx - 1;
1499: } else
1500: px--;
1501:
1502: grid_get_cell(s->grid, px, py, &gc);
1503: if (gc.data.size == 1 &&
1504: (~gc.flags & GRID_FLAG_PADDING)) {
1505: if (*gc.data.data == found)
1506: n++;
1507: else if (*gc.data.data == start)
1508: n--;
1509: }
1510: } while (n != 0);
1511:
1512: /* Move the cursor to the found location if any. */
1513: if (!failed)
1.296 nicm 1514: window_copy_scroll_to(wme, px, py, 0);
1.218 nicm 1515: }
1516:
1517: return (WINDOW_COPY_CMD_NOTHING);
1518: }
1519:
1520: static enum window_copy_cmd_action
1521: window_copy_cmd_next_matching_bracket(struct window_copy_cmd_state *cs)
1522: {
1523: struct window_mode_entry *wme = cs->wme;
1524: u_int np = wme->prefix;
1525: struct window_copy_mode_data *data = wme->data;
1526: struct screen *s = data->backing;
1527: char open[] = "{[(", close[] = "}])";
1528: char tried, found, end, *cp;
1529: u_int px, py, xx, yy, sx, sy, n;
1530: struct grid_cell gc;
1531: int failed;
1532: struct grid_line *gl;
1533:
1534: for (; np != 0; np--) {
1535: /* Get cursor position and line length. */
1536: px = data->cx;
1537: py = screen_hsize(s) + data->cy - data->oy;
1538: xx = window_copy_find_length(wme, py);
1539: yy = screen_hsize(s) + screen_size_y(s) - 1;
1540: if (xx == 0)
1541: break;
1542:
1543: /*
1544: * Get the current character. If not on a bracket, try the
1545: * next. If still not, then behave like next-word.
1546: */
1547: tried = 0;
1548: retry:
1549: grid_get_cell(s->grid, px, py, &gc);
1550: if (gc.data.size != 1 || (gc.flags & GRID_FLAG_PADDING))
1551: cp = NULL;
1552: else {
1553: found = *gc.data.data;
1554:
1555: /*
1556: * In vi mode, attempt to move to previous bracket if a
1557: * closing bracket is found first. If this fails,
1558: * return to the original cursor position.
1559: */
1560: cp = strchr(close, found);
1561: if (cp != NULL && data->modekeys == MODEKEY_VI) {
1562: sx = data->cx;
1563: sy = screen_hsize(s) + data->cy - data->oy;
1564:
1.296 nicm 1565: window_copy_scroll_to(wme, px, py, 0);
1.218 nicm 1566: window_copy_cmd_previous_matching_bracket(cs);
1567:
1568: px = data->cx;
1569: py = screen_hsize(s) + data->cy - data->oy;
1570: grid_get_cell(s->grid, px, py, &gc);
1.286 nicm 1571: if (gc.data.size == 1 &&
1572: (~gc.flags & GRID_FLAG_PADDING) &&
1573: strchr(close, *gc.data.data) != NULL)
1.296 nicm 1574: window_copy_scroll_to(wme, sx, sy, 0);
1.218 nicm 1575: break;
1576: }
1577:
1578: cp = strchr(open, found);
1579: }
1580: if (cp == NULL) {
1581: if (data->modekeys == MODEKEY_EMACS) {
1582: if (!tried && px <= xx) {
1583: px++;
1584: tried = 1;
1585: goto retry;
1586: }
1.323 nicm 1587: window_copy_cursor_next_word_end(wme, open, 0);
1.218 nicm 1588: continue;
1589: }
1590: /* For vi, continue searching for bracket until EOL. */
1591: if (px > xx) {
1592: if (py == yy)
1593: continue;
1594: gl = grid_get_line(s->grid, py);
1595: if (~gl->flags & GRID_LINE_WRAPPED)
1596: continue;
1597: if (gl->cellsize > s->grid->sx)
1598: continue;
1599: px = 0;
1600: py++;
1601: xx = window_copy_find_length(wme, py);
1602: } else
1603: px++;
1604: goto retry;
1605: }
1606: end = close[cp - open];
1607:
1608: /* Walk forward until the matching bracket is reached. */
1609: n = 1;
1610: failed = 0;
1611: do {
1612: if (px > xx) {
1613: if (py == yy) {
1614: failed = 1;
1615: break;
1616: }
1617: px = 0;
1618: py++;
1619: xx = window_copy_find_length(wme, py);
1620: } else
1621: px++;
1622:
1623: grid_get_cell(s->grid, px, py, &gc);
1624: if (gc.data.size == 1 &&
1625: (~gc.flags & GRID_FLAG_PADDING)) {
1626: if (*gc.data.data == found)
1627: n++;
1628: else if (*gc.data.data == end)
1629: n--;
1630: }
1631: } while (n != 0);
1632:
1633: /* Move the cursor to the found location if any. */
1634: if (!failed)
1.296 nicm 1635: window_copy_scroll_to(wme, px, py, 0);
1.218 nicm 1636: }
1637:
1638: return (WINDOW_COPY_CMD_NOTHING);
1639: }
1640:
1641: static enum window_copy_cmd_action
1.213 nicm 1642: window_copy_cmd_next_paragraph(struct window_copy_cmd_state *cs)
1643: {
1644: struct window_mode_entry *wme = cs->wme;
1645: u_int np = wme->prefix;
1646:
1647: for (; np != 0; np--)
1648: window_copy_next_paragraph(wme);
1649: return (WINDOW_COPY_CMD_NOTHING);
1650: }
1651:
1652: static enum window_copy_cmd_action
1653: window_copy_cmd_next_space(struct window_copy_cmd_state *cs)
1654: {
1655: struct window_mode_entry *wme = cs->wme;
1656: u_int np = wme->prefix;
1657:
1658: for (; np != 0; np--)
1.323 nicm 1659: window_copy_cursor_next_word(wme, "");
1.213 nicm 1660: return (WINDOW_COPY_CMD_NOTHING);
1661: }
1662:
1663: static enum window_copy_cmd_action
1664: window_copy_cmd_next_space_end(struct window_copy_cmd_state *cs)
1665: {
1666: struct window_mode_entry *wme = cs->wme;
1667: u_int np = wme->prefix;
1668:
1669: for (; np != 0; np--)
1.323 nicm 1670: window_copy_cursor_next_word_end(wme, "", 0);
1.213 nicm 1671: return (WINDOW_COPY_CMD_NOTHING);
1672: }
1673:
1674: static enum window_copy_cmd_action
1675: window_copy_cmd_next_word(struct window_copy_cmd_state *cs)
1676: {
1677: struct window_mode_entry *wme = cs->wme;
1678: u_int np = wme->prefix;
1.323 nicm 1679: const char *separators;
1680:
1681: separators = options_get_string(cs->s->options, "word-separators");
1.213 nicm 1682:
1683: for (; np != 0; np--)
1.323 nicm 1684: window_copy_cursor_next_word(wme, separators);
1.213 nicm 1685: return (WINDOW_COPY_CMD_NOTHING);
1686: }
1687:
1688: static enum window_copy_cmd_action
1689: window_copy_cmd_next_word_end(struct window_copy_cmd_state *cs)
1690: {
1691: struct window_mode_entry *wme = cs->wme;
1692: u_int np = wme->prefix;
1.323 nicm 1693: const char *separators;
1694:
1695: separators = options_get_string(cs->s->options, "word-separators");
1.213 nicm 1696:
1697: for (; np != 0; np--)
1.323 nicm 1698: window_copy_cursor_next_word_end(wme, separators, 0);
1.213 nicm 1699: return (WINDOW_COPY_CMD_NOTHING);
1700: }
1701:
1702: static enum window_copy_cmd_action
1703: window_copy_cmd_other_end(struct window_copy_cmd_state *cs)
1704: {
1705: struct window_mode_entry *wme = cs->wme;
1706: u_int np = wme->prefix;
1.254 nicm 1707: struct window_copy_mode_data *data = wme->data;
1.213 nicm 1708:
1.254 nicm 1709: data->selflag = SEL_CHAR;
1.213 nicm 1710: if ((np % 2) != 0)
1711: window_copy_other_end(wme);
1712: return (WINDOW_COPY_CMD_NOTHING);
1713: }
1714:
1715: static enum window_copy_cmd_action
1716: window_copy_cmd_page_down(struct window_copy_cmd_state *cs)
1717: {
1718: struct window_mode_entry *wme = cs->wme;
1719: struct window_copy_mode_data *data = wme->data;
1720: u_int np = wme->prefix;
1721:
1722: for (; np != 0; np--) {
1723: if (window_copy_pagedown(wme, 0, data->scroll_exit))
1724: return (WINDOW_COPY_CMD_CANCEL);
1725: }
1726: return (WINDOW_COPY_CMD_NOTHING);
1727: }
1728:
1729: static enum window_copy_cmd_action
1730: window_copy_cmd_page_down_and_cancel(struct window_copy_cmd_state *cs)
1731: {
1732: struct window_mode_entry *wme = cs->wme;
1733: u_int np = wme->prefix;
1734:
1735: for (; np != 0; np--) {
1736: if (window_copy_pagedown(wme, 0, 1))
1737: return (WINDOW_COPY_CMD_CANCEL);
1738: }
1739: return (WINDOW_COPY_CMD_NOTHING);
1740: }
1741:
1742: static enum window_copy_cmd_action
1743: window_copy_cmd_page_up(struct window_copy_cmd_state *cs)
1744: {
1745: struct window_mode_entry *wme = cs->wme;
1746: u_int np = wme->prefix;
1747:
1748: for (; np != 0; np--)
1749: window_copy_pageup1(wme, 0);
1750: return (WINDOW_COPY_CMD_NOTHING);
1751: }
1752:
1753: static enum window_copy_cmd_action
1754: window_copy_cmd_previous_paragraph(struct window_copy_cmd_state *cs)
1755: {
1756: struct window_mode_entry *wme = cs->wme;
1757: u_int np = wme->prefix;
1758:
1759: for (; np != 0; np--)
1760: window_copy_previous_paragraph(wme);
1761: return (WINDOW_COPY_CMD_NOTHING);
1762: }
1763:
1764: static enum window_copy_cmd_action
1765: window_copy_cmd_previous_space(struct window_copy_cmd_state *cs)
1766: {
1767: struct window_mode_entry *wme = cs->wme;
1768: u_int np = wme->prefix;
1769:
1770: for (; np != 0; np--)
1.323 nicm 1771: window_copy_cursor_previous_word(wme, "", 1);
1.213 nicm 1772: return (WINDOW_COPY_CMD_NOTHING);
1773: }
1774:
1775: static enum window_copy_cmd_action
1776: window_copy_cmd_previous_word(struct window_copy_cmd_state *cs)
1777: {
1778: struct window_mode_entry *wme = cs->wme;
1779: u_int np = wme->prefix;
1.323 nicm 1780: const char *separators;
1781:
1782: separators = options_get_string(cs->s->options, "word-separators");
1.213 nicm 1783:
1784: for (; np != 0; np--)
1.323 nicm 1785: window_copy_cursor_previous_word(wme, separators, 1);
1.213 nicm 1786: return (WINDOW_COPY_CMD_NOTHING);
1787: }
1788:
1789: static enum window_copy_cmd_action
1.313 nicm 1790: window_copy_cmd_rectangle_on(struct window_copy_cmd_state *cs)
1791: {
1792: struct window_mode_entry *wme = cs->wme;
1793: struct window_copy_mode_data *data = wme->data;
1794:
1795: data->lineflag = LINE_SEL_NONE;
1796: window_copy_rectangle_set(wme, 1);
1797:
1798: return (WINDOW_COPY_CMD_NOTHING);
1799: }
1800:
1801: static enum window_copy_cmd_action
1802: window_copy_cmd_rectangle_off(struct window_copy_cmd_state *cs)
1803: {
1804: struct window_mode_entry *wme = cs->wme;
1805: struct window_copy_mode_data *data = wme->data;
1806:
1807: data->lineflag = LINE_SEL_NONE;
1808: window_copy_rectangle_set(wme, 0);
1809:
1810: return (WINDOW_COPY_CMD_NOTHING);
1811: }
1812:
1813: static enum window_copy_cmd_action
1.213 nicm 1814: window_copy_cmd_rectangle_toggle(struct window_copy_cmd_state *cs)
1815: {
1816: struct window_mode_entry *wme = cs->wme;
1817: struct window_copy_mode_data *data = wme->data;
1818:
1819: data->lineflag = LINE_SEL_NONE;
1.313 nicm 1820: window_copy_rectangle_set(wme, !data->rectflag);
1.213 nicm 1821:
1822: return (WINDOW_COPY_CMD_NOTHING);
1823: }
1824:
1825: static enum window_copy_cmd_action
1826: window_copy_cmd_scroll_down(struct window_copy_cmd_state *cs)
1827: {
1828: struct window_mode_entry *wme = cs->wme;
1829: struct window_copy_mode_data *data = wme->data;
1830: u_int np = wme->prefix;
1831:
1832: for (; np != 0; np--)
1833: window_copy_cursor_down(wme, 1);
1834: if (data->scroll_exit && data->oy == 0)
1835: return (WINDOW_COPY_CMD_CANCEL);
1836: return (WINDOW_COPY_CMD_NOTHING);
1837: }
1838:
1839: static enum window_copy_cmd_action
1840: window_copy_cmd_scroll_down_and_cancel(struct window_copy_cmd_state *cs)
1841: {
1842: struct window_mode_entry *wme = cs->wme;
1843: struct window_copy_mode_data *data = wme->data;
1844: u_int np = wme->prefix;
1845:
1846: for (; np != 0; np--)
1847: window_copy_cursor_down(wme, 1);
1848: if (data->oy == 0)
1849: return (WINDOW_COPY_CMD_CANCEL);
1850: return (WINDOW_COPY_CMD_NOTHING);
1851: }
1852:
1853: static enum window_copy_cmd_action
1854: window_copy_cmd_scroll_up(struct window_copy_cmd_state *cs)
1855: {
1856: struct window_mode_entry *wme = cs->wme;
1857: u_int np = wme->prefix;
1858:
1859: for (; np != 0; np--)
1860: window_copy_cursor_up(wme, 1);
1861: return (WINDOW_COPY_CMD_NOTHING);
1862: }
1863:
1864: static enum window_copy_cmd_action
1865: window_copy_cmd_search_again(struct window_copy_cmd_state *cs)
1866: {
1867: struct window_mode_entry *wme = cs->wme;
1868: struct window_copy_mode_data *data = wme->data;
1869: u_int np = wme->prefix;
1870:
1871: if (data->searchtype == WINDOW_COPY_SEARCHUP) {
1872: for (; np != 0; np--)
1.321 nicm 1873: window_copy_search_up(wme, data->searchregex);
1.213 nicm 1874: } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
1875: for (; np != 0; np--)
1.321 nicm 1876: window_copy_search_down(wme, data->searchregex);
1.213 nicm 1877: }
1878: return (WINDOW_COPY_CMD_NOTHING);
1879: }
1880:
1881: static enum window_copy_cmd_action
1882: window_copy_cmd_search_reverse(struct window_copy_cmd_state *cs)
1883: {
1884: struct window_mode_entry *wme = cs->wme;
1885: struct window_copy_mode_data *data = wme->data;
1886: u_int np = wme->prefix;
1887:
1888: if (data->searchtype == WINDOW_COPY_SEARCHUP) {
1889: for (; np != 0; np--)
1.321 nicm 1890: window_copy_search_down(wme, data->searchregex);
1.213 nicm 1891: } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
1892: for (; np != 0; np--)
1.321 nicm 1893: window_copy_search_up(wme, data->searchregex);
1.213 nicm 1894: }
1895: return (WINDOW_COPY_CMD_NOTHING);
1896: }
1897:
1898: static enum window_copy_cmd_action
1899: window_copy_cmd_select_line(struct window_copy_cmd_state *cs)
1900: {
1901: struct window_mode_entry *wme = cs->wme;
1902: struct window_copy_mode_data *data = wme->data;
1903: u_int np = wme->prefix;
1904:
1905: data->lineflag = LINE_SEL_LEFT_RIGHT;
1906: data->rectflag = 0;
1.247 nicm 1907: data->selflag = SEL_LINE;
1908: data->dx = data->cx;
1909: data->dy = screen_hsize(data->backing) + data->cy - data->oy;
1.213 nicm 1910:
1911: window_copy_cursor_start_of_line(wme);
1.247 nicm 1912: data->selrx = data->cx;
1913: data->selry = screen_hsize(data->backing) + data->cy - data->oy;
1.258 nicm 1914: data->endselry = data->selry;
1.213 nicm 1915: window_copy_start_selection(wme);
1.319 nicm 1916: window_copy_cursor_end_of_line(wme);
1917: data->endselry = screen_hsize(data->backing) + data->cy - data->oy;
1918: data->endselrx = window_copy_find_length(wme, data->endselry);
1919: for (; np > 1; np--) {
1.213 nicm 1920: window_copy_cursor_down(wme, 0);
1.319 nicm 1921: window_copy_cursor_end_of_line(wme);
1922: }
1.213 nicm 1923:
1924: return (WINDOW_COPY_CMD_REDRAW);
1925: }
1926:
1927: static enum window_copy_cmd_action
1928: window_copy_cmd_select_word(struct window_copy_cmd_state *cs)
1929: {
1930: struct window_mode_entry *wme = cs->wme;
1.323 nicm 1931: struct options *session_options = cs->s->options;
1.213 nicm 1932: struct window_copy_mode_data *data = wme->data;
1.319 nicm 1933: u_int px, py, nextx, nexty;
1.323 nicm 1934:
1.213 nicm 1935: data->lineflag = LINE_SEL_LEFT_RIGHT;
1936: data->rectflag = 0;
1.247 nicm 1937: data->selflag = SEL_WORD;
1938: data->dx = data->cx;
1939: data->dy = screen_hsize(data->backing) + data->cy - data->oy;
1.213 nicm 1940:
1.323 nicm 1941: data->separators = options_get_string(session_options,
1942: "word-separators");
1943: window_copy_cursor_previous_word(wme, data->separators, 0);
1.245 nicm 1944: px = data->cx;
1945: py = screen_hsize(data->backing) + data->cy - data->oy;
1.257 nicm 1946: data->selrx = px;
1947: data->selry = py;
1.213 nicm 1948: window_copy_start_selection(wme);
1.245 nicm 1949:
1.319 nicm 1950: /* Handle single character words. */
1951: nextx = px + 1;
1952: nexty = py;
1953: if (grid_get_line(data->backing->grid, nexty)->flags &
1954: GRID_LINE_WRAPPED && nextx > screen_size_x(data->backing) - 1) {
1955: nextx = 0;
1956: nexty++;
1957: }
1.247 nicm 1958: if (px >= window_copy_find_length(wme, py) ||
1.323 nicm 1959: !window_copy_in_set(wme, nextx, nexty, WHITESPACE))
1960: window_copy_cursor_next_word_end(wme, data->separators, 1);
1.245 nicm 1961: else {
1962: window_copy_update_cursor(wme, px, data->cy);
1.255 nicm 1963: if (window_copy_update_selection(wme, 1, 1))
1.245 nicm 1964: window_copy_redraw_lines(wme, data->cy, 1);
1965: }
1.247 nicm 1966: data->endselrx = data->cx;
1967: data->endselry = screen_hsize(data->backing) + data->cy - data->oy;
1.319 nicm 1968: if (data->dy > data->endselry) {
1969: data->dy = data->endselry;
1970: data->dx = data->endselrx;
1971: } else if (data->dx > data->endselrx)
1.257 nicm 1972: data->dx = data->endselrx;
1.213 nicm 1973:
1974: return (WINDOW_COPY_CMD_REDRAW);
1975: }
1976:
1977: static enum window_copy_cmd_action
1.288 nicm 1978: window_copy_cmd_set_mark(struct window_copy_cmd_state *cs)
1979: {
1980: struct window_copy_mode_data *data = cs->wme->data;
1981:
1982: data->mx = data->cx;
1983: data->my = screen_hsize(data->backing) + data->cy - data->oy;
1984: data->showmark = 1;
1985: return (WINDOW_COPY_CMD_REDRAW);
1986: }
1987:
1988: static enum window_copy_cmd_action
1.213 nicm 1989: window_copy_cmd_start_of_line(struct window_copy_cmd_state *cs)
1990: {
1991: struct window_mode_entry *wme = cs->wme;
1992:
1993: window_copy_cursor_start_of_line(wme);
1994: return (WINDOW_COPY_CMD_NOTHING);
1995: }
1996:
1997: static enum window_copy_cmd_action
1998: window_copy_cmd_top_line(struct window_copy_cmd_state *cs)
1999: {
2000: struct window_mode_entry *wme = cs->wme;
2001: struct window_copy_mode_data *data = wme->data;
2002:
2003: data->cx = 0;
2004: data->cy = 0;
2005:
1.252 nicm 2006: window_copy_update_selection(wme, 1, 0);
1.213 nicm 2007: return (WINDOW_COPY_CMD_REDRAW);
2008: }
2009:
2010: static enum window_copy_cmd_action
1.216 nicm 2011: window_copy_cmd_copy_pipe_no_clear(struct window_copy_cmd_state *cs)
1.213 nicm 2012: {
2013: struct window_mode_entry *wme = cs->wme;
1.215 nicm 2014: struct client *c = cs->c;
1.213 nicm 2015: struct session *s = cs->s;
1.215 nicm 2016: struct winlink *wl = cs->wl;
2017: struct window_pane *wp = wme->wp;
1.329 nicm 2018: char *command = NULL, *prefix = NULL;
2019: const char *arg1 = args_string(cs->args, 1);
2020: const char *arg2 = args_string(cs->args, 2);
1.215 nicm 2021:
1.329 nicm 2022: if (arg2 != NULL)
2023: prefix = format_single(NULL, arg2, c, s, wl, wp);
1.215 nicm 2024:
1.329 nicm 2025: if (s != NULL && arg1 != NULL && *arg1 != '\0')
2026: command = format_single(NULL, arg1, c, s, wl, wp);
1.277 nicm 2027: window_copy_copy_pipe(wme, s, prefix, command);
2028: free(command);
1.213 nicm 2029:
1.215 nicm 2030: free(prefix);
1.213 nicm 2031: return (WINDOW_COPY_CMD_NOTHING);
2032: }
2033:
2034: static enum window_copy_cmd_action
1.216 nicm 2035: window_copy_cmd_copy_pipe(struct window_copy_cmd_state *cs)
1.213 nicm 2036: {
2037: struct window_mode_entry *wme = cs->wme;
1.215 nicm 2038:
1.216 nicm 2039: window_copy_cmd_copy_pipe_no_clear(cs);
2040: window_copy_clear_selection(wme);
2041: return (WINDOW_COPY_CMD_REDRAW);
2042: }
1.215 nicm 2043:
1.216 nicm 2044: static enum window_copy_cmd_action
2045: window_copy_cmd_copy_pipe_and_cancel(struct window_copy_cmd_state *cs)
2046: {
2047: struct window_mode_entry *wme = cs->wme;
1.213 nicm 2048:
1.216 nicm 2049: window_copy_cmd_copy_pipe_no_clear(cs);
2050: window_copy_clear_selection(wme);
2051: return (WINDOW_COPY_CMD_CANCEL);
1.213 nicm 2052: }
2053:
2054: static enum window_copy_cmd_action
1.314 nicm 2055: window_copy_cmd_pipe_no_clear(struct window_copy_cmd_state *cs)
2056: {
2057: struct window_mode_entry *wme = cs->wme;
2058: struct client *c = cs->c;
2059: struct session *s = cs->s;
2060: struct winlink *wl = cs->wl;
2061: struct window_pane *wp = wme->wp;
2062: char *command = NULL;
1.329 nicm 2063: const char *arg1 = args_string(cs->args, 1);
1.314 nicm 2064:
1.329 nicm 2065: if (s != NULL && arg1 != NULL && *arg1 != '\0')
2066: command = format_single(NULL, arg1, c, s, wl, wp);
1.314 nicm 2067: window_copy_pipe(wme, s, command);
2068: free(command);
2069:
2070: return (WINDOW_COPY_CMD_NOTHING);
2071: }
2072:
2073: static enum window_copy_cmd_action
2074: window_copy_cmd_pipe(struct window_copy_cmd_state *cs)
2075: {
2076: struct window_mode_entry *wme = cs->wme;
2077:
2078: window_copy_cmd_pipe_no_clear(cs);
2079: window_copy_clear_selection(wme);
2080: return (WINDOW_COPY_CMD_REDRAW);
2081: }
2082:
2083: static enum window_copy_cmd_action
2084: window_copy_cmd_pipe_and_cancel(struct window_copy_cmd_state *cs)
2085: {
2086: struct window_mode_entry *wme = cs->wme;
2087:
2088: window_copy_cmd_pipe_no_clear(cs);
2089: window_copy_clear_selection(wme);
2090: return (WINDOW_COPY_CMD_CANCEL);
2091: }
2092:
2093: static enum window_copy_cmd_action
1.213 nicm 2094: window_copy_cmd_goto_line(struct window_copy_cmd_state *cs)
2095: {
2096: struct window_mode_entry *wme = cs->wme;
1.329 nicm 2097: const char *arg1 = args_string(cs->args, 1);
1.213 nicm 2098:
1.329 nicm 2099: if (*arg1 != '\0')
2100: window_copy_goto_line(wme, arg1);
1.213 nicm 2101: return (WINDOW_COPY_CMD_NOTHING);
2102: }
2103:
2104: static enum window_copy_cmd_action
2105: window_copy_cmd_jump_backward(struct window_copy_cmd_state *cs)
2106: {
2107: struct window_mode_entry *wme = cs->wme;
2108: struct window_copy_mode_data *data = wme->data;
2109: u_int np = wme->prefix;
1.329 nicm 2110: const char *arg1 = args_string(cs->args, 1);
1.213 nicm 2111:
1.329 nicm 2112: if (*arg1 != '\0') {
1.213 nicm 2113: data->jumptype = WINDOW_COPY_JUMPBACKWARD;
1.315 nicm 2114: free(data->jumpchar);
1.329 nicm 2115: data->jumpchar = utf8_fromcstr(arg1);
1.213 nicm 2116: for (; np != 0; np--)
2117: window_copy_cursor_jump_back(wme);
2118: }
2119: return (WINDOW_COPY_CMD_NOTHING);
2120: }
2121:
2122: static enum window_copy_cmd_action
2123: window_copy_cmd_jump_forward(struct window_copy_cmd_state *cs)
2124: {
2125: struct window_mode_entry *wme = cs->wme;
2126: struct window_copy_mode_data *data = wme->data;
2127: u_int np = wme->prefix;
1.329 nicm 2128: const char *arg1 = args_string(cs->args, 1);
1.213 nicm 2129:
1.329 nicm 2130: if (*arg1 != '\0') {
1.213 nicm 2131: data->jumptype = WINDOW_COPY_JUMPFORWARD;
1.315 nicm 2132: free(data->jumpchar);
1.329 nicm 2133: data->jumpchar = utf8_fromcstr(arg1);
1.213 nicm 2134: for (; np != 0; np--)
1.215 nicm 2135: window_copy_cursor_jump(wme);
1.213 nicm 2136: }
2137: return (WINDOW_COPY_CMD_NOTHING);
2138: }
2139:
2140: static enum window_copy_cmd_action
2141: window_copy_cmd_jump_to_backward(struct window_copy_cmd_state *cs)
2142: {
2143: struct window_mode_entry *wme = cs->wme;
2144: struct window_copy_mode_data *data = wme->data;
2145: u_int np = wme->prefix;
1.329 nicm 2146: const char *arg1 = args_string(cs->args, 1);
1.213 nicm 2147:
1.329 nicm 2148: if (*arg1 != '\0') {
1.213 nicm 2149: data->jumptype = WINDOW_COPY_JUMPTOBACKWARD;
1.315 nicm 2150: free(data->jumpchar);
1.329 nicm 2151: data->jumpchar = utf8_fromcstr(arg1);
1.213 nicm 2152: for (; np != 0; np--)
2153: window_copy_cursor_jump_to_back(wme);
2154: }
2155: return (WINDOW_COPY_CMD_NOTHING);
2156: }
2157:
2158: static enum window_copy_cmd_action
2159: window_copy_cmd_jump_to_forward(struct window_copy_cmd_state *cs)
2160: {
2161: struct window_mode_entry *wme = cs->wme;
2162: struct window_copy_mode_data *data = wme->data;
2163: u_int np = wme->prefix;
1.329 nicm 2164: const char *arg1 = args_string(cs->args, 1);
1.213 nicm 2165:
1.329 nicm 2166: if (*arg1 != '\0') {
1.213 nicm 2167: data->jumptype = WINDOW_COPY_JUMPTOFORWARD;
1.315 nicm 2168: free(data->jumpchar);
1.329 nicm 2169: data->jumpchar = utf8_fromcstr(arg1);
1.213 nicm 2170: for (; np != 0; np--)
2171: window_copy_cursor_jump_to(wme);
2172: }
2173: return (WINDOW_COPY_CMD_NOTHING);
2174: }
2175:
2176: static enum window_copy_cmd_action
1.288 nicm 2177: window_copy_cmd_jump_to_mark(struct window_copy_cmd_state *cs)
2178: {
2179: struct window_mode_entry *wme = cs->wme;
2180:
2181: window_copy_jump_to_mark(wme);
2182: return (WINDOW_COPY_CMD_NOTHING);
2183: }
2184:
2185: static enum window_copy_cmd_action
1.213 nicm 2186: window_copy_cmd_search_backward(struct window_copy_cmd_state *cs)
2187: {
2188: struct window_mode_entry *wme = cs->wme;
2189: struct window_copy_mode_data *data = wme->data;
2190: u_int np = wme->prefix;
2191:
1.259 nicm 2192: if (!window_copy_expand_search_string(cs))
2193: return (WINDOW_COPY_CMD_NOTHING);
2194:
2195: if (data->searchstr != NULL) {
2196: data->searchtype = WINDOW_COPY_SEARCHUP;
2197: data->searchregex = 1;
1.263 nicm 2198: data->timeout = 0;
1.259 nicm 2199: for (; np != 0; np--)
1.321 nicm 2200: window_copy_search_up(wme, 1);
1.233 nicm 2201: }
1.259 nicm 2202: return (WINDOW_COPY_CMD_NOTHING);
2203: }
2204:
2205: static enum window_copy_cmd_action
2206: window_copy_cmd_search_backward_text(struct window_copy_cmd_state *cs)
2207: {
2208: struct window_mode_entry *wme = cs->wme;
2209: struct window_copy_mode_data *data = wme->data;
2210: u_int np = wme->prefix;
2211:
2212: if (!window_copy_expand_search_string(cs))
2213: return (WINDOW_COPY_CMD_NOTHING);
2214:
1.233 nicm 2215: if (data->searchstr != NULL) {
1.232 nicm 2216: data->searchtype = WINDOW_COPY_SEARCHUP;
1.259 nicm 2217: data->searchregex = 0;
1.263 nicm 2218: data->timeout = 0;
1.213 nicm 2219: for (; np != 0; np--)
1.321 nicm 2220: window_copy_search_up(wme, 0);
1.213 nicm 2221: }
2222: return (WINDOW_COPY_CMD_NOTHING);
2223: }
2224:
2225: static enum window_copy_cmd_action
2226: window_copy_cmd_search_forward(struct window_copy_cmd_state *cs)
2227: {
2228: struct window_mode_entry *wme = cs->wme;
2229: struct window_copy_mode_data *data = wme->data;
2230: u_int np = wme->prefix;
2231:
1.259 nicm 2232: if (!window_copy_expand_search_string(cs))
2233: return (WINDOW_COPY_CMD_NOTHING);
2234:
2235: if (data->searchstr != NULL) {
2236: data->searchtype = WINDOW_COPY_SEARCHDOWN;
2237: data->searchregex = 1;
1.263 nicm 2238: data->timeout = 0;
1.259 nicm 2239: for (; np != 0; np--)
1.321 nicm 2240: window_copy_search_down(wme, 1);
1.233 nicm 2241: }
1.259 nicm 2242: return (WINDOW_COPY_CMD_NOTHING);
2243: }
2244:
2245: static enum window_copy_cmd_action
2246: window_copy_cmd_search_forward_text(struct window_copy_cmd_state *cs)
2247: {
2248: struct window_mode_entry *wme = cs->wme;
2249: struct window_copy_mode_data *data = wme->data;
2250: u_int np = wme->prefix;
2251:
2252: if (!window_copy_expand_search_string(cs))
2253: return (WINDOW_COPY_CMD_NOTHING);
2254:
1.233 nicm 2255: if (data->searchstr != NULL) {
1.232 nicm 2256: data->searchtype = WINDOW_COPY_SEARCHDOWN;
1.259 nicm 2257: data->searchregex = 0;
1.263 nicm 2258: data->timeout = 0;
1.213 nicm 2259: for (; np != 0; np--)
1.321 nicm 2260: window_copy_search_down(wme, 0);
1.213 nicm 2261: }
2262: return (WINDOW_COPY_CMD_NOTHING);
2263: }
2264:
2265: static enum window_copy_cmd_action
2266: window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs)
2267: {
2268: struct window_mode_entry *wme = cs->wme;
2269: struct window_copy_mode_data *data = wme->data;
1.329 nicm 2270: const char *arg1 = args_string(cs->args, 1);
1.225 nicm 2271: const char *ss = data->searchstr;
2272: char prefix;
1.213 nicm 2273: enum window_copy_cmd_action action = WINDOW_COPY_CMD_NOTHING;
2274:
1.263 nicm 2275: data->timeout = 0;
2276:
1.329 nicm 2277: log_debug("%s: %s", __func__, arg1);
1.310 nicm 2278:
1.329 nicm 2279: prefix = *arg1++;
1.213 nicm 2280: if (data->searchx == -1 || data->searchy == -1) {
2281: data->searchx = data->cx;
2282: data->searchy = data->cy;
2283: data->searcho = data->oy;
1.329 nicm 2284: } else if (ss != NULL && strcmp(arg1, ss) != 0) {
1.213 nicm 2285: data->cx = data->searchx;
2286: data->cy = data->searchy;
2287: data->oy = data->searcho;
2288: action = WINDOW_COPY_CMD_REDRAW;
2289: }
1.329 nicm 2290: if (*arg1 == '\0') {
1.213 nicm 2291: window_copy_clear_marks(wme);
2292: return (WINDOW_COPY_CMD_REDRAW);
2293: }
1.225 nicm 2294: switch (prefix) {
1.213 nicm 2295: case '=':
2296: case '-':
2297: data->searchtype = WINDOW_COPY_SEARCHUP;
1.259 nicm 2298: data->searchregex = 0;
1.213 nicm 2299: free(data->searchstr);
1.329 nicm 2300: data->searchstr = xstrdup(arg1);
1.321 nicm 2301: if (!window_copy_search_up(wme, 0)) {
1.213 nicm 2302: window_copy_clear_marks(wme);
2303: return (WINDOW_COPY_CMD_REDRAW);
2304: }
2305: break;
2306: case '+':
2307: data->searchtype = WINDOW_COPY_SEARCHDOWN;
1.259 nicm 2308: data->searchregex = 0;
1.213 nicm 2309: free(data->searchstr);
1.329 nicm 2310: data->searchstr = xstrdup(arg1);
1.321 nicm 2311: if (!window_copy_search_down(wme, 0)) {
1.213 nicm 2312: window_copy_clear_marks(wme);
2313: return (WINDOW_COPY_CMD_REDRAW);
2314: }
2315: break;
2316: }
2317: return (action);
2318: }
2319:
2320: static enum window_copy_cmd_action
2321: window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs)
2322: {
2323: struct window_mode_entry *wme = cs->wme;
2324: struct window_copy_mode_data *data = wme->data;
1.329 nicm 2325: const char *arg1 = args_string(cs->args, 1);
1.225 nicm 2326: const char *ss = data->searchstr;
2327: char prefix;
1.213 nicm 2328: enum window_copy_cmd_action action = WINDOW_COPY_CMD_NOTHING;
2329:
1.263 nicm 2330: data->timeout = 0;
1.310 nicm 2331:
1.329 nicm 2332: log_debug("%s: %s", __func__, arg1);
1.263 nicm 2333:
1.329 nicm 2334: prefix = *arg1++;
1.213 nicm 2335: if (data->searchx == -1 || data->searchy == -1) {
2336: data->searchx = data->cx;
2337: data->searchy = data->cy;
2338: data->searcho = data->oy;
1.329 nicm 2339: } else if (ss != NULL && strcmp(arg1, ss) != 0) {
1.213 nicm 2340: data->cx = data->searchx;
2341: data->cy = data->searchy;
2342: data->oy = data->searcho;
2343: action = WINDOW_COPY_CMD_REDRAW;
2344: }
1.329 nicm 2345: if (*arg1 == '\0') {
1.213 nicm 2346: window_copy_clear_marks(wme);
2347: return (WINDOW_COPY_CMD_REDRAW);
2348: }
1.225 nicm 2349: switch (prefix) {
1.213 nicm 2350: case '=':
2351: case '+':
2352: data->searchtype = WINDOW_COPY_SEARCHDOWN;
1.259 nicm 2353: data->searchregex = 0;
1.213 nicm 2354: free(data->searchstr);
1.329 nicm 2355: data->searchstr = xstrdup(arg1);
1.321 nicm 2356: if (!window_copy_search_down(wme, 0)) {
1.213 nicm 2357: window_copy_clear_marks(wme);
2358: return (WINDOW_COPY_CMD_REDRAW);
2359: }
2360: break;
2361: case '-':
2362: data->searchtype = WINDOW_COPY_SEARCHUP;
1.259 nicm 2363: data->searchregex = 0;
1.213 nicm 2364: free(data->searchstr);
1.329 nicm 2365: data->searchstr = xstrdup(arg1);
1.321 nicm 2366: if (!window_copy_search_up(wme, 0)) {
1.213 nicm 2367: window_copy_clear_marks(wme);
2368: return (WINDOW_COPY_CMD_REDRAW);
2369: }
2370: }
2371: return (action);
2372: }
2373:
1.266 nicm 2374: static enum window_copy_cmd_action
2375: window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state *cs)
2376: {
2377: struct window_mode_entry *wme = cs->wme;
1.270 nicm 2378: struct window_pane *wp = wme->swp;
1.266 nicm 2379: struct window_copy_mode_data *data = wme->data;
2380:
2381: if (data->viewmode)
2382: return (WINDOW_COPY_CMD_NOTHING);
2383:
2384: screen_free(data->backing);
2385: free(data->backing);
1.326 nicm 2386: data->backing = window_copy_clone_screen(&wp->base, &data->screen, NULL, NULL, wme->swp != wme->wp);
1.266 nicm 2387:
1.275 nicm 2388: window_copy_size_changed(wme);
1.266 nicm 2389: return (WINDOW_COPY_CMD_REDRAW);
2390: }
2391:
1.213 nicm 2392: static const struct {
2393: const char *command;
1.329 nicm 2394: u_int minargs;
2395: u_int maxargs;
1.295 nicm 2396: enum window_copy_cmd_clear clear;
1.213 nicm 2397: enum window_copy_cmd_action (*f)(struct window_copy_cmd_state *);
2398: } window_copy_cmd_table[] = {
1.326 nicm 2399: { .command = "append-selection",
2400: .minargs = 0,
2401: .maxargs = 0,
2402: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2403: .f = window_copy_cmd_append_selection
2404: },
2405: { .command = "append-selection-and-cancel",
2406: .minargs = 0,
2407: .maxargs = 0,
2408: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2409: .f = window_copy_cmd_append_selection_and_cancel
2410: },
2411: { .command = "back-to-indentation",
2412: .minargs = 0,
2413: .maxargs = 0,
2414: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2415: .f = window_copy_cmd_back_to_indentation
2416: },
2417: { .command = "begin-selection",
2418: .minargs = 0,
2419: .maxargs = 0,
2420: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2421: .f = window_copy_cmd_begin_selection
2422: },
2423: { .command = "bottom-line",
2424: .minargs = 0,
2425: .maxargs = 0,
2426: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2427: .f = window_copy_cmd_bottom_line
2428: },
2429: { .command = "cancel",
2430: .minargs = 0,
2431: .maxargs = 0,
2432: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2433: .f = window_copy_cmd_cancel
2434: },
2435: { .command = "clear-selection",
2436: .minargs = 0,
2437: .maxargs = 0,
2438: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2439: .f = window_copy_cmd_clear_selection
2440: },
2441: { .command = "copy-end-of-line",
2442: .minargs = 0,
2443: .maxargs = 1,
2444: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2445: .f = window_copy_cmd_copy_end_of_line
2446: },
2447: { .command = "copy-end-of-line-and-cancel",
2448: .minargs = 0,
2449: .maxargs = 1,
2450: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2451: .f = window_copy_cmd_copy_end_of_line_and_cancel
2452: },
2453: { .command = "copy-pipe-end-of-line",
2454: .minargs = 0,
2455: .maxargs = 2,
2456: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2457: .f = window_copy_cmd_copy_pipe_end_of_line
2458: },
2459: { .command = "copy-pipe-end-of-line-and-cancel",
2460: .minargs = 0,
2461: .maxargs = 2,
2462: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2463: .f = window_copy_cmd_copy_pipe_end_of_line_and_cancel
2464: },
2465: { .command = "copy-line",
2466: .minargs = 0,
2467: .maxargs = 1,
2468: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2469: .f = window_copy_cmd_copy_line
2470: },
2471: { .command = "copy-line-and-cancel",
2472: .minargs = 0,
2473: .maxargs = 1,
2474: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2475: .f = window_copy_cmd_copy_line_and_cancel
2476: },
2477: { .command = "copy-pipe-line",
2478: .minargs = 0,
2479: .maxargs = 2,
2480: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2481: .f = window_copy_cmd_copy_pipe_line
2482: },
2483: { .command = "copy-pipe-line-and-cancel",
2484: .minargs = 0,
2485: .maxargs = 2,
2486: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2487: .f = window_copy_cmd_copy_pipe_line_and_cancel
2488: },
2489: { .command = "copy-pipe-no-clear",
2490: .minargs = 0,
2491: .maxargs = 2,
2492: .clear = WINDOW_COPY_CMD_CLEAR_NEVER,
2493: .f = window_copy_cmd_copy_pipe_no_clear
2494: },
2495: { .command = "copy-pipe",
2496: .minargs = 0,
2497: .maxargs = 2,
2498: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2499: .f = window_copy_cmd_copy_pipe
2500: },
2501: { .command = "copy-pipe-and-cancel",
2502: .minargs = 0,
2503: .maxargs = 2,
2504: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2505: .f = window_copy_cmd_copy_pipe_and_cancel
2506: },
2507: { .command = "copy-selection-no-clear",
2508: .minargs = 0,
2509: .maxargs = 1,
2510: .clear = WINDOW_COPY_CMD_CLEAR_NEVER,
2511: .f = window_copy_cmd_copy_selection_no_clear
2512: },
2513: { .command = "copy-selection",
2514: .minargs = 0,
2515: .maxargs = 1,
2516: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2517: .f = window_copy_cmd_copy_selection
2518: },
2519: { .command = "copy-selection-and-cancel",
2520: .minargs = 0,
2521: .maxargs = 1,
2522: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2523: .f = window_copy_cmd_copy_selection_and_cancel
2524: },
2525: { .command = "cursor-down",
2526: .minargs = 0,
2527: .maxargs = 0,
2528: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2529: .f = window_copy_cmd_cursor_down
2530: },
2531: { .command = "cursor-down-and-cancel",
2532: .minargs = 0,
2533: .maxargs = 0,
2534: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2535: .f = window_copy_cmd_cursor_down_and_cancel
2536: },
2537: { .command = "cursor-left",
2538: .minargs = 0,
2539: .maxargs = 0,
2540: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2541: .f = window_copy_cmd_cursor_left
2542: },
2543: { .command = "cursor-right",
2544: .minargs = 0,
2545: .maxargs = 0,
2546: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2547: .f = window_copy_cmd_cursor_right
2548: },
2549: { .command = "cursor-up",
2550: .minargs = 0,
2551: .maxargs = 0,
2552: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2553: .f = window_copy_cmd_cursor_up
2554: },
2555: { .command = "end-of-line",
2556: .minargs = 0,
2557: .maxargs = 0,
2558: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2559: .f = window_copy_cmd_end_of_line
2560: },
2561: { .command = "goto-line",
2562: .minargs = 1,
2563: .maxargs = 1,
2564: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2565: .f = window_copy_cmd_goto_line
2566: },
2567: { .command = "halfpage-down",
2568: .minargs = 0,
2569: .maxargs = 0,
2570: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2571: .f = window_copy_cmd_halfpage_down
2572: },
2573: { .command = "halfpage-down-and-cancel",
2574: .minargs = 0,
2575: .maxargs = 0,
2576: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2577: .f = window_copy_cmd_halfpage_down_and_cancel
2578: },
2579: { .command = "halfpage-up",
2580: .minargs = 0,
2581: .maxargs = 0,
2582: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2583: .f = window_copy_cmd_halfpage_up
2584: },
2585: { .command = "history-bottom",
2586: .minargs = 0,
2587: .maxargs = 0,
2588: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2589: .f = window_copy_cmd_history_bottom
2590: },
2591: { .command = "history-top",
2592: .minargs = 0,
2593: .maxargs = 0,
2594: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2595: .f = window_copy_cmd_history_top
2596: },
2597: { .command = "jump-again",
2598: .minargs = 0,
2599: .maxargs = 0,
2600: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2601: .f = window_copy_cmd_jump_again
2602: },
2603: { .command = "jump-backward",
2604: .minargs = 1,
2605: .maxargs = 1,
2606: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2607: .f = window_copy_cmd_jump_backward
2608: },
2609: { .command = "jump-forward",
2610: .minargs = 1,
2611: .maxargs = 1,
2612: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2613: .f = window_copy_cmd_jump_forward
2614: },
2615: { .command = "jump-reverse",
2616: .minargs = 0,
2617: .maxargs = 0,
2618: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2619: .f = window_copy_cmd_jump_reverse
2620: },
2621: { .command = "jump-to-backward",
2622: .minargs = 1,
2623: .maxargs = 1,
2624: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2625: .f = window_copy_cmd_jump_to_backward
2626: },
2627: { .command = "jump-to-forward",
2628: .minargs = 1,
2629: .maxargs = 1,
2630: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2631: .f = window_copy_cmd_jump_to_forward
2632: },
2633: { .command = "jump-to-mark",
2634: .minargs = 0,
2635: .maxargs = 0,
2636: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2637: .f = window_copy_cmd_jump_to_mark
2638: },
2639: { .command = "middle-line",
2640: .minargs = 0,
2641: .maxargs = 0,
2642: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2643: .f = window_copy_cmd_middle_line
2644: },
2645: { .command = "next-matching-bracket",
2646: .minargs = 0,
2647: .maxargs = 0,
2648: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2649: .f = window_copy_cmd_next_matching_bracket
2650: },
2651: { .command = "next-paragraph",
2652: .minargs = 0,
2653: .maxargs = 0,
2654: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2655: .f = window_copy_cmd_next_paragraph
2656: },
2657: { .command = "next-space",
2658: .minargs = 0,
2659: .maxargs = 0,
2660: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2661: .f = window_copy_cmd_next_space
2662: },
2663: { .command = "next-space-end",
2664: .minargs = 0,
2665: .maxargs = 0,
2666: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2667: .f = window_copy_cmd_next_space_end
2668: },
2669: { .command = "next-word",
2670: .minargs = 0,
2671: .maxargs = 0,
2672: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2673: .f = window_copy_cmd_next_word
2674: },
2675: { .command = "next-word-end",
2676: .minargs = 0,
2677: .maxargs = 0,
2678: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2679: .f = window_copy_cmd_next_word_end
2680: },
2681: { .command = "other-end",
2682: .minargs = 0,
2683: .maxargs = 0,
2684: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2685: .f = window_copy_cmd_other_end
2686: },
2687: { .command = "page-down",
2688: .minargs = 0,
2689: .maxargs = 0,
2690: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2691: .f = window_copy_cmd_page_down
2692: },
2693: { .command = "page-down-and-cancel",
2694: .minargs = 0,
2695: .maxargs = 0,
2696: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2697: .f = window_copy_cmd_page_down_and_cancel
2698: },
2699: { .command = "page-up",
2700: .minargs = 0,
2701: .maxargs = 0,
2702: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2703: .f = window_copy_cmd_page_up
2704: },
2705: { .command = "pipe-no-clear",
2706: .minargs = 0,
2707: .maxargs = 1,
2708: .clear = WINDOW_COPY_CMD_CLEAR_NEVER,
2709: .f = window_copy_cmd_pipe_no_clear
2710: },
2711: { .command = "pipe",
2712: .minargs = 0,
2713: .maxargs = 1,
2714: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2715: .f = window_copy_cmd_pipe
2716: },
2717: { .command = "pipe-and-cancel",
2718: .minargs = 0,
2719: .maxargs = 1,
2720: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2721: .f = window_copy_cmd_pipe_and_cancel
2722: },
2723: { .command = "previous-matching-bracket",
2724: .minargs = 0,
2725: .maxargs = 0,
2726: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2727: .f = window_copy_cmd_previous_matching_bracket
2728: },
2729: { .command = "previous-paragraph",
2730: .minargs = 0,
2731: .maxargs = 0,
2732: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2733: .f = window_copy_cmd_previous_paragraph
2734: },
2735: { .command = "previous-space",
2736: .minargs = 0,
2737: .maxargs = 0,
2738: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2739: .f = window_copy_cmd_previous_space
2740: },
2741: { .command = "previous-word",
2742: .minargs = 0,
2743: .maxargs = 0,
2744: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2745: .f = window_copy_cmd_previous_word
2746: },
2747: { .command = "rectangle-on",
2748: .minargs = 0,
2749: .maxargs = 0,
2750: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2751: .f = window_copy_cmd_rectangle_on
2752: },
2753: { .command = "rectangle-off",
2754: .minargs = 0,
2755: .maxargs = 0,
2756: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2757: .f = window_copy_cmd_rectangle_off
2758: },
2759: { .command = "rectangle-toggle",
2760: .minargs = 0,
2761: .maxargs = 0,
2762: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2763: .f = window_copy_cmd_rectangle_toggle
2764: },
2765: { .command = "refresh-from-pane",
2766: .minargs = 0,
2767: .maxargs = 0,
2768: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2769: .f = window_copy_cmd_refresh_from_pane
2770: },
2771: { .command = "scroll-down",
2772: .minargs = 0,
2773: .maxargs = 0,
2774: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2775: .f = window_copy_cmd_scroll_down
2776: },
2777: { .command = "scroll-down-and-cancel",
2778: .minargs = 0,
2779: .maxargs = 0,
2780: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2781: .f = window_copy_cmd_scroll_down_and_cancel
2782: },
2783: { .command = "scroll-up",
2784: .minargs = 0,
2785: .maxargs = 0,
2786: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2787: .f = window_copy_cmd_scroll_up
2788: },
2789: { .command = "search-again",
2790: .minargs = 0,
2791: .maxargs = 0,
2792: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2793: .f = window_copy_cmd_search_again
2794: },
2795: { .command = "search-backward",
2796: .minargs = 0,
2797: .maxargs = 1,
2798: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2799: .f = window_copy_cmd_search_backward
2800: },
2801: { .command = "search-backward-text",
2802: .minargs = 0,
2803: .maxargs = 1,
2804: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2805: .f = window_copy_cmd_search_backward_text
2806: },
2807: { .command = "search-backward-incremental",
2808: .minargs = 1,
2809: .maxargs = 1,
2810: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2811: .f = window_copy_cmd_search_backward_incremental
2812: },
2813: { .command = "search-forward",
2814: .minargs = 0,
2815: .maxargs = 1,
2816: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2817: .f = window_copy_cmd_search_forward
2818: },
2819: { .command = "search-forward-text",
2820: .minargs = 0,
2821: .maxargs = 1,
2822: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2823: .f = window_copy_cmd_search_forward_text
2824: },
2825: { .command = "search-forward-incremental",
2826: .minargs = 1,
2827: .maxargs = 1,
2828: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2829: .f = window_copy_cmd_search_forward_incremental
2830: },
2831: { .command = "search-reverse",
2832: .minargs = 0,
2833: .maxargs = 0,
2834: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2835: .f = window_copy_cmd_search_reverse
2836: },
2837: { .command = "select-line",
2838: .minargs = 0,
2839: .maxargs = 0,
2840: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2841: .f = window_copy_cmd_select_line
2842: },
2843: { .command = "select-word",
2844: .minargs = 0,
2845: .maxargs = 0,
2846: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2847: .f = window_copy_cmd_select_word
2848: },
2849: { .command = "set-mark",
2850: .minargs = 0,
2851: .maxargs = 0,
2852: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2853: .f = window_copy_cmd_set_mark
2854: },
2855: { .command = "start-of-line",
2856: .minargs = 0,
2857: .maxargs = 0,
2858: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2859: .f = window_copy_cmd_start_of_line
2860: },
2861: { .command = "stop-selection",
2862: .minargs = 0,
2863: .maxargs = 0,
2864: .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2865: .f = window_copy_cmd_stop_selection
1.333 nicm 2866: },
2867: { .command = "toggle-position",
2868: .minargs = 0,
2869: .maxargs = 0,
2870: .clear = WINDOW_COPY_CMD_CLEAR_NEVER,
2871: .f = window_copy_cmd_toggle_position
1.326 nicm 2872: },
2873: { .command = "top-line",
2874: .minargs = 0,
2875: .maxargs = 0,
2876: .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2877: .f = window_copy_cmd_top_line
2878: }
1.213 nicm 2879: };
2880:
1.157 nicm 2881: static void
1.208 nicm 2882: window_copy_command(struct window_mode_entry *wme, struct client *c,
1.215 nicm 2883: struct session *s, struct winlink *wl, struct args *args,
1.208 nicm 2884: struct mouse_event *m)
1.1 nicm 2885: {
1.208 nicm 2886: struct window_copy_mode_data *data = wme->data;
1.213 nicm 2887: struct window_copy_cmd_state cs;
2888: enum window_copy_cmd_action action;
1.295 nicm 2889: enum window_copy_cmd_clear clear = WINDOW_COPY_CMD_CLEAR_NEVER;
1.213 nicm 2890: const char *command;
1.329 nicm 2891: u_int i, count = args_count(args);
1.295 nicm 2892: int keys;
1.155 nicm 2893:
1.329 nicm 2894: if (count == 0)
1.155 nicm 2895: return;
1.329 nicm 2896: command = args_string(args, 0);
1.330 nicm 2897:
1.202 nicm 2898: if (m != NULL && m->valid && !MOUSE_WHEEL(m->b))
1.156 nicm 2899: window_copy_move_mouse(m);
2900:
1.213 nicm 2901: cs.wme = wme;
2902: cs.args = args;
2903: cs.m = m;
1.215 nicm 2904:
1.213 nicm 2905: cs.c = c;
2906: cs.s = s;
1.215 nicm 2907: cs.wl = wl;
1.213 nicm 2908:
2909: action = WINDOW_COPY_CMD_NOTHING;
2910: for (i = 0; i < nitems(window_copy_cmd_table); i++) {
2911: if (strcmp(window_copy_cmd_table[i].command, command) == 0) {
1.329 nicm 2912: if (count - 1 < window_copy_cmd_table[i].minargs ||
2913: count - 1 > window_copy_cmd_table[i].maxargs)
1.155 nicm 2914: break;
1.295 nicm 2915: clear = window_copy_cmd_table[i].clear;
1.327 nicm 2916: action = window_copy_cmd_table[i].f(&cs);
1.213 nicm 2917: break;
1.163 nicm 2918: }
1.1 nicm 2919: }
1.21 nicm 2920:
1.162 nicm 2921: if (strncmp(command, "search-", 7) != 0 && data->searchmark != NULL) {
1.239 nicm 2922: keys = options_get_number(wme->wp->window->options, "mode-keys");
1.295 nicm 2923: if (clear == WINDOW_COPY_CMD_CLEAR_EMACS_ONLY &&
2924: keys == MODEKEY_VI)
2925: clear = WINDOW_COPY_CMD_CLEAR_NEVER;
2926: if (clear != WINDOW_COPY_CMD_CLEAR_NEVER) {
1.239 nicm 2927: window_copy_clear_marks(wme);
2928: data->searchx = data->searchy = -1;
2929: }
1.213 nicm 2930: if (action == WINDOW_COPY_CMD_NOTHING)
2931: action = WINDOW_COPY_CMD_REDRAW;
1.162 nicm 2932: }
1.209 nicm 2933: wme->prefix = 1;
2934:
1.213 nicm 2935: if (action == WINDOW_COPY_CMD_CANCEL)
2936: window_pane_reset_mode(wme->wp);
2937: else if (action == WINDOW_COPY_CMD_REDRAW)
1.208 nicm 2938: window_copy_redraw_screen(wme);
1.50 nicm 2939: }
2940:
1.157 nicm 2941: static void
1.296 nicm 2942: window_copy_scroll_to(struct window_mode_entry *wme, u_int px, u_int py,
2943: int no_redraw)
1.21 nicm 2944: {
1.208 nicm 2945: struct window_copy_mode_data *data = wme->data;
1.54 nicm 2946: struct grid *gd = data->backing->grid;
1.21 nicm 2947: u_int offset, gap;
2948:
2949: data->cx = px;
2950:
1.185 nicm 2951: if (py >= gd->hsize - data->oy && py < gd->hsize - data->oy + gd->sy)
2952: data->cy = py - (gd->hsize - data->oy);
2953: else {
2954: gap = gd->sy / 4;
2955: if (py < gd->sy) {
2956: offset = 0;
2957: data->cy = py;
2958: } else if (py > gd->hsize + gd->sy - gap) {
2959: offset = gd->hsize;
2960: data->cy = py - gd->hsize;
2961: } else {
2962: offset = py + gap - gd->sy;
2963: data->cy = py - offset;
2964: }
2965: data->oy = gd->hsize - offset;
1.21 nicm 2966: }
2967:
1.296 nicm 2968: if (!no_redraw && data->searchmark != NULL && !data->timeout)
2969: window_copy_search_marks(wme, NULL, data->searchregex, 1);
1.252 nicm 2970: window_copy_update_selection(wme, 1, 0);
1.296 nicm 2971: if (!no_redraw)
2972: window_copy_redraw_screen(wme);
1.21 nicm 2973: }
2974:
1.157 nicm 2975: static int
1.118 nicm 2976: window_copy_search_compare(struct grid *gd, u_int px, u_int py,
2977: struct grid *sgd, u_int spx, int cis)
1.21 nicm 2978: {
1.140 nicm 2979: struct grid_cell gc, sgc;
2980: const struct utf8_data *ud, *sud;
1.21 nicm 2981:
1.140 nicm 2982: grid_get_cell(gd, px, py, &gc);
2983: ud = &gc.data;
2984: grid_get_cell(sgd, spx, 0, &sgc);
2985: sud = &sgc.data;
1.35 nicm 2986:
1.140 nicm 2987: if (ud->size != sud->size || ud->width != sud->width)
1.21 nicm 2988: return (0);
1.97 nicm 2989:
1.140 nicm 2990: if (cis && ud->size == 1)
2991: return (tolower(ud->data[0]) == sud->data[0]);
1.97 nicm 2992:
1.140 nicm 2993: return (memcmp(ud->data, sud->data, ud->size) == 0);
1.21 nicm 2994: }
2995:
1.157 nicm 2996: static int
1.302 nicm 2997: window_copy_search_lr(struct grid *gd, struct grid *sgd, u_int *ppx, u_int py,
2998: u_int first, u_int last, int cis)
1.21 nicm 2999: {
1.243 nicm 3000: u_int ax, bx, px, pywrap, endline;
3001: int matched;
3002: struct grid_line *gl;
1.21 nicm 3003:
1.242 nicm 3004: endline = gd->hsize + gd->sy - 1;
1.21 nicm 3005: for (ax = first; ax < last; ax++) {
3006: for (bx = 0; bx < sgd->sx; bx++) {
3007: px = ax + bx;
1.242 nicm 3008: pywrap = py;
3009: /* Wrap line. */
3010: while (px >= gd->sx && pywrap < endline) {
1.243 nicm 3011: gl = grid_get_line(gd, pywrap);
3012: if (~gl->flags & GRID_LINE_WRAPPED)
3013: break;
1.242 nicm 3014: px -= gd->sx;
3015: pywrap++;
3016: }
3017: /* We have run off the end of the grid. */
3018: if (px >= gd->sx)
3019: break;
3020: matched = window_copy_search_compare(gd, px, pywrap,
3021: sgd, bx, cis);
1.97 nicm 3022: if (!matched)
1.21 nicm 3023: break;
3024: }
3025: if (bx == sgd->sx) {
3026: *ppx = ax;
3027: return (1);
3028: }
3029: }
3030: return (0);
3031: }
3032:
1.157 nicm 3033: static int
1.21 nicm 3034: window_copy_search_rl(struct grid *gd,
1.97 nicm 3035: struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
1.21 nicm 3036: {
1.243 nicm 3037: u_int ax, bx, px, pywrap, endline;
3038: int matched;
3039: struct grid_line *gl;
1.21 nicm 3040:
1.242 nicm 3041: endline = gd->hsize + gd->sy - 1;
3042: for (ax = last; ax > first; ax--) {
1.21 nicm 3043: for (bx = 0; bx < sgd->sx; bx++) {
3044: px = ax - 1 + bx;
1.242 nicm 3045: pywrap = py;
3046: /* Wrap line. */
3047: while (px >= gd->sx && pywrap < endline) {
1.243 nicm 3048: gl = grid_get_line(gd, pywrap);
3049: if (~gl->flags & GRID_LINE_WRAPPED)
3050: break;
1.242 nicm 3051: px -= gd->sx;
3052: pywrap++;
3053: }
3054: /* We have run off the end of the grid. */
3055: if (px >= gd->sx)
3056: break;
3057: matched = window_copy_search_compare(gd, px, pywrap,
3058: sgd, bx, cis);
1.97 nicm 3059: if (!matched)
1.21 nicm 3060: break;
3061: }
3062: if (bx == sgd->sx) {
3063: *ppx = ax - 1;
3064: return (1);
3065: }
3066: }
3067: return (0);
3068: }
3069:
1.244 nicm 3070: static int
1.260 nicm 3071: window_copy_search_lr_regex(struct grid *gd, u_int *ppx, u_int *psx, u_int py,
3072: u_int first, u_int last, regex_t *reg)
1.244 nicm 3073: {
1.260 nicm 3074: int eflags = 0;
1.244 nicm 3075: u_int endline, foundx, foundy, len, pywrap, size = 1;
1.260 nicm 3076: char *buf;
1.244 nicm 3077: regmatch_t regmatch;
3078: struct grid_line *gl;
3079:
3080: /*
3081: * This can happen during search if the last match was the last
3082: * character on a line.
3083: */
3084: if (first >= last)
3085: return (0);
3086:
3087: /* Set flags for regex search. */
3088: if (first != 0)
3089: eflags |= REG_NOTBOL;
3090:
3091: /* Need to look at the entire string. */
3092: buf = xmalloc(size);
3093: buf[0] = '\0';
3094: buf = window_copy_stringify(gd, py, first, gd->sx, buf, &size);
3095: len = gd->sx - first;
3096: endline = gd->hsize + gd->sy - 1;
3097: pywrap = py;
3098: while (buf != NULL && pywrap <= endline) {
3099: gl = grid_get_line(gd, pywrap);
3100: if (~gl->flags & GRID_LINE_WRAPPED)
3101: break;
3102: pywrap++;
3103: buf = window_copy_stringify(gd, pywrap, 0, gd->sx, buf, &size);
3104: len += gd->sx;
3105: }
3106:
1.287 nicm 3107: if (regexec(reg, buf, 1, ®match, eflags) == 0 &&
3108: regmatch.rm_so != regmatch.rm_eo) {
1.244 nicm 3109: foundx = first;
3110: foundy = py;
3111: window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
3112: buf + regmatch.rm_so);
3113: if (foundy == py && foundx < last) {
3114: *ppx = foundx;
3115: len -= foundx - first;
3116: window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
3117: buf + regmatch.rm_eo);
3118: *psx = foundx;
3119: while (foundy > py) {
3120: *psx += gd->sx;
3121: foundy--;
3122: }
3123: *psx -= *ppx;
3124: free(buf);
3125: return (1);
3126: }
3127: }
3128:
3129: free(buf);
3130: *ppx = 0;
3131: *psx = 0;
3132: return (0);
3133: }
3134:
3135: static int
1.260 nicm 3136: window_copy_search_rl_regex(struct grid *gd, u_int *ppx, u_int *psx, u_int py,
3137: u_int first, u_int last, regex_t *reg)
1.244 nicm 3138: {
1.260 nicm 3139: int eflags = 0;
3140: u_int endline, len, pywrap, size = 1;
3141: char *buf;
1.244 nicm 3142: struct grid_line *gl;
3143:
3144: /* Set flags for regex search. */
3145: if (first != 0)
3146: eflags |= REG_NOTBOL;
3147:
3148: /* Need to look at the entire string. */
3149: buf = xmalloc(size);
3150: buf[0] = '\0';
3151: buf = window_copy_stringify(gd, py, first, gd->sx, buf, &size);
3152: len = gd->sx - first;
3153: endline = gd->hsize + gd->sy - 1;
3154: pywrap = py;
3155: while (buf != NULL && (pywrap <= endline)) {
3156: gl = grid_get_line(gd, pywrap);
3157: if (~gl->flags & GRID_LINE_WRAPPED)
3158: break;
3159: pywrap++;
3160: buf = window_copy_stringify(gd, pywrap, 0, gd->sx, buf, &size);
3161: len += gd->sx;
3162: }
3163:
3164: if (window_copy_last_regex(gd, py, first, last, len, ppx, psx, buf,
1.260 nicm 3165: reg, eflags))
1.244 nicm 3166: {
3167: free(buf);
3168: return (1);
3169: }
3170:
3171: free(buf);
3172: *ppx = 0;
3173: *psx = 0;
3174: return (0);
3175: }
3176:
1.260 nicm 3177: static const char *
1.289 nicm 3178: window_copy_cellstring(const struct grid_line *gl, u_int px, size_t *size,
3179: int *allocated)
1.260 nicm 3180: {
1.289 nicm 3181: static struct utf8_data ud;
1.260 nicm 3182: struct grid_cell_entry *gce;
1.289 nicm 3183: char *copy;
1.260 nicm 3184:
3185: if (px >= gl->cellsize) {
3186: *size = 1;
1.289 nicm 3187: *allocated = 0;
1.260 nicm 3188: return (" ");
3189: }
3190:
3191: gce = &gl->celldata[px];
1.301 nicm 3192: if (gce->flags & GRID_FLAG_PADDING) {
3193: *size = 0;
3194: *allocated = 0;
3195: return (NULL);
3196: }
1.260 nicm 3197: if (~gce->flags & GRID_FLAG_EXTENDED) {
3198: *size = 1;
1.289 nicm 3199: *allocated = 0;
1.260 nicm 3200: return (&gce->data.data);
3201: }
3202:
1.291 nicm 3203: utf8_to_data(gl->extddata[gce->offset].data, &ud);
1.332 nicm 3204: if (ud.size == 0) {
3205: *size = 0;
3206: *allocated = 0;
3207: return (NULL);
3208: }
1.289 nicm 3209: *size = ud.size;
3210: *allocated = 1;
3211:
3212: copy = xmalloc(ud.size);
3213: memcpy(copy, ud.data, ud.size);
3214: return (copy);
1.260 nicm 3215: }
3216:
1.244 nicm 3217: /* Find last match in given range. */
3218: static int
3219: window_copy_last_regex(struct grid *gd, u_int py, u_int first, u_int last,
3220: u_int len, u_int *ppx, u_int *psx, const char *buf, const regex_t *preg,
3221: int eflags)
3222: {
3223: u_int foundx, foundy, oldx, px = 0, savepx, savesx = 0;
3224: regmatch_t regmatch;
3225:
3226: foundx = first;
3227: foundy = py;
3228: oldx = first;
3229: while (regexec(preg, buf + px, 1, ®match, eflags) == 0) {
1.287 nicm 3230: if (regmatch.rm_so == regmatch.rm_eo)
3231: break;
1.244 nicm 3232: window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
3233: buf + px + regmatch.rm_so);
3234: if (foundy > py || foundx >= last)
3235: break;
3236: len -= foundx - oldx;
3237: savepx = foundx;
3238: window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
3239: buf + px + regmatch.rm_eo);
3240: if (foundy > py || foundx >= last) {
3241: *ppx = savepx;
3242: *psx = foundx;
3243: while (foundy > py) {
3244: *psx += gd->sx;
3245: foundy--;
3246: }
3247: *psx -= *ppx;
3248: return (1);
3249: } else {
3250: savesx = foundx - savepx;
3251: len -= savesx;
3252: oldx = foundx;
3253: }
3254: px += regmatch.rm_eo;
3255: }
3256:
3257: if (savesx > 0) {
3258: *ppx = savepx;
3259: *psx = savesx;
3260: return (1);
3261: } else {
3262: *ppx = 0;
3263: *psx = 0;
3264: return (0);
3265: }
3266: }
3267:
3268: /* Stringify line and append to input buffer. Caller frees. */
3269: static char *
3270: window_copy_stringify(struct grid *gd, u_int py, u_int first, u_int last,
3271: char *buf, u_int *size)
3272: {
1.260 nicm 3273: u_int ax, bx, newsize = *size;
3274: const struct grid_line *gl;
3275: const char *d;
3276: size_t bufsize = 1024, dlen;
1.289 nicm 3277: int allocated;
1.260 nicm 3278:
3279: while (bufsize < newsize)
3280: bufsize *= 2;
3281: buf = xrealloc(buf, bufsize);
1.244 nicm 3282:
1.260 nicm 3283: gl = grid_peek_line(gd, py);
1.244 nicm 3284: bx = *size - 1;
3285: for (ax = first; ax < last; ax++) {
1.289 nicm 3286: d = window_copy_cellstring(gl, ax, &dlen, &allocated);
1.260 nicm 3287: newsize += dlen;
3288: while (bufsize < newsize) {
3289: bufsize *= 2;
3290: buf = xrealloc(buf, bufsize);
3291: }
3292: if (dlen == 1)
3293: buf[bx++] = *d;
3294: else {
3295: memcpy(buf + bx, d, dlen);
3296: bx += dlen;
3297: }
1.289 nicm 3298: if (allocated)
3299: free((void *)d);
1.244 nicm 3300: }
1.260 nicm 3301: buf[newsize - 1] = '\0';
1.244 nicm 3302:
3303: *size = newsize;
3304: return (buf);
3305: }
3306:
3307: /* Map start of C string containing UTF-8 data to grid cell position. */
3308: static void
3309: window_copy_cstrtocellpos(struct grid *gd, u_int ncells, u_int *ppx, u_int *ppy,
3310: const char *str)
3311: {
1.260 nicm 3312: u_int cell, ccell, px, pywrap, pos, len;
3313: int match;
3314: const struct grid_line *gl;
3315: const char *d;
3316: size_t dlen;
3317: struct {
3318: const char *d;
3319: size_t dlen;
1.289 nicm 3320: int allocated;
1.260 nicm 3321: } *cells;
1.244 nicm 3322:
1.260 nicm 3323: /* Populate the array of cell data. */
1.244 nicm 3324: cells = xreallocarray(NULL, ncells, sizeof cells[0]);
3325: cell = 0;
3326: px = *ppx;
3327: pywrap = *ppy;
1.260 nicm 3328: gl = grid_peek_line(gd, pywrap);
1.244 nicm 3329: while (cell < ncells) {
1.260 nicm 3330: cells[cell].d = window_copy_cellstring(gl, px,
1.289 nicm 3331: &cells[cell].dlen, &cells[cell].allocated);
1.244 nicm 3332: cell++;
1.261 nicm 3333: px++;
3334: if (px == gd->sx) {
3335: px = 0;
1.244 nicm 3336: pywrap++;
1.260 nicm 3337: gl = grid_peek_line(gd, pywrap);
3338: }
1.244 nicm 3339: }
3340:
3341: /* Locate starting cell. */
3342: cell = 0;
1.260 nicm 3343: len = strlen(str);
1.244 nicm 3344: while (cell < ncells) {
3345: ccell = cell;
1.260 nicm 3346: pos = 0;
1.244 nicm 3347: match = 1;
3348: while (ccell < ncells) {
1.260 nicm 3349: if (str[pos] == '\0') {
1.244 nicm 3350: match = 0;
3351: break;
3352: }
1.260 nicm 3353: d = cells[ccell].d;
3354: dlen = cells[ccell].dlen;
3355: if (dlen == 1) {
3356: if (str[pos] != *d) {
3357: match = 0;
3358: break;
3359: }
3360: pos++;
3361: } else {
3362: if (dlen > len - pos)
3363: dlen = len - pos;
3364: if (memcmp(str + pos, d, dlen) != 0) {
1.244 nicm 3365: match = 0;
3366: break;
3367: }
1.260 nicm 3368: pos += dlen;
1.244 nicm 3369: }
3370: ccell++;
3371: }
3372: if (match)
3373: break;
3374: cell++;
3375: }
3376:
3377: /* If not found this will be one past the end. */
3378: px = *ppx + cell;
3379: pywrap = *ppy;
3380: while (px >= gd->sx) {
3381: px -= gd->sx;
3382: pywrap++;
3383: }
3384:
3385: *ppx = px;
3386: *ppy = pywrap;
3387:
3388: /* Free cell data. */
1.289 nicm 3389: for (cell = 0; cell < ncells; cell++) {
3390: if (cells[cell].allocated)
3391: free((void *)cells[cell].d);
3392: }
1.244 nicm 3393: free(cells);
3394: }
3395:
1.157 nicm 3396: static void
1.230 nicm 3397: window_copy_move_left(struct screen *s, u_int *fx, u_int *fy, int wrapflag)
1.21 nicm 3398: {
1.150 nicm 3399: if (*fx == 0) { /* left */
1.230 nicm 3400: if (*fy == 0) { /* top */
3401: if (wrapflag) {
3402: *fx = screen_size_x(s) - 1;
1.242 nicm 3403: *fy = screen_hsize(s) + screen_size_y(s) - 1;
1.230 nicm 3404: }
1.150 nicm 3405: return;
1.230 nicm 3406: }
1.150 nicm 3407: *fx = screen_size_x(s) - 1;
3408: *fy = *fy - 1;
3409: } else
3410: *fx = *fx - 1;
3411: }
1.21 nicm 3412:
1.321 nicm 3413: static void
3414: window_copy_move_right(struct screen *s, u_int *fx, u_int *fy, int wrapflag)
3415: {
3416: if (*fx == screen_size_x(s) - 1) { /* right */
3417: if (*fy == screen_hsize(s) + screen_size_y(s) - 1) { /* bottom */
3418: if (wrapflag) {
3419: *fx = 0;
3420: *fy = 0;
3421: }
3422: return;
3423: }
3424: *fx = 0;
3425: *fy = *fy + 1;
3426: } else
3427: *fx = *fx + 1;
3428: }
3429:
1.157 nicm 3430: static int
1.150 nicm 3431: window_copy_is_lowercase(const char *ptr)
3432: {
3433: while (*ptr != '\0') {
3434: if (*ptr != tolower((u_char)*ptr))
3435: return (0);
3436: ++ptr;
1.97 nicm 3437: }
1.150 nicm 3438: return (1);
3439: }
1.97 nicm 3440:
1.150 nicm 3441: /*
1.317 nicm 3442: * Handle backward wrapped regex searches with overlapping matches. In this case
3443: * find the longest overlapping match from previous wrapped lines.
3444: */
3445: static void
3446: window_copy_search_back_overlap(struct grid *gd, regex_t *preg, u_int *ppx,
3447: u_int *psx, u_int *ppy, u_int endline)
3448: {
3449: u_int endx, endy, oldendx, oldendy, px, py, sx;
3450: int found = 1;
3451:
3452: oldendx = *ppx + *psx;
3453: oldendy = *ppy - 1;
3454: while (oldendx > gd->sx - 1) {
3455: oldendx -= gd->sx;
3456: oldendy++;
3457: }
3458: endx = oldendx;
3459: endy = oldendy;
3460: px = *ppx;
3461: py = *ppy;
3462: while (found && px == 0 && py - 1 > endline &&
3463: grid_get_line(gd, py - 2)->flags & GRID_LINE_WRAPPED &&
3464: endx == oldendx && endy == oldendy) {
3465: py--;
3466: found = window_copy_search_rl_regex(gd, &px, &sx, py - 1, 0,
3467: gd->sx, preg);
3468: if (found) {
3469: endx = px + sx;
3470: endy = py - 1;
3471: while (endx > gd->sx - 1) {
3472: endx -= gd->sx;
3473: endy++;
3474: }
3475: if (endx == oldendx && endy == oldendy) {
3476: *ppx = px;
3477: *ppy = py;
3478: }
3479: }
3480: }
3481: }
3482:
3483: /*
1.150 nicm 3484: * Search for text stored in sgd starting from position fx,fy up to endline. If
3485: * found, jump to it. If cis then ignore case. The direction is 0 for searching
3486: * up, down otherwise. If wrap then go to begin/end of grid and try again if
3487: * not found.
3488: */
1.163 nicm 3489: static int
1.208 nicm 3490: window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
1.150 nicm 3491: struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap,
1.321 nicm 3492: int direction, int regex)
1.150 nicm 3493: {
1.260 nicm 3494: u_int i, px, sx, ssize = 1;
3495: int found = 0, cflags = REG_EXTENDED;
3496: char *sbuf;
3497: regex_t reg;
3498:
3499: if (regex) {
3500: sbuf = xmalloc(ssize);
3501: sbuf[0] = '\0';
3502: sbuf = window_copy_stringify(sgd, 0, 0, sgd->sx, sbuf, &ssize);
3503: if (cis)
3504: cflags |= REG_ICASE;
3505: if (regcomp(®, sbuf, cflags) != 0) {
3506: free(sbuf);
3507: return (0);
3508: }
1.304 nicm 3509: free(sbuf);
1.260 nicm 3510: }
1.150 nicm 3511:
3512: if (direction) {
3513: for (i = fy; i <= endline; i++) {
1.260 nicm 3514: if (regex) {
3515: found = window_copy_search_lr_regex(gd,
3516: &px, &sx, i, fx, gd->sx, ®);
3517: } else {
1.244 nicm 3518: found = window_copy_search_lr(gd, sgd,
3519: &px, i, fx, gd->sx, cis);
1.260 nicm 3520: }
1.150 nicm 3521: if (found)
3522: break;
3523: fx = 0;
3524: }
3525: } else {
3526: for (i = fy + 1; endline < i; i--) {
1.260 nicm 3527: if (regex) {
3528: found = window_copy_search_rl_regex(gd,
3529: &px, &sx, i - 1, 0, fx + 1, ®);
1.317 nicm 3530: if (found) {
3531: window_copy_search_back_overlap(gd,
3532: ®, &px, &sx, &i, endline);
3533: }
1.260 nicm 3534: } else {
1.244 nicm 3535: found = window_copy_search_rl(gd, sgd,
3536: &px, i - 1, 0, fx + 1, cis);
1.260 nicm 3537: }
1.150 nicm 3538: if (found) {
3539: i--;
3540: break;
3541: }
1.242 nicm 3542: fx = gd->sx - 1;
1.21 nicm 3543: }
3544: }
1.304 nicm 3545: if (regex)
1.260 nicm 3546: regfree(®);
1.150 nicm 3547:
1.163 nicm 3548: if (found) {
1.296 nicm 3549: window_copy_scroll_to(wme, px, i, 1);
1.163 nicm 3550: return (1);
3551: }
3552: if (wrap) {
1.208 nicm 3553: return (window_copy_search_jump(wme, gd, sgd,
1.163 nicm 3554: direction ? 0 : gd->sx - 1,
1.150 nicm 3555: direction ? 0 : gd->hsize + gd->sy - 1, fy, cis, 0,
1.321 nicm 3556: direction, regex));
1.21 nicm 3557: }
1.163 nicm 3558: return (0);
1.21 nicm 3559: }
3560:
1.321 nicm 3561: static void
3562: window_copy_move_after_search_mark(struct window_copy_mode_data *data,
3563: u_int *fx, u_int *fy, int wrapflag)
3564: {
3565: struct screen *s = data->backing;
3566: u_int at, start;
3567:
3568: if (window_copy_search_mark_at(data, *fx, *fy, &start) == 0 &&
3569: data->searchmark[start] != 0) {
3570: while (window_copy_search_mark_at(data, *fx, *fy, &at) == 0) {
3571: if (data->searchmark[at] != data->searchmark[start])
3572: break;
3573: /* Stop if not wrapping and at the end of the grid. */
3574: if (!wrapflag &&
3575: *fx == screen_size_x(s) - 1 &&
3576: *fy == screen_hsize(s) + screen_size_y(s) - 1)
3577: break;
3578:
3579: window_copy_move_right(s, fx, fy, wrapflag);
3580: }
3581: }
3582: }
3583:
1.232 nicm 3584: /*
3585: * Search in for text searchstr. If direction is 0 then search up, otherwise
3586: * down.
3587: */
1.163 nicm 3588: static int
1.321 nicm 3589: window_copy_search(struct window_mode_entry *wme, int direction, int regex)
1.21 nicm 3590: {
1.208 nicm 3591: struct window_pane *wp = wme->wp;
3592: struct window_copy_mode_data *data = wme->data;
1.54 nicm 3593: struct screen *s = data->backing, ss;
1.21 nicm 3594: struct screen_write_ctx ctx;
1.150 nicm 3595: struct grid *gd = s->grid;
1.262 nicm 3596: const char *str = data->searchstr;
1.321 nicm 3597: u_int at, endline, fx, fy, start;
3598: int cis, found, keys, visible_only;
3599: int wrapflag;
1.21 nicm 3600:
1.262 nicm 3601: if (regex && str[strcspn(str, "^$*+()?[].\\")] == '\0')
3602: regex = 0;
3603:
1.321 nicm 3604: data->searchdirection = direction;
3605:
1.263 nicm 3606: if (data->timeout)
3607: return (0);
3608:
1.308 nicm 3609: if (data->searchall || wp->searchstr == NULL ||
3610: wp->searchregex != regex) {
1.296 nicm 3611: visible_only = 0;
1.308 nicm 3612: data->searchall = 0;
3613: } else
1.296 nicm 3614: visible_only = (strcmp(wp->searchstr, str) == 0);
1.337 nicm 3615: if (visible_only == 0 && data->searchmark != NULL)
3616: window_copy_clear_marks(wme);
1.174 nicm 3617: free(wp->searchstr);
1.262 nicm 3618: wp->searchstr = xstrdup(str);
1.259 nicm 3619: wp->searchregex = regex;
1.174 nicm 3620:
1.150 nicm 3621: fx = data->cx;
3622: fy = screen_hsize(data->backing) - data->oy + data->cy;
1.21 nicm 3623:
1.262 nicm 3624: screen_init(&ss, screen_write_strlen("%s", str), 1, 0);
1.283 nicm 3625: screen_write_start(&ctx, &ss);
1.262 nicm 3626: screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", str);
1.21 nicm 3627: screen_write_stop(&ctx);
3628:
1.150 nicm 3629: wrapflag = options_get_number(wp->window->options, "wrap-search");
1.262 nicm 3630: cis = window_copy_is_lowercase(str);
1.21 nicm 3631:
1.321 nicm 3632: keys = options_get_number(wp->window->options, "mode-keys");
3633:
3634: if (direction) {
3635: /*
3636: * Behave according to mode-keys. If it is emacs, search forward
3637: * leaves the cursor after the match. If it is vi, the cursor
3638: * remains at the beginning of the match, regardless of
3639: * direction, which means that we need to start the next search
3640: * after the term the cursor is currently on when searching
3641: * forward.
3642: */
3643: if (keys == MODEKEY_VI) {
3644: if (data->searchmark != NULL)
3645: window_copy_move_after_search_mark(data, &fx,
3646: &fy, wrapflag);
3647: else {
3648: /*
3649: * When there are no search marks, start the
3650: * search after the current cursor position.
3651: */
3652: window_copy_move_right(s, &fx, &fy, wrapflag);
3653: }
3654: }
1.150 nicm 3655: endline = gd->hsize + gd->sy - 1;
1.321 nicm 3656: }
1.302 nicm 3657: else {
1.321 nicm 3658: window_copy_move_left(s, &fx, &fy, wrapflag);
1.150 nicm 3659: endline = 0;
1.230 nicm 3660: }
1.244 nicm 3661:
1.208 nicm 3662: found = window_copy_search_jump(wme, gd, ss.grid, fx, fy, endline, cis,
1.321 nicm 3663: wrapflag, direction, regex);
1.302 nicm 3664: if (found) {
1.296 nicm 3665: window_copy_search_marks(wme, &ss, regex, visible_only);
1.321 nicm 3666: fx = data->cx;
3667: fy = screen_hsize(data->backing) - data->oy + data->cy;
3668:
3669: /*
3670: * When searching forward, if the cursor is not at the beginning
3671: * of the mark, search again.
3672: */
3673: if (direction &&
3674: window_copy_search_mark_at(data, fx, fy, &at) == 0 &&
3675: at > 0 &&
1.338 ! nicm 3676: data->searchmark != NULL &&
1.321 nicm 3677: data->searchmark[at] == data->searchmark[at - 1]) {
3678: window_copy_move_after_search_mark(data, &fx, &fy,
3679: wrapflag);
3680: window_copy_search_jump(wme, gd, ss.grid, fx,
3681: fy, endline, cis, wrapflag, direction,
3682: regex);
3683: fx = data->cx;
3684: fy = screen_hsize(data->backing) - data->oy + data->cy;
3685: }
3686:
3687: if (direction) {
3688: /*
3689: * When in Emacs mode, position the cursor just after
3690: * the mark.
3691: */
3692: if (keys == MODEKEY_EMACS) {
3693: window_copy_move_after_search_mark(data, &fx,
3694: &fy, wrapflag);
3695: data->cx = fx;
3696: data->cy = fy - screen_hsize(data->backing) +
3697: data-> oy;
3698: }
3699: }
3700: else {
3701: /*
3702: * When searching backward, position the cursor at the
3703: * beginning of the mark.
3704: */
3705: if (window_copy_search_mark_at(data, fx, fy,
3706: &start) == 0) {
3707: while (window_copy_search_mark_at(data, fx, fy,
3708: &at) == 0 &&
1.338 ! nicm 3709: data->searchmark != NULL &&
1.321 nicm 3710: data->searchmark[at] ==
3711: data->searchmark[start]) {
3712: data->cx = fx;
3713: data->cy = fy -
3714: screen_hsize(data->backing) +
3715: data-> oy;
3716: if (at == 0)
3717: break;
3718:
3719: window_copy_move_left(s, &fx, &fy, 0);
3720: }
1.317 nicm 3721: }
1.302 nicm 3722: }
3723: }
1.296 nicm 3724: window_copy_redraw_screen(wme);
1.21 nicm 3725:
1.150 nicm 3726: screen_free(&ss);
1.163 nicm 3727: return (found);
1.150 nicm 3728: }
1.97 nicm 3729:
1.296 nicm 3730: static void
3731: window_copy_visible_lines(struct window_copy_mode_data *data, u_int *start,
3732: u_int *end)
3733: {
3734: struct grid *gd = data->backing->grid;
3735: const struct grid_line *gl;
3736:
3737: for (*start = gd->hsize - data->oy; *start > 0; (*start)--) {
3738: gl = grid_peek_line(gd, (*start) - 1);
3739: if (~gl->flags & GRID_LINE_WRAPPED)
3740: break;
3741: }
3742: *end = gd->hsize - data->oy + gd->sy;
3743: }
3744:
1.162 nicm 3745: static int
1.302 nicm 3746: window_copy_search_mark_at(struct window_copy_mode_data *data, u_int px,
3747: u_int py, u_int *at)
1.297 nicm 3748: {
3749: struct screen *s = data->backing;
3750: struct grid *gd = s->grid;
3751:
3752: if (py < gd->hsize - data->oy)
3753: return (-1);
3754: if (py > gd->hsize - data->oy + gd->sy - 1)
3755: return (-1);
3756: *at = ((py - (gd->hsize - data->oy)) * gd->sx) + px;
3757: return (0);
3758: }
3759:
3760: static int
1.244 nicm 3761: window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp,
1.296 nicm 3762: int regex, int visible_only)
1.162 nicm 3763: {
1.208 nicm 3764: struct window_copy_mode_data *data = wme->data;
1.162 nicm 3765: struct screen *s = data->backing, ss;
3766: struct screen_write_ctx ctx;
3767: struct grid *gd = s->grid;
1.309 nicm 3768: int found, cis, stopped = 0;
1.260 nicm 3769: int cflags = REG_EXTENDED;
1.282 nicm 3770: u_int px, py, i, b, nfound = 0, width;
1.284 nicm 3771: u_int ssize = 1, start, end;
1.260 nicm 3772: char *sbuf;
3773: regex_t reg;
1.284 nicm 3774: uint64_t stop = 0, tstart, t;
1.162 nicm 3775:
3776: if (ssp == NULL) {
3777: width = screen_write_strlen("%s", data->searchstr);
3778: screen_init(&ss, width, 1, 0);
1.283 nicm 3779: screen_write_start(&ctx, &ss);
1.162 nicm 3780: screen_write_nputs(&ctx, -1, &grid_default_cell, "%s",
3781: data->searchstr);
3782: screen_write_stop(&ctx);
3783: ssp = &ss;
3784: } else
3785: width = screen_size_x(ssp);
3786:
3787: cis = window_copy_is_lowercase(data->searchstr);
3788:
1.260 nicm 3789: if (regex) {
3790: sbuf = xmalloc(ssize);
3791: sbuf[0] = '\0';
3792: sbuf = window_copy_stringify(ssp->grid, 0, 0, ssp->grid->sx,
3793: sbuf, &ssize);
3794: if (cis)
3795: cflags |= REG_ICASE;
3796: if (regcomp(®, sbuf, cflags) != 0) {
3797: free(sbuf);
3798: return (0);
3799: }
1.304 nicm 3800: free(sbuf);
1.260 nicm 3801: }
1.292 nicm 3802: tstart = get_timer();
1.284 nicm 3803:
1.296 nicm 3804: if (visible_only)
3805: window_copy_visible_lines(data, &start, &end);
3806: else {
3807: start = 0;
3808: end = gd->hsize + gd->sy;
3809: stop = get_timer() + WINDOW_COPY_SEARCH_ALL_TIMEOUT;
3810: }
1.284 nicm 3811:
3812: again:
3813: free(data->searchmark);
1.297 nicm 3814: data->searchmark = xcalloc(gd->sx, gd->sy);
1.284 nicm 3815: data->searchgen = 1;
3816:
3817: for (py = start; py < end; py++) {
1.162 nicm 3818: px = 0;
3819: for (;;) {
1.244 nicm 3820: if (regex) {
3821: found = window_copy_search_lr_regex(gd,
1.260 nicm 3822: &px, &width, py, px, gd->sx, ®);
1.244 nicm 3823: if (!found)
3824: break;
1.260 nicm 3825: } else {
1.244 nicm 3826: found = window_copy_search_lr(gd, ssp->grid,
1.260 nicm 3827: &px, py, px, gd->sx, cis);
1.244 nicm 3828: if (!found)
3829: break;
3830: }
1.162 nicm 3831: nfound++;
3832:
1.297 nicm 3833: if (window_copy_search_mark_at(data, px, py, &b) == 0) {
3834: if (b + width > gd->sx * gd->sy)
3835: width = (gd->sx * gd->sy) - b;
1.317 nicm 3836: for (i = b; i < b + width; i++) {
3837: if (data->searchmark[i] != 0)
3838: continue;
1.297 nicm 3839: data->searchmark[i] = data->searchgen;
1.317 nicm 3840: }
1.297 nicm 3841: if (data->searchgen == UCHAR_MAX)
3842: data->searchgen = 1;
3843: else
3844: data->searchgen++;
3845: }
1.302 nicm 3846: px += width;
1.162 nicm 3847: }
1.263 nicm 3848:
1.292 nicm 3849: t = get_timer();
1.263 nicm 3850: if (t - tstart > WINDOW_COPY_SEARCH_TIMEOUT) {
3851: data->timeout = 1;
3852: break;
3853: }
1.284 nicm 3854: if (stop != 0 && t > stop) {
3855: stopped = 1;
3856: break;
3857: }
1.162 nicm 3858: }
1.263 nicm 3859: if (data->timeout) {
3860: window_copy_clear_marks(wme);
1.284 nicm 3861: goto out;
3862: }
3863:
3864: if (stopped && stop != 0) {
3865: /* Try again but just the visible context. */
1.296 nicm 3866: window_copy_visible_lines(data, &start, &end);
1.284 nicm 3867: stop = 0;
3868: goto again;
1.263 nicm 3869: }
1.162 nicm 3870:
1.296 nicm 3871: if (!visible_only) {
3872: if (stopped) {
3873: if (nfound > 1000)
3874: data->searchcount = 1000;
3875: else if (nfound > 100)
3876: data->searchcount = 100;
3877: else if (nfound > 10)
3878: data->searchcount = 10;
3879: else
3880: data->searchcount = -1;
3881: data->searchmore = 1;
3882: } else {
3883: data->searchcount = nfound;
3884: data->searchmore = 0;
3885: }
1.284 nicm 3886: }
1.170 nicm 3887:
1.284 nicm 3888: out:
1.162 nicm 3889: if (ssp == &ss)
3890: screen_free(&ss);
1.304 nicm 3891: if (regex)
1.284 nicm 3892: regfree(®);
1.263 nicm 3893: return (1);
1.162 nicm 3894: }
3895:
1.157 nicm 3896: static void
1.208 nicm 3897: window_copy_clear_marks(struct window_mode_entry *wme)
1.163 nicm 3898: {
1.208 nicm 3899: struct window_copy_mode_data *data = wme->data;
1.163 nicm 3900:
3901: free(data->searchmark);
3902: data->searchmark = NULL;
3903: }
3904:
3905: static int
1.321 nicm 3906: window_copy_search_up(struct window_mode_entry *wme, int regex)
1.150 nicm 3907: {
1.321 nicm 3908: return (window_copy_search(wme, 0, regex));
1.150 nicm 3909: }
1.21 nicm 3910:
1.163 nicm 3911: static int
1.321 nicm 3912: window_copy_search_down(struct window_mode_entry *wme, int regex)
1.150 nicm 3913: {
1.321 nicm 3914: return (window_copy_search(wme, 1, regex));
1.21 nicm 3915: }
3916:
1.157 nicm 3917: static void
1.208 nicm 3918: window_copy_goto_line(struct window_mode_entry *wme, const char *linestr)
1.21 nicm 3919: {
1.208 nicm 3920: struct window_copy_mode_data *data = wme->data;
1.21 nicm 3921: const char *errstr;
1.199 nicm 3922: int lineno;
1.21 nicm 3923:
1.199 nicm 3924: lineno = strtonum(linestr, -1, INT_MAX, &errstr);
1.21 nicm 3925: if (errstr != NULL)
3926: return;
1.199 nicm 3927: if (lineno < 0 || (u_int)lineno > screen_hsize(data->backing))
3928: lineno = screen_hsize(data->backing);
1.35 nicm 3929:
1.21 nicm 3930: data->oy = lineno;
1.252 nicm 3931: window_copy_update_selection(wme, 1, 0);
1.208 nicm 3932: window_copy_redraw_screen(wme);
1.21 nicm 3933: }
3934:
1.157 nicm 3935: static void
1.282 nicm 3936: window_copy_match_start_end(struct window_copy_mode_data *data, u_int at,
3937: u_int *start, u_int *end)
3938: {
3939: struct grid *gd = data->backing->grid;
1.297 nicm 3940: u_int last = (gd->sy * gd->sx) - 1;
1.282 nicm 3941: u_char mark = data->searchmark[at];
3942:
3943: *start = *end = at;
3944: while (*start != 0 && data->searchmark[*start] == mark)
3945: (*start)--;
3946: if (data->searchmark[*start] != mark)
3947: (*start)++;
3948: while (*end != last && data->searchmark[*end] == mark)
3949: (*end)++;
3950: if (data->searchmark[*end] != mark)
3951: (*end)--;
3952: }
3953:
3954: static char *
3955: window_copy_match_at_cursor(struct window_copy_mode_data *data)
3956: {
3957: struct grid *gd = data->backing->grid;
3958: struct grid_cell gc;
3959: u_int at, start, end, cy, px, py;
3960: u_int sx = screen_size_x(data->backing);
3961: char *buf = NULL;
3962: size_t len = 0;
3963:
3964: if (data->searchmark == NULL)
3965: return (NULL);
3966:
3967: cy = screen_hsize(data->backing) - data->oy + data->cy;
1.297 nicm 3968: if (window_copy_search_mark_at(data, data->cx, cy, &at) != 0)
3969: return (NULL);
1.320 nicm 3970: if (data->searchmark[at] == 0) {
3971: /* Allow one position after the match. */
3972: if (at == 0 || data->searchmark[--at] == 0)
3973: return (NULL);
3974: }
1.282 nicm 3975: window_copy_match_start_end(data, at, &start, &end);
3976:
3977: /*
3978: * Cells will not be set in the marked array unless they are valid text
3979: * and wrapping will be taken care of, so we can just copy.
3980: */
3981: for (at = start; at <= end; at++) {
3982: py = at / sx;
1.290 nicm 3983: px = at - (py * sx);
1.282 nicm 3984:
1.297 nicm 3985: grid_get_cell(gd, px, gd->hsize + py - data->oy, &gc);
1.282 nicm 3986: buf = xrealloc(buf, len + gc.data.size + 1);
3987: memcpy(buf + len, gc.data.data, gc.data.size);
3988: len += gc.data.size;
3989: }
3990: if (len != 0)
3991: buf[len] = '\0';
3992: return (buf);
3993: }
3994:
3995: static void
3996: window_copy_update_style(struct window_mode_entry *wme, u_int fx, u_int fy,
3997: struct grid_cell *gc, const struct grid_cell *mgc,
1.288 nicm 3998: const struct grid_cell *cgc, const struct grid_cell *mkgc)
1.282 nicm 3999: {
1.321 nicm 4000: struct window_pane *wp = wme->wp;
1.282 nicm 4001: struct window_copy_mode_data *data = wme->data;
1.284 nicm 4002: u_int mark, start, end, cy, cursor, current;
1.302 nicm 4003: int inv = 0, found = 0;
1.321 nicm 4004: int keys;
1.288 nicm 4005:
4006: if (data->showmark && fy == data->my) {
4007: gc->attr = mkgc->attr;
4008: if (fx == data->mx)
4009: inv = 1;
4010: if (inv) {
4011: gc->fg = mkgc->bg;
4012: gc->bg = mkgc->fg;
4013: }
4014: else {
4015: gc->fg = mkgc->fg;
4016: gc->bg = mkgc->bg;
4017: }
4018: }
1.282 nicm 4019:
4020: if (data->searchmark == NULL)
4021: return;
1.284 nicm 4022:
1.297 nicm 4023: if (window_copy_search_mark_at(data, fx, fy, ¤t) != 0)
4024: return;
1.284 nicm 4025: mark = data->searchmark[current];
1.282 nicm 4026: if (mark == 0)
4027: return;
4028:
4029: cy = screen_hsize(data->backing) - data->oy + data->cy;
1.302 nicm 4030: if (window_copy_search_mark_at(data, data->cx, cy, &cursor) == 0) {
1.321 nicm 4031: keys = options_get_number(wp->window->options, "mode-keys");
4032: if (cursor != 0 &&
4033: keys == MODEKEY_EMACS &&
4034: data->searchdirection) {
4035: if (data->searchmark[cursor - 1] == mark) {
4036: cursor--;
4037: found = 1;
4038: }
4039: } else if (data->searchmark[cursor] == mark)
1.302 nicm 4040: found = 1;
4041: if (found) {
4042: window_copy_match_start_end(data, cursor, &start, &end);
4043: if (current >= start && current <= end) {
4044: gc->attr = cgc->attr;
4045: if (inv) {
4046: gc->fg = cgc->bg;
4047: gc->bg = cgc->fg;
4048: }
4049: else {
4050: gc->fg = cgc->fg;
4051: gc->bg = cgc->bg;
4052: }
4053: return;
1.288 nicm 4054: }
1.282 nicm 4055: }
4056: }
4057:
4058: gc->attr = mgc->attr;
1.288 nicm 4059: if (inv) {
4060: gc->fg = mgc->bg;
4061: gc->bg = mgc->fg;
4062: }
4063: else {
4064: gc->fg = mgc->fg;
4065: gc->bg = mgc->bg;
4066: }
1.282 nicm 4067: }
4068:
4069: static void
4070: window_copy_write_one(struct window_mode_entry *wme,
4071: struct screen_write_ctx *ctx, u_int py, u_int fy, u_int nx,
1.288 nicm 4072: const struct grid_cell *mgc, const struct grid_cell *cgc,
4073: const struct grid_cell *mkgc)
1.282 nicm 4074: {
4075: struct window_copy_mode_data *data = wme->data;
4076: struct grid *gd = data->backing->grid;
4077: struct grid_cell gc;
4078: u_int fx;
4079:
4080: screen_write_cursormove(ctx, 0, py, 0);
4081: for (fx = 0; fx < nx; fx++) {
4082: grid_get_cell(gd, fx, fy, &gc);
4083: if (fx + gc.data.width <= nx) {
1.288 nicm 4084: window_copy_update_style(wme, fx, fy, &gc, mgc, cgc,
4085: mkgc);
1.282 nicm 4086: screen_write_cell(ctx, &gc);
4087: }
4088: }
4089: }
4090:
4091: static void
1.208 nicm 4092: window_copy_write_line(struct window_mode_entry *wme,
4093: struct screen_write_ctx *ctx, u_int py)
1.1 nicm 4094: {
1.208 nicm 4095: struct window_pane *wp = wme->wp;
4096: struct window_copy_mode_data *data = wme->data;
1.1 nicm 4097: struct screen *s = &data->screen;
1.136 nicm 4098: struct options *oo = wp->window->options;
1.336 nicm 4099: struct grid_line *gl;
1.288 nicm 4100: struct grid_cell gc, mgc, cgc, mkgc;
1.336 nicm 4101: char hdr[512], tmp[256], *t;
1.162 nicm 4102: size_t size = 0;
1.270 nicm 4103: u_int hsize = screen_hsize(data->backing);
1.21 nicm 4104:
1.281 nicm 4105: style_apply(&gc, oo, "mode-style", NULL);
1.164 nicm 4106: gc.flags |= GRID_FLAG_NOPALETTE;
1.282 nicm 4107: style_apply(&mgc, oo, "copy-mode-match-style", NULL);
4108: mgc.flags |= GRID_FLAG_NOPALETTE;
4109: style_apply(&cgc, oo, "copy-mode-current-match-style", NULL);
4110: cgc.flags |= GRID_FLAG_NOPALETTE;
1.288 nicm 4111: style_apply(&mkgc, oo, "copy-mode-mark-style", NULL);
4112: mkgc.flags |= GRID_FLAG_NOPALETTE;
1.1 nicm 4113:
1.249 nicm 4114: if (py == 0 && s->rupper < s->rlower && !data->hide_position) {
1.336 nicm 4115: gl = grid_get_line(data->backing->grid, hsize - data->oy);
4116: if (gl->time == 0)
4117: xsnprintf(tmp, sizeof tmp, "[%u/%u]", data->oy, hsize);
4118: else {
4119: t = format_pretty_time(gl->time, 1);
4120: xsnprintf(tmp, sizeof tmp, "%s [%u/%u]", t, data->oy,
4121: hsize);
4122: free(t);
4123: }
4124:
1.170 nicm 4125: if (data->searchmark == NULL) {
1.263 nicm 4126: if (data->timeout) {
4127: size = xsnprintf(hdr, sizeof hdr,
1.336 nicm 4128: "(timed out) %s", tmp);
4129: } else
4130: size = xsnprintf(hdr, sizeof hdr, "%s", tmp);
1.170 nicm 4131: } else {
1.336 nicm 4132: if (data->searchcount == -1)
4133: size = xsnprintf(hdr, sizeof hdr, "%s", tmp);
4134: else {
1.170 nicm 4135: size = xsnprintf(hdr, sizeof hdr,
1.336 nicm 4136: "(%d%s results) %s", data->searchcount,
4137: data->searchmore ? "+" : "", tmp);
1.170 nicm 4138: }
4139: }
1.62 nicm 4140: if (size > screen_size_x(s))
4141: size = screen_size_x(s);
1.212 nicm 4142: screen_write_cursormove(ctx, screen_size_x(s) - size, 0, 0);
1.1 nicm 4143: screen_write_puts(ctx, &gc, "%s", hdr);
4144: } else
4145: size = 0;
4146:
1.105 nicm 4147: if (size < screen_size_x(s)) {
1.282 nicm 4148: window_copy_write_one(wme, ctx, py, hsize - data->oy + py,
1.288 nicm 4149: screen_size_x(s) - size, &mgc, &cgc, &mkgc);
1.105 nicm 4150: }
1.18 nicm 4151:
4152: if (py == data->cy && data->cx == screen_size_x(s)) {
1.212 nicm 4153: screen_write_cursormove(ctx, screen_size_x(s) - 1, py, 0);
1.282 nicm 4154: screen_write_putc(ctx, &grid_default_cell, '$');
1.18 nicm 4155: }
1.1 nicm 4156: }
4157:
1.157 nicm 4158: static void
1.208 nicm 4159: window_copy_write_lines(struct window_mode_entry *wme,
4160: struct screen_write_ctx *ctx, u_int py, u_int ny)
1.1 nicm 4161: {
4162: u_int yy;
4163:
4164: for (yy = py; yy < py + ny; yy++)
1.208 nicm 4165: window_copy_write_line(wme, ctx, py);
1.121 nicm 4166: }
4167:
1.157 nicm 4168: static void
1.208 nicm 4169: window_copy_redraw_selection(struct window_mode_entry *wme, u_int old_y)
1.121 nicm 4170: {
1.208 nicm 4171: struct window_copy_mode_data *data = wme->data;
1.247 nicm 4172: struct grid *gd = data->backing->grid;
1.121 nicm 4173: u_int new_y, start, end;
4174:
4175: new_y = data->cy;
4176: if (old_y <= new_y) {
4177: start = old_y;
4178: end = new_y;
4179: } else {
4180: start = new_y;
4181: end = old_y;
4182: }
1.247 nicm 4183:
4184: /*
4185: * In word selection mode the first word on the line below the cursor
4186: * might be selected, so add this line to the redraw area.
4187: */
4188: if (data->selflag == SEL_WORD) {
4189: /* Last grid line in data coordinates. */
4190: if (end < gd->sy + data->oy - 1)
4191: end++;
4192: }
1.208 nicm 4193: window_copy_redraw_lines(wme, start, end - start + 1);
1.1 nicm 4194: }
4195:
1.157 nicm 4196: static void
1.208 nicm 4197: window_copy_redraw_lines(struct window_mode_entry *wme, u_int py, u_int ny)
1.1 nicm 4198: {
1.208 nicm 4199: struct window_pane *wp = wme->wp;
4200: struct window_copy_mode_data *data = wme->data;
1.1 nicm 4201: struct screen_write_ctx ctx;
4202: u_int i;
4203:
1.283 nicm 4204: screen_write_start_pane(&ctx, wp, NULL);
1.1 nicm 4205: for (i = py; i < py + ny; i++)
1.208 nicm 4206: window_copy_write_line(wme, &ctx, i);
1.212 nicm 4207: screen_write_cursormove(&ctx, data->cx, data->cy, 0);
1.1 nicm 4208: screen_write_stop(&ctx);
4209: }
4210:
1.157 nicm 4211: static void
1.208 nicm 4212: window_copy_redraw_screen(struct window_mode_entry *wme)
1.1 nicm 4213: {
1.208 nicm 4214: struct window_copy_mode_data *data = wme->data;
1.1 nicm 4215:
1.208 nicm 4216: window_copy_redraw_lines(wme, 0, screen_size_y(&data->screen));
1.1 nicm 4217: }
4218:
1.157 nicm 4219: static void
1.252 nicm 4220: window_copy_synchronize_cursor_end(struct window_mode_entry *wme, int begin,
4221: int no_reset)
1.161 nicm 4222: {
1.208 nicm 4223: struct window_copy_mode_data *data = wme->data;
1.161 nicm 4224: u_int xx, yy;
4225:
1.311 nicm 4226: xx = data->cx;
1.161 nicm 4227: yy = screen_hsize(data->backing) + data->cy - data->oy;
1.247 nicm 4228: switch (data->selflag) {
4229: case SEL_WORD:
1.252 nicm 4230: if (no_reset)
1.247 nicm 4231: break;
1.252 nicm 4232: begin = 0;
1.247 nicm 4233: if (data->dy > yy || (data->dy == yy && data->dx > xx)) {
4234: /* Right to left selection. */
1.323 nicm 4235: window_copy_cursor_previous_word_pos(wme,
4236: data->separators, &xx, &yy);
1.247 nicm 4237: begin = 1;
4238:
4239: /* Reset the end. */
4240: data->endselx = data->endselrx;
4241: data->endsely = data->endselry;
4242: } else {
4243: /* Left to right selection. */
4244: if (xx >= window_copy_find_length(wme, yy) ||
1.323 nicm 4245: !window_copy_in_set(wme, xx + 1, yy, WHITESPACE)) {
1.247 nicm 4246: window_copy_cursor_next_word_end_pos(wme,
1.323 nicm 4247: data->separators, &xx, &yy);
4248: }
1.247 nicm 4249:
4250: /* Reset the start. */
4251: data->selx = data->selrx;
4252: data->sely = data->selry;
4253: }
4254: break;
4255: case SEL_LINE:
1.311 nicm 4256: if (no_reset)
1.252 nicm 4257: break;
1.251 nicm 4258: begin = 0;
1.247 nicm 4259: if (data->dy > yy) {
4260: /* Right to left selection. */
4261: xx = 0;
4262: begin = 1;
4263:
4264: /* Reset the end. */
4265: data->endselx = data->endselrx;
4266: data->endsely = data->endselry;
4267: } else {
4268: /* Left to right selection. */
1.319 nicm 4269: if (yy < data->endselry)
4270: yy = data->endselry;
1.247 nicm 4271: xx = window_copy_find_length(wme, yy);
4272:
4273: /* Reset the start. */
4274: data->selx = data->selrx;
4275: data->sely = data->selry;
4276: }
4277: break;
4278: case SEL_CHAR:
4279: break;
4280: }
4281: if (begin) {
4282: data->selx = xx;
4283: data->sely = yy;
4284: } else {
4285: data->endselx = xx;
4286: data->endsely = yy;
4287: }
4288: }
4289:
4290: static void
1.252 nicm 4291: window_copy_synchronize_cursor(struct window_mode_entry *wme, int no_reset)
1.247 nicm 4292: {
4293: struct window_copy_mode_data *data = wme->data;
1.161 nicm 4294:
4295: switch (data->cursordrag) {
4296: case CURSORDRAG_ENDSEL:
1.252 nicm 4297: window_copy_synchronize_cursor_end(wme, 0, no_reset);
1.161 nicm 4298: break;
4299: case CURSORDRAG_SEL:
1.252 nicm 4300: window_copy_synchronize_cursor_end(wme, 1, no_reset);
1.161 nicm 4301: break;
4302: case CURSORDRAG_NONE:
4303: break;
4304: }
4305: }
4306:
4307: static void
1.208 nicm 4308: window_copy_update_cursor(struct window_mode_entry *wme, u_int cx, u_int cy)
1.1 nicm 4309: {
1.208 nicm 4310: struct window_pane *wp = wme->wp;
4311: struct window_copy_mode_data *data = wme->data;
1.18 nicm 4312: struct screen *s = &data->screen;
1.1 nicm 4313: struct screen_write_ctx ctx;
1.18 nicm 4314: u_int old_cx, old_cy;
1.1 nicm 4315:
1.18 nicm 4316: old_cx = data->cx; old_cy = data->cy;
4317: data->cx = cx; data->cy = cy;
4318: if (old_cx == screen_size_x(s))
1.208 nicm 4319: window_copy_redraw_lines(wme, old_cy, 1);
1.18 nicm 4320: if (data->cx == screen_size_x(s))
1.208 nicm 4321: window_copy_redraw_lines(wme, data->cy, 1);
1.18 nicm 4322: else {
1.283 nicm 4323: screen_write_start_pane(&ctx, wp, NULL);
1.212 nicm 4324: screen_write_cursormove(&ctx, data->cx, data->cy, 0);
1.18 nicm 4325: screen_write_stop(&ctx);
4326: }
1.1 nicm 4327: }
4328:
1.157 nicm 4329: static void
1.208 nicm 4330: window_copy_start_selection(struct window_mode_entry *wme)
1.1 nicm 4331: {
1.208 nicm 4332: struct window_copy_mode_data *data = wme->data;
1.1 nicm 4333:
1.18 nicm 4334: data->selx = data->cx;
1.54 nicm 4335: data->sely = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 4336:
1.161 nicm 4337: data->endselx = data->selx;
4338: data->endsely = data->sely;
4339:
4340: data->cursordrag = CURSORDRAG_ENDSEL;
4341:
1.252 nicm 4342: window_copy_set_selection(wme, 1, 0);
1.1 nicm 4343: }
4344:
1.157 nicm 4345: static int
1.208 nicm 4346: window_copy_adjust_selection(struct window_mode_entry *wme, u_int *selx,
4347: u_int *sely)
1.161 nicm 4348: {
1.208 nicm 4349: struct window_copy_mode_data *data = wme->data;
1.161 nicm 4350: struct screen *s = &data->screen;
4351: u_int sx, sy, ty;
4352: int relpos;
4353:
4354: sx = *selx;
4355: sy = *sely;
4356:
4357: ty = screen_hsize(data->backing) - data->oy;
4358: if (sy < ty) {
4359: relpos = WINDOW_COPY_REL_POS_ABOVE;
4360: if (!data->rectflag)
4361: sx = 0;
4362: sy = 0;
4363: } else if (sy > ty + screen_size_y(s) - 1) {
4364: relpos = WINDOW_COPY_REL_POS_BELOW;
4365: if (!data->rectflag)
4366: sx = screen_size_x(s) - 1;
4367: sy = screen_size_y(s) - 1;
4368: } else {
4369: relpos = WINDOW_COPY_REL_POS_ON_SCREEN;
4370: sy -= ty;
4371: }
4372:
4373: *selx = sx;
1.176 nicm 4374: *sely = sy;
1.161 nicm 4375: return (relpos);
4376: }
4377:
4378: static int
1.252 nicm 4379: window_copy_update_selection(struct window_mode_entry *wme, int may_redraw,
4380: int no_reset)
1.1 nicm 4381: {
1.208 nicm 4382: struct window_copy_mode_data *data = wme->data;
1.1 nicm 4383: struct screen *s = &data->screen;
1.192 nicm 4384:
4385: if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
4386: return (0);
1.252 nicm 4387: return (window_copy_set_selection(wme, may_redraw, no_reset));
1.192 nicm 4388: }
4389:
4390: static int
1.252 nicm 4391: window_copy_set_selection(struct window_mode_entry *wme, int may_redraw,
4392: int no_reset)
1.192 nicm 4393: {
1.208 nicm 4394: struct window_pane *wp = wme->wp;
4395: struct window_copy_mode_data *data = wme->data;
1.192 nicm 4396: struct screen *s = &data->screen;
1.136 nicm 4397: struct options *oo = wp->window->options;
1.1 nicm 4398: struct grid_cell gc;
1.161 nicm 4399: u_int sx, sy, cy, endsx, endsy;
4400: int startrelpos, endrelpos;
1.1 nicm 4401:
1.252 nicm 4402: window_copy_synchronize_cursor(wme, no_reset);
1.1 nicm 4403:
4404: /* Adjust the selection. */
4405: sx = data->selx;
4406: sy = data->sely;
1.208 nicm 4407: startrelpos = window_copy_adjust_selection(wme, &sx, &sy);
1.161 nicm 4408:
4409: /* Adjust the end of selection. */
4410: endsx = data->endselx;
4411: endsy = data->endsely;
1.208 nicm 4412: endrelpos = window_copy_adjust_selection(wme, &endsx, &endsy);
1.161 nicm 4413:
4414: /* Selection is outside of the current screen */
4415: if (startrelpos == endrelpos &&
4416: startrelpos != WINDOW_COPY_REL_POS_ON_SCREEN) {
4417: screen_hide_selection(s);
4418: return (0);
4419: }
1.1 nicm 4420:
1.161 nicm 4421: /* Set colours and selection. */
1.281 nicm 4422: style_apply(&gc, oo, "mode-style", NULL);
1.164 nicm 4423: gc.flags |= GRID_FLAG_NOPALETTE;
1.192 nicm 4424: screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag,
4425: data->modekeys, &gc);
1.42 nicm 4426:
1.96 nicm 4427: if (data->rectflag && may_redraw) {
1.42 nicm 4428: /*
4429: * Can't rely on the caller to redraw the right lines for
4430: * rectangle selection - find the highest line and the number
4431: * of lines, and redraw just past that in both directions
4432: */
4433: cy = data->cy;
1.182 nicm 4434: if (data->cursordrag == CURSORDRAG_ENDSEL) {
4435: if (sy < cy)
1.208 nicm 4436: window_copy_redraw_lines(wme, sy, cy - sy + 1);
1.182 nicm 4437: else
1.208 nicm 4438: window_copy_redraw_lines(wme, cy, sy - cy + 1);
1.182 nicm 4439: } else {
1.208 nicm 4440: if (endsy < cy) {
4441: window_copy_redraw_lines(wme, endsy,
4442: cy - endsy + 1);
4443: } else {
4444: window_copy_redraw_lines(wme, cy,
4445: endsy - cy + 1);
4446: }
1.182 nicm 4447: }
1.42 nicm 4448: }
4449:
1.1 nicm 4450: return (1);
4451: }
4452:
1.157 nicm 4453: static void *
1.208 nicm 4454: window_copy_get_selection(struct window_mode_entry *wme, size_t *len)
1.1 nicm 4455: {
1.208 nicm 4456: struct window_pane *wp = wme->wp;
4457: struct window_copy_mode_data *data = wme->data;
1.1 nicm 4458: struct screen *s = &data->screen;
4459: char *buf;
1.42 nicm 4460: size_t off;
1.111 nicm 4461: u_int i, xx, yy, sx, sy, ex, ey, ey_last;
1.188 nicm 4462: u_int firstsx, lastex, restex, restsx, selx;
1.69 nicm 4463: int keys;
1.1 nicm 4464:
1.282 nicm 4465: if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE) {
4466: buf = window_copy_match_at_cursor(data);
4467: if (buf != NULL)
4468: *len = strlen(buf);
1.293 nicm 4469: else
4470: *len = 0;
1.282 nicm 4471: return (buf);
4472: }
1.1 nicm 4473:
4474: buf = xmalloc(1);
4475: off = 0;
4476:
4477: *buf = '\0';
4478:
4479: /*
4480: * The selection extends from selx,sely to (adjusted) cx,cy on
4481: * the base screen.
4482: */
4483:
4484: /* Find start and end. */
1.161 nicm 4485: xx = data->endselx;
4486: yy = data->endsely;
1.2 nicm 4487: if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
1.1 nicm 4488: sx = xx; sy = yy;
4489: ex = data->selx; ey = data->sely;
4490: } else {
4491: sx = data->selx; sy = data->sely;
4492: ex = xx; ey = yy;
4493: }
4494:
4495: /* Trim ex to end of line. */
1.208 nicm 4496: ey_last = window_copy_find_length(wme, ey);
1.111 nicm 4497: if (ex > ey_last)
4498: ex = ey_last;
1.1 nicm 4499:
1.42 nicm 4500: /*
4501: * Deal with rectangle-copy if necessary; four situations: start of
4502: * first line (firstsx), end of last line (lastex), start (restsx) and
4503: * end (restex) of all other lines.
4504: */
4505: xx = screen_size_x(s);
1.69 nicm 4506:
4507: /*
4508: * Behave according to mode-keys. If it is emacs, copy like emacs,
4509: * keeping the top-left-most character, and dropping the
4510: * bottom-right-most, regardless of copy direction. If it is vi, also
4511: * keep bottom-right-most character.
4512: */
1.136 nicm 4513: keys = options_get_number(wp->window->options, "mode-keys");
1.42 nicm 4514: if (data->rectflag) {
4515: /*
4516: * Need to ignore the column with the cursor in it, which for
4517: * rectangular copy means knowing which side the cursor is on.
4518: */
1.188 nicm 4519: if (data->cursordrag == CURSORDRAG_ENDSEL)
4520: selx = data->selx;
4521: else
4522: selx = data->endselx;
4523: if (selx < data->cx) {
1.42 nicm 4524: /* Selection start is on the left. */
1.69 nicm 4525: if (keys == MODEKEY_EMACS) {
4526: lastex = data->cx;
4527: restex = data->cx;
4528: }
4529: else {
4530: lastex = data->cx + 1;
4531: restex = data->cx + 1;
4532: }
1.188 nicm 4533: firstsx = selx;
4534: restsx = selx;
1.42 nicm 4535: } else {
4536: /* Cursor is on the left. */
1.188 nicm 4537: lastex = selx + 1;
4538: restex = selx + 1;
1.64 nicm 4539: firstsx = data->cx;
4540: restsx = data->cx;
1.42 nicm 4541: }
4542: } else {
1.69 nicm 4543: if (keys == MODEKEY_EMACS)
4544: lastex = ex;
1.74 nicm 4545: else
1.69 nicm 4546: lastex = ex + 1;
1.42 nicm 4547: restex = xx;
4548: firstsx = sx;
4549: restsx = 0;
4550: }
4551:
1.1 nicm 4552: /* Copy the lines. */
1.110 nicm 4553: for (i = sy; i <= ey; i++) {
1.208 nicm 4554: window_copy_copy_line(wme, &buf, &off, i,
1.110 nicm 4555: (i == sy ? firstsx : restsx),
4556: (i == ey ? lastex : restex));
1.1 nicm 4557: }
4558:
1.26 nicm 4559: /* Don't bother if no data. */
4560: if (off == 0) {
1.81 nicm 4561: free(buf);
1.294 nicm 4562: *len = 0;
1.89 nicm 4563: return (NULL);
1.26 nicm 4564: }
1.319 nicm 4565: /* Remove final \n (unless at end in vi mode). */
4566: if (keys == MODEKEY_EMACS || lastex <= ey_last) {
4567: if (~grid_get_line(data->backing->grid, ey)->flags &
4568: GRID_LINE_WRAPPED || lastex != ey_last)
4569: off -= 1;
4570: }
1.111 nicm 4571: *len = off;
1.89 nicm 4572: return (buf);
4573: }
4574:
1.157 nicm 4575: static void
1.215 nicm 4576: window_copy_copy_buffer(struct window_mode_entry *wme, const char *prefix,
4577: void *buf, size_t len)
1.89 nicm 4578: {
1.208 nicm 4579: struct window_pane *wp = wme->wp;
4580: struct screen_write_ctx ctx;
1.72 nicm 4581:
1.178 nicm 4582: if (options_get_number(global_options, "set-clipboard") != 0) {
1.283 nicm 4583: screen_write_start_pane(&ctx, wp, NULL);
1.335 nicm 4584: screen_write_setselection(&ctx, "", buf, len);
1.91 nicm 4585: screen_write_stop(&ctx);
1.179 nicm 4586: notify_pane("pane-set-clipboard", wp);
1.91 nicm 4587: }
1.1 nicm 4588:
1.215 nicm 4589: paste_add(prefix, buf, len);
1.89 nicm 4590: }
4591:
1.314 nicm 4592: static void *
4593: window_copy_pipe_run(struct window_mode_entry *wme, struct session *s,
4594: const char *cmd, size_t *len)
1.89 nicm 4595: {
1.215 nicm 4596: void *buf;
4597: struct job *job;
1.89 nicm 4598:
1.314 nicm 4599: buf = window_copy_get_selection(wme, len);
1.277 nicm 4600: if (cmd == NULL || *cmd == '\0')
4601: cmd = options_get_string(global_options, "copy-command");
4602: if (cmd != NULL && *cmd != '\0') {
1.331 nicm 4603: job = job_run(cmd, 0, NULL, NULL, s, NULL, NULL, NULL, NULL,
4604: NULL, JOB_NOWAIT, -1, -1);
1.314 nicm 4605: bufferevent_write(job_get_event(job), buf, *len);
1.277 nicm 4606: }
1.314 nicm 4607: return (buf);
4608: }
4609:
4610: static void
4611: window_copy_pipe(struct window_mode_entry *wme, struct session *s,
4612: const char *cmd)
4613: {
4614: size_t len;
4615:
4616: window_copy_pipe_run(wme, s, cmd, &len);
4617: }
4618:
4619: static void
4620: window_copy_copy_pipe(struct window_mode_entry *wme, struct session *s,
4621: const char *prefix, const char *cmd)
4622: {
4623: void *buf;
4624: size_t len;
4625:
4626: buf = window_copy_pipe_run(wme, s, cmd, &len);
1.293 nicm 4627: if (buf != NULL)
4628: window_copy_copy_buffer(wme, prefix, buf, len);
1.89 nicm 4629: }
4630:
1.157 nicm 4631: static void
1.215 nicm 4632: window_copy_copy_selection(struct window_mode_entry *wme, const char *prefix)
1.89 nicm 4633: {
1.203 nicm 4634: char *buf;
1.114 nicm 4635: size_t len;
1.89 nicm 4636:
1.208 nicm 4637: buf = window_copy_get_selection(wme, &len);
1.203 nicm 4638: if (buf != NULL)
1.215 nicm 4639: window_copy_copy_buffer(wme, prefix, buf, len);
1.103 nicm 4640: }
4641:
1.157 nicm 4642: static void
1.208 nicm 4643: window_copy_append_selection(struct window_mode_entry *wme)
1.103 nicm 4644: {
1.208 nicm 4645: struct window_pane *wp = wme->wp;
1.108 nicm 4646: char *buf;
4647: struct paste_buffer *pb;
1.227 nicm 4648: const char *bufdata, *bufname = NULL;
1.132 nicm 4649: size_t len, bufsize;
1.108 nicm 4650: struct screen_write_ctx ctx;
1.103 nicm 4651:
1.208 nicm 4652: buf = window_copy_get_selection(wme, &len);
1.103 nicm 4653: if (buf == NULL)
4654: return;
4655:
1.178 nicm 4656: if (options_get_number(global_options, "set-clipboard") != 0) {
1.283 nicm 4657: screen_write_start_pane(&ctx, wp, NULL);
1.335 nicm 4658: screen_write_setselection(&ctx, "", buf, len);
1.103 nicm 4659: screen_write_stop(&ctx);
1.179 nicm 4660: notify_pane("pane-set-clipboard", wp);
1.103 nicm 4661: }
4662:
1.203 nicm 4663: pb = paste_get_top(&bufname);
1.103 nicm 4664: if (pb != NULL) {
1.132 nicm 4665: bufdata = paste_buffer_data(pb, &bufsize);
4666: buf = xrealloc(buf, len + bufsize);
4667: memmove(buf + bufsize, buf, len);
4668: memcpy(buf, bufdata, bufsize);
4669: len += bufsize;
1.103 nicm 4670: }
1.108 nicm 4671: if (paste_set(buf, len, bufname, NULL) != 0)
1.103 nicm 4672: free(buf);
1.1 nicm 4673: }
4674:
1.157 nicm 4675: static void
1.208 nicm 4676: window_copy_copy_line(struct window_mode_entry *wme, char **buf, size_t *off,
4677: u_int sy, u_int sx, u_int ex)
1.1 nicm 4678: {
1.208 nicm 4679: struct window_copy_mode_data *data = wme->data;
1.54 nicm 4680: struct grid *gd = data->backing->grid;
1.140 nicm 4681: struct grid_cell gc;
1.54 nicm 4682: struct grid_line *gl;
1.86 nicm 4683: struct utf8_data ud;
1.54 nicm 4684: u_int i, xx, wrapped = 0;
1.115 nicm 4685: const char *s;
1.1 nicm 4686:
4687: if (sx > ex)
4688: return;
4689:
1.16 nicm 4690: /*
4691: * Work out if the line was wrapped at the screen edge and all of it is
4692: * on screen.
4693: */
1.190 nicm 4694: gl = grid_get_line(gd, sy);
1.35 nicm 4695: if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
1.16 nicm 4696: wrapped = 1;
4697:
4698: /* If the line was wrapped, don't strip spaces (use the full length). */
4699: if (wrapped)
4700: xx = gl->cellsize;
4701: else
1.208 nicm 4702: xx = window_copy_find_length(wme, sy);
1.1 nicm 4703: if (ex > xx)
4704: ex = xx;
4705: if (sx > xx)
4706: sx = xx;
4707:
4708: if (sx < ex) {
4709: for (i = sx; i < ex; i++) {
1.140 nicm 4710: grid_get_cell(gd, i, sy, &gc);
4711: if (gc.flags & GRID_FLAG_PADDING)
1.1 nicm 4712: continue;
1.140 nicm 4713: utf8_copy(&ud, &gc.data);
4714: if (ud.size == 1 && (gc.attr & GRID_ATTR_CHARSET)) {
1.115 nicm 4715: s = tty_acs_get(NULL, ud.data[0]);
4716: if (s != NULL && strlen(s) <= sizeof ud.data) {
4717: ud.size = strlen(s);
1.117 nicm 4718: memcpy(ud.data, s, ud.size);
1.115 nicm 4719: }
4720: }
1.86 nicm 4721:
1.116 nicm 4722: *buf = xrealloc(*buf, (*off) + ud.size);
1.86 nicm 4723: memcpy(*buf + *off, ud.data, ud.size);
4724: *off += ud.size;
1.1 nicm 4725: }
4726: }
4727:
1.16 nicm 4728: /* Only add a newline if the line wasn't wrapped. */
1.44 nicm 4729: if (!wrapped || ex != xx) {
1.116 nicm 4730: *buf = xrealloc(*buf, (*off) + 1);
1.16 nicm 4731: (*buf)[(*off)++] = '\n';
4732: }
1.1 nicm 4733: }
4734:
1.157 nicm 4735: static void
1.208 nicm 4736: window_copy_clear_selection(struct window_mode_entry *wme)
1.47 nicm 4737: {
1.208 nicm 4738: struct window_copy_mode_data *data = wme->data;
1.47 nicm 4739: u_int px, py;
4740:
4741: screen_clear_selection(&data->screen);
4742:
1.161 nicm 4743: data->cursordrag = CURSORDRAG_NONE;
1.197 nicm 4744: data->lineflag = LINE_SEL_NONE;
1.250 nicm 4745: data->selflag = SEL_CHAR;
1.161 nicm 4746:
1.54 nicm 4747: py = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 4748: px = window_copy_find_length(wme, py);
1.47 nicm 4749: if (data->cx > px)
1.208 nicm 4750: window_copy_update_cursor(wme, px, data->cy);
1.47 nicm 4751: }
4752:
1.157 nicm 4753: static int
1.208 nicm 4754: window_copy_in_set(struct window_mode_entry *wme, u_int px, u_int py,
4755: const char *set)
1.1 nicm 4756: {
1.208 nicm 4757: struct window_copy_mode_data *data = wme->data;
1.140 nicm 4758: struct grid_cell gc;
4759:
4760: grid_get_cell(data->backing->grid, px, py, &gc);
1.204 nicm 4761: if (gc.flags & GRID_FLAG_PADDING)
4762: return (0);
1.224 nicm 4763: return (utf8_cstrhas(set, &gc.data));
1.1 nicm 4764: }
4765:
1.157 nicm 4766: static u_int
1.208 nicm 4767: window_copy_find_length(struct window_mode_entry *wme, u_int py)
1.1 nicm 4768: {
1.208 nicm 4769: struct window_copy_mode_data *data = wme->data;
1.1 nicm 4770:
1.224 nicm 4771: return (grid_line_length(data->backing->grid, py));
1.1 nicm 4772: }
4773:
1.157 nicm 4774: static void
1.208 nicm 4775: window_copy_cursor_start_of_line(struct window_mode_entry *wme)
1.5 nicm 4776: {
1.208 nicm 4777: struct window_copy_mode_data *data = wme->data;
1.58 nicm 4778: struct screen *back_s = data->backing;
1.307 nicm 4779: struct grid_reader gr;
1.315 nicm 4780: u_int px, py, oldy, hsize;
1.58 nicm 4781:
1.307 nicm 4782: px = data->cx;
4783: hsize = screen_hsize(back_s);
4784: py = hsize + data->cy - data->oy;
1.312 nicm 4785: oldy = data->cy;
1.307 nicm 4786:
4787: grid_reader_start(&gr, back_s->grid, px, py);
4788: grid_reader_cursor_start_of_line(&gr, 1);
4789: grid_reader_get_cursor(&gr, &px, &py);
1.315 nicm 4790: window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
1.6 nicm 4791: }
4792:
1.157 nicm 4793: static void
1.208 nicm 4794: window_copy_cursor_back_to_indentation(struct window_mode_entry *wme)
1.6 nicm 4795: {
1.208 nicm 4796: struct window_copy_mode_data *data = wme->data;
1.322 nicm 4797: struct screen *back_s = data->backing;
4798: struct grid_reader gr;
4799: u_int px, py, oldy, hsize;
1.6 nicm 4800:
1.322 nicm 4801: px = data->cx;
4802: hsize = screen_hsize(back_s);
4803: py = hsize + data->cy - data->oy;
4804: oldy = data->cy;
1.6 nicm 4805:
1.322 nicm 4806: grid_reader_start(&gr, back_s->grid, px, py);
4807: grid_reader_cursor_back_to_indentation(&gr);
4808: grid_reader_get_cursor(&gr, &px, &py);
4809: window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
1.5 nicm 4810: }
4811:
1.157 nicm 4812: static void
1.208 nicm 4813: window_copy_cursor_end_of_line(struct window_mode_entry *wme)
1.5 nicm 4814: {
1.208 nicm 4815: struct window_copy_mode_data *data = wme->data;
1.54 nicm 4816: struct screen *back_s = data->backing;
1.307 nicm 4817: struct grid_reader gr;
1.315 nicm 4818: u_int px, py, oldy, hsize;
1.307 nicm 4819:
4820: px = data->cx;
4821: hsize = screen_hsize(back_s);
4822: py = hsize + data->cy - data->oy;
1.312 nicm 4823: oldy = data->cy;
1.5 nicm 4824:
1.307 nicm 4825: grid_reader_start(&gr, back_s->grid, px, py);
4826: if (data->screen.sel != NULL && data->rectflag)
4827: grid_reader_cursor_end_of_line(&gr, 1, 1);
4828: else
4829: grid_reader_cursor_end_of_line(&gr, 1, 0);
4830: grid_reader_get_cursor(&gr, &px, &py);
1.315 nicm 4831: window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
4832: data->oy, oldy, px, py, 0);
1.95 nicm 4833: }
4834:
1.157 nicm 4835: static void
1.208 nicm 4836: window_copy_other_end(struct window_mode_entry *wme)
1.95 nicm 4837: {
1.208 nicm 4838: struct window_copy_mode_data *data = wme->data;
1.95 nicm 4839: struct screen *s = &data->screen;
1.161 nicm 4840: u_int selx, sely, cy, yy, hsize;
1.95 nicm 4841:
1.192 nicm 4842: if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
1.95 nicm 4843: return;
4844:
1.192 nicm 4845: if (data->lineflag == LINE_SEL_LEFT_RIGHT)
4846: data->lineflag = LINE_SEL_RIGHT_LEFT;
4847: else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
4848: data->lineflag = LINE_SEL_LEFT_RIGHT;
1.118 nicm 4849:
1.161 nicm 4850: switch (data->cursordrag) {
4851: case CURSORDRAG_NONE:
4852: case CURSORDRAG_SEL:
4853: data->cursordrag = CURSORDRAG_ENDSEL;
4854: break;
4855: case CURSORDRAG_ENDSEL:
4856: data->cursordrag = CURSORDRAG_SEL;
4857: break;
4858: }
4859:
4860: selx = data->endselx;
4861: sely = data->endsely;
4862: if (data->cursordrag == CURSORDRAG_SEL) {
4863: selx = data->selx;
4864: sely = data->sely;
4865: }
4866:
1.95 nicm 4867: cy = data->cy;
4868: yy = screen_hsize(data->backing) + data->cy - data->oy;
4869:
4870: data->cx = selx;
4871:
1.122 nicm 4872: hsize = screen_hsize(data->backing);
1.161 nicm 4873: if (sely < hsize - data->oy) { /* above */
1.122 nicm 4874: data->oy = hsize - sely;
1.95 nicm 4875: data->cy = 0;
1.161 nicm 4876: } else if (sely > hsize - data->oy + screen_size_y(s)) { /* below */
1.122 nicm 4877: data->oy = hsize - sely + screen_size_y(s) - 1;
1.95 nicm 4878: data->cy = screen_size_y(s) - 1;
4879: } else
4880: data->cy = cy + sely - yy;
4881:
1.252 nicm 4882: window_copy_update_selection(wme, 1, 1);
1.208 nicm 4883: window_copy_redraw_screen(wme);
1.5 nicm 4884: }
4885:
1.157 nicm 4886: static void
1.208 nicm 4887: window_copy_cursor_left(struct window_mode_entry *wme)
1.1 nicm 4888: {
1.208 nicm 4889: struct window_copy_mode_data *data = wme->data;
1.307 nicm 4890: struct screen *back_s = data->backing;
4891: struct grid_reader gr;
1.315 nicm 4892: u_int px, py, oldy, hsize;
1.307 nicm 4893:
4894: px = data->cx;
4895: hsize = screen_hsize(back_s);
4896: py = hsize + data->cy - data->oy;
1.315 nicm 4897: oldy = data->cy;
1.1 nicm 4898:
1.307 nicm 4899: grid_reader_start(&gr, back_s->grid, px, py);
1.322 nicm 4900: grid_reader_cursor_left(&gr, 1);
1.307 nicm 4901: grid_reader_get_cursor(&gr, &px, &py);
1.315 nicm 4902: window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
1.1 nicm 4903: }
4904:
1.157 nicm 4905: static void
1.305 nicm 4906: window_copy_cursor_right(struct window_mode_entry *wme, int all)
1.1 nicm 4907: {
1.208 nicm 4908: struct window_copy_mode_data *data = wme->data;
1.307 nicm 4909: struct screen *back_s = data->backing;
4910: struct grid_reader gr;
1.315 nicm 4911: u_int px, py, oldy, hsize;
1.307 nicm 4912:
4913: px = data->cx;
4914: hsize = screen_hsize(back_s);
4915: py = hsize + data->cy - data->oy;
1.315 nicm 4916: oldy = data->cy;
1.1 nicm 4917:
1.307 nicm 4918: grid_reader_start(&gr, back_s->grid, px, py);
4919: grid_reader_cursor_right(&gr, 1, all);
4920: grid_reader_get_cursor(&gr, &px, &py);
1.315 nicm 4921: window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
4922: data->oy, oldy, px, py, 0);
1.1 nicm 4923: }
4924:
1.157 nicm 4925: static void
1.208 nicm 4926: window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only)
1.1 nicm 4927: {
1.208 nicm 4928: struct window_copy_mode_data *data = wme->data;
1.36 nicm 4929: struct screen *s = &data->screen;
1.1 nicm 4930: u_int ox, oy, px, py;
1.324 nicm 4931: int norectsel;
1.1 nicm 4932:
1.324 nicm 4933: norectsel = data->screen.sel == NULL || !data->rectflag;
1.54 nicm 4934: oy = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 4935: ox = window_copy_find_length(wme, oy);
1.324 nicm 4936: if (norectsel && data->cx != ox) {
1.25 nicm 4937: data->lastcx = data->cx;
4938: data->lastsx = ox;
4939: }
1.1 nicm 4940:
1.192 nicm 4941: if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
1.208 nicm 4942: window_copy_other_end(wme);
1.118 nicm 4943:
1.28 nicm 4944: if (scroll_only || data->cy == 0) {
1.324 nicm 4945: if (norectsel)
4946: data->cx = data->lastcx;
1.208 nicm 4947: window_copy_scroll_down(wme, 1);
1.36 nicm 4948: if (scroll_only) {
4949: if (data->cy == screen_size_y(s) - 1)
1.208 nicm 4950: window_copy_redraw_lines(wme, data->cy, 1);
1.36 nicm 4951: else
1.208 nicm 4952: window_copy_redraw_lines(wme, data->cy, 2);
1.36 nicm 4953: }
1.28 nicm 4954: } else {
1.324 nicm 4955: if (norectsel) {
4956: window_copy_update_cursor(wme, data->lastcx,
4957: data->cy - 1);
4958: } else
4959: window_copy_update_cursor(wme, data->cx, data->cy - 1);
1.252 nicm 4960: if (window_copy_update_selection(wme, 1, 0)) {
1.36 nicm 4961: if (data->cy == screen_size_y(s) - 1)
1.208 nicm 4962: window_copy_redraw_lines(wme, data->cy, 1);
1.36 nicm 4963: else
1.208 nicm 4964: window_copy_redraw_lines(wme, data->cy, 2);
1.36 nicm 4965: }
1.1 nicm 4966: }
4967:
1.324 nicm 4968: if (norectsel) {
1.54 nicm 4969: py = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 4970: px = window_copy_find_length(wme, py);
1.49 nicm 4971: if ((data->cx >= data->lastsx && data->cx != px) ||
4972: data->cx > px)
1.307 nicm 4973: {
4974: window_copy_update_cursor(wme, px, data->cy);
4975: if (window_copy_update_selection(wme, 1, 0))
4976: window_copy_redraw_lines(wme, data->cy, 1);
4977: }
1.47 nicm 4978: }
1.118 nicm 4979:
1.192 nicm 4980: if (data->lineflag == LINE_SEL_LEFT_RIGHT)
1.307 nicm 4981: {
4982: py = screen_hsize(data->backing) + data->cy - data->oy;
4983: if (data->rectflag)
4984: px = screen_size_x(data->backing);
4985: else
4986: px = window_copy_find_length(wme, py);
4987: window_copy_update_cursor(wme, px, data->cy);
4988: if (window_copy_update_selection(wme, 1, 0))
4989: window_copy_redraw_lines(wme, data->cy, 1);
4990: }
1.192 nicm 4991: else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
1.307 nicm 4992: {
4993: window_copy_update_cursor(wme, 0, data->cy);
4994: if (window_copy_update_selection(wme, 1, 0))
4995: window_copy_redraw_lines(wme, data->cy, 1);
4996: }
1.1 nicm 4997: }
4998:
1.157 nicm 4999: static void
1.208 nicm 5000: window_copy_cursor_down(struct window_mode_entry *wme, int scroll_only)
1.1 nicm 5001: {
1.208 nicm 5002: struct window_copy_mode_data *data = wme->data;
1.1 nicm 5003: struct screen *s = &data->screen;
5004: u_int ox, oy, px, py;
1.324 nicm 5005: int norectsel;
1.1 nicm 5006:
1.324 nicm 5007: norectsel = data->screen.sel == NULL || !data->rectflag;
1.54 nicm 5008: oy = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 5009: ox = window_copy_find_length(wme, oy);
1.324 nicm 5010: if (norectsel && data->cx != ox) {
1.25 nicm 5011: data->lastcx = data->cx;
5012: data->lastsx = ox;
5013: }
1.1 nicm 5014:
1.192 nicm 5015: if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
1.208 nicm 5016: window_copy_other_end(wme);
1.118 nicm 5017:
1.28 nicm 5018: if (scroll_only || data->cy == screen_size_y(s) - 1) {
1.324 nicm 5019: if (norectsel)
5020: data->cx = data->lastcx;
1.208 nicm 5021: window_copy_scroll_up(wme, 1);
1.31 nicm 5022: if (scroll_only && data->cy > 0)
1.208 nicm 5023: window_copy_redraw_lines(wme, data->cy - 1, 2);
1.28 nicm 5024: } else {
1.324 nicm 5025: if (norectsel) {
5026: window_copy_update_cursor(wme, data->lastcx,
5027: data->cy + 1);
5028: } else
5029: window_copy_update_cursor(wme, data->cx, data->cy + 1);
1.252 nicm 5030: if (window_copy_update_selection(wme, 1, 0))
1.208 nicm 5031: window_copy_redraw_lines(wme, data->cy - 1, 2);
1.1 nicm 5032: }
5033:
1.324 nicm 5034: if (norectsel) {
1.54 nicm 5035: py = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 5036: px = window_copy_find_length(wme, py);
1.49 nicm 5037: if ((data->cx >= data->lastsx && data->cx != px) ||
5038: data->cx > px)
1.307 nicm 5039: {
5040: window_copy_update_cursor(wme, px, data->cy);
5041: if (window_copy_update_selection(wme, 1, 0))
5042: window_copy_redraw_lines(wme, data->cy, 1);
5043: }
1.52 nicm 5044: }
1.118 nicm 5045:
1.192 nicm 5046: if (data->lineflag == LINE_SEL_LEFT_RIGHT)
1.307 nicm 5047: {
5048: py = screen_hsize(data->backing) + data->cy - data->oy;
5049: if (data->rectflag)
5050: px = screen_size_x(data->backing);
5051: else
5052: px = window_copy_find_length(wme, py);
5053: window_copy_update_cursor(wme, px, data->cy);
5054: if (window_copy_update_selection(wme, 1, 0))
5055: window_copy_redraw_lines(wme, data->cy, 1);
5056: }
1.192 nicm 5057: else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
1.307 nicm 5058: {
5059: window_copy_update_cursor(wme, 0, data->cy);
5060: if (window_copy_update_selection(wme, 1, 0))
5061: window_copy_redraw_lines(wme, data->cy, 1);
5062: }
1.52 nicm 5063: }
5064:
1.157 nicm 5065: static void
1.208 nicm 5066: window_copy_cursor_jump(struct window_mode_entry *wme)
1.52 nicm 5067: {
1.208 nicm 5068: struct window_copy_mode_data *data = wme->data;
1.54 nicm 5069: struct screen *back_s = data->backing;
1.315 nicm 5070: struct grid_reader gr;
5071: u_int px, py, oldy, hsize;
1.52 nicm 5072:
5073: px = data->cx + 1;
1.315 nicm 5074: hsize = screen_hsize(back_s);
5075: py = hsize + data->cy - data->oy;
5076: oldy = data->cy;
1.52 nicm 5077:
1.315 nicm 5078: grid_reader_start(&gr, back_s->grid, px, py);
5079: if (grid_reader_cursor_jump(&gr, data->jumpchar)) {
5080: grid_reader_get_cursor(&gr, &px, &py);
5081: window_copy_acquire_cursor_down(wme, hsize,
5082: screen_size_y(back_s), data->oy, oldy, px, py, 0);
1.52 nicm 5083: }
5084: }
5085:
1.157 nicm 5086: static void
1.208 nicm 5087: window_copy_cursor_jump_back(struct window_mode_entry *wme)
1.52 nicm 5088: {
1.208 nicm 5089: struct window_copy_mode_data *data = wme->data;
1.54 nicm 5090: struct screen *back_s = data->backing;
1.315 nicm 5091: struct grid_reader gr;
5092: u_int px, py, oldy, hsize;
1.52 nicm 5093:
5094: px = data->cx;
1.315 nicm 5095: hsize = screen_hsize(back_s);
5096: py = hsize + data->cy - data->oy;
5097: oldy = data->cy;
1.52 nicm 5098:
1.315 nicm 5099: grid_reader_start(&gr, back_s->grid, px, py);
1.322 nicm 5100: grid_reader_cursor_left(&gr, 0);
1.315 nicm 5101: if (grid_reader_cursor_jump_back(&gr, data->jumpchar)) {
5102: grid_reader_get_cursor(&gr, &px, &py);
5103: window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px,
5104: py);
1.76 nicm 5105: }
5106: }
5107:
1.157 nicm 5108: static void
1.208 nicm 5109: window_copy_cursor_jump_to(struct window_mode_entry *wme)
1.76 nicm 5110: {
1.208 nicm 5111: struct window_copy_mode_data *data = wme->data;
1.76 nicm 5112: struct screen *back_s = data->backing;
1.315 nicm 5113: struct grid_reader gr;
5114: u_int px, py, oldy, hsize;
1.76 nicm 5115:
1.184 nicm 5116: px = data->cx + 2;
1.315 nicm 5117: hsize = screen_hsize(back_s);
5118: py = hsize + data->cy - data->oy;
5119: oldy = data->cy;
1.76 nicm 5120:
1.315 nicm 5121: grid_reader_start(&gr, back_s->grid, px, py);
5122: if (grid_reader_cursor_jump(&gr, data->jumpchar)) {
1.322 nicm 5123: grid_reader_cursor_left(&gr, 1);
1.315 nicm 5124: grid_reader_get_cursor(&gr, &px, &py);
5125: window_copy_acquire_cursor_down(wme, hsize,
5126: screen_size_y(back_s), data->oy, oldy, px, py, 0);
1.76 nicm 5127: }
5128: }
5129:
1.157 nicm 5130: static void
1.208 nicm 5131: window_copy_cursor_jump_to_back(struct window_mode_entry *wme)
1.76 nicm 5132: {
1.208 nicm 5133: struct window_copy_mode_data *data = wme->data;
1.76 nicm 5134: struct screen *back_s = data->backing;
1.315 nicm 5135: struct grid_reader gr;
5136: u_int px, py, oldy, hsize;
1.76 nicm 5137:
5138: px = data->cx;
1.315 nicm 5139: hsize = screen_hsize(back_s);
5140: py = hsize + data->cy - data->oy;
5141: oldy = data->cy;
1.76 nicm 5142:
1.315 nicm 5143: grid_reader_start(&gr, back_s->grid, px, py);
1.322 nicm 5144: grid_reader_cursor_left(&gr, 0);
5145: grid_reader_cursor_left(&gr, 0);
1.315 nicm 5146: if (grid_reader_cursor_jump_back(&gr, data->jumpchar)) {
5147: grid_reader_cursor_right(&gr, 1, 0);
5148: grid_reader_get_cursor(&gr, &px, &py);
5149: window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px,
5150: py);
1.47 nicm 5151: }
1.1 nicm 5152: }
5153:
1.157 nicm 5154: static void
1.208 nicm 5155: window_copy_cursor_next_word(struct window_mode_entry *wme,
5156: const char *separators)
1.40 nicm 5157: {
1.208 nicm 5158: struct window_copy_mode_data *data = wme->data;
1.54 nicm 5159: struct screen *back_s = data->backing;
1.312 nicm 5160: struct grid_reader gr;
1.315 nicm 5161: u_int px, py, oldy, hsize;
1.40 nicm 5162:
5163: px = data->cx;
1.312 nicm 5164: hsize = screen_hsize(back_s);
5165: py = hsize + data->cy - data->oy;
5166: oldy = data->cy;
1.40 nicm 5167:
1.312 nicm 5168: grid_reader_start(&gr, back_s->grid, px, py);
5169: grid_reader_cursor_next_word(&gr, separators);
5170: grid_reader_get_cursor(&gr, &px, &py);
1.315 nicm 5171: window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
5172: data->oy, oldy, px, py, 0);
1.40 nicm 5173: }
5174:
1.319 nicm 5175: /* Compute the next place where a word ends. */
1.157 nicm 5176: static void
1.247 nicm 5177: window_copy_cursor_next_word_end_pos(struct window_mode_entry *wme,
5178: const char *separators, u_int *ppx, u_int *ppy)
5179: {
5180: struct window_pane *wp = wme->wp;
5181: struct window_copy_mode_data *data = wme->data;
5182: struct options *oo = wp->window->options;
5183: struct screen *back_s = data->backing;
1.319 nicm 5184: struct grid_reader gr;
5185: u_int px, py, hsize;
1.247 nicm 5186:
5187: px = data->cx;
1.319 nicm 5188: hsize = screen_hsize(back_s);
5189: py = hsize + data->cy - data->oy;
1.247 nicm 5190:
1.319 nicm 5191: grid_reader_start(&gr, back_s->grid, px, py);
1.323 nicm 5192: if (options_get_number(oo, "mode-keys") == MODEKEY_VI) {
5193: if (!grid_reader_in_set(&gr, WHITESPACE))
5194: grid_reader_cursor_right(&gr, 0, 0);
5195: grid_reader_cursor_next_word_end(&gr, separators);
1.322 nicm 5196: grid_reader_cursor_left(&gr, 1);
1.323 nicm 5197: } else
5198: grid_reader_cursor_next_word_end(&gr, separators);
1.319 nicm 5199: grid_reader_get_cursor(&gr, &px, &py);
1.247 nicm 5200: *ppx = px;
5201: *ppy = py;
5202: }
5203:
1.319 nicm 5204: /* Move to the next place where a word ends. */
1.247 nicm 5205: static void
1.208 nicm 5206: window_copy_cursor_next_word_end(struct window_mode_entry *wme,
1.255 nicm 5207: const char *separators, int no_reset)
1.1 nicm 5208: {
1.208 nicm 5209: struct window_pane *wp = wme->wp;
5210: struct window_copy_mode_data *data = wme->data;
1.136 nicm 5211: struct options *oo = wp->window->options;
1.54 nicm 5212: struct screen *back_s = data->backing;
1.307 nicm 5213: struct grid_reader gr;
1.315 nicm 5214: u_int px, py, oldy, hsize;
1.1 nicm 5215:
1.18 nicm 5216: px = data->cx;
1.307 nicm 5217: hsize = screen_hsize(back_s);
5218: py = hsize + data->cy - data->oy;
1.312 nicm 5219: oldy = data->cy;
1.1 nicm 5220:
1.307 nicm 5221: grid_reader_start(&gr, back_s->grid, px, py);
1.323 nicm 5222: if (options_get_number(oo, "mode-keys") == MODEKEY_VI) {
5223: if (!grid_reader_in_set(&gr, WHITESPACE))
5224: grid_reader_cursor_right(&gr, 0, 0);
5225: grid_reader_cursor_next_word_end(&gr, separators);
1.322 nicm 5226: grid_reader_cursor_left(&gr, 1);
1.323 nicm 5227: } else
5228: grid_reader_cursor_next_word_end(&gr, separators);
1.307 nicm 5229: grid_reader_get_cursor(&gr, &px, &py);
1.315 nicm 5230: window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
5231: data->oy, oldy, px, py, no_reset);
1.1 nicm 5232: }
5233:
1.247 nicm 5234: /* Compute the previous place where a word begins. */
5235: static void
5236: window_copy_cursor_previous_word_pos(struct window_mode_entry *wme,
1.323 nicm 5237: const char *separators, u_int *ppx, u_int *ppy)
1.247 nicm 5238: {
5239: struct window_copy_mode_data *data = wme->data;
1.319 nicm 5240: struct screen *back_s = data->backing;
5241: struct grid_reader gr;
1.306 nicm 5242: u_int px, py, hsize;
1.247 nicm 5243:
5244: px = data->cx;
1.319 nicm 5245: hsize = screen_hsize(back_s);
1.306 nicm 5246: py = hsize + data->cy - data->oy;
1.247 nicm 5247:
1.319 nicm 5248: grid_reader_start(&gr, back_s->grid, px, py);
1.323 nicm 5249: grid_reader_cursor_previous_word(&gr, separators, /* already= */ 0,
5250: /* stop_at_eol= */ 1);
1.319 nicm 5251: grid_reader_get_cursor(&gr, &px, &py);
1.247 nicm 5252: *ppx = px;
5253: *ppy = py;
5254: }
5255:
1.8 nicm 5256: /* Move to the previous place where a word begins. */
1.157 nicm 5257: static void
1.208 nicm 5258: window_copy_cursor_previous_word(struct window_mode_entry *wme,
1.229 nicm 5259: const char *separators, int already)
1.1 nicm 5260: {
1.208 nicm 5261: struct window_copy_mode_data *data = wme->data;
1.329 nicm 5262: struct window *w = wme->wp->window;
1.307 nicm 5263: struct screen *back_s = data->backing;
5264: struct grid_reader gr;
1.315 nicm 5265: u_int px, py, oldy, hsize;
1.323 nicm 5266: int stop_at_eol;
5267:
1.329 nicm 5268: if (options_get_number(w->options, "mode-keys") == MODEKEY_EMACS)
5269: stop_at_eol = 1;
5270: else
5271: stop_at_eol = 0;
1.1 nicm 5272:
1.18 nicm 5273: px = data->cx;
1.307 nicm 5274: hsize = screen_hsize(back_s);
1.306 nicm 5275: py = hsize + data->cy - data->oy;
1.312 nicm 5276: oldy = data->cy;
1.1 nicm 5277:
1.307 nicm 5278: grid_reader_start(&gr, back_s->grid, px, py);
1.323 nicm 5279: grid_reader_cursor_previous_word(&gr, separators, already, stop_at_eol);
1.307 nicm 5280: grid_reader_get_cursor(&gr, &px, &py);
1.315 nicm 5281: window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
1.1 nicm 5282: }
5283:
1.157 nicm 5284: static void
1.208 nicm 5285: window_copy_scroll_up(struct window_mode_entry *wme, u_int ny)
1.1 nicm 5286: {
1.208 nicm 5287: struct window_pane *wp = wme->wp;
5288: struct window_copy_mode_data *data = wme->data;
1.1 nicm 5289: struct screen *s = &data->screen;
5290: struct screen_write_ctx ctx;
5291:
5292: if (data->oy < ny)
5293: ny = data->oy;
5294: if (ny == 0)
5295: return;
5296: data->oy -= ny;
5297:
1.264 nicm 5298: if (data->searchmark != NULL && !data->timeout)
1.296 nicm 5299: window_copy_search_marks(wme, NULL, data->searchregex, 1);
1.252 nicm 5300: window_copy_update_selection(wme, 0, 0);
1.96 nicm 5301:
1.283 nicm 5302: screen_write_start_pane(&ctx, wp, NULL);
1.212 nicm 5303: screen_write_cursormove(&ctx, 0, 0, 0);
1.159 nicm 5304: screen_write_deleteline(&ctx, ny, 8);
1.208 nicm 5305: window_copy_write_lines(wme, &ctx, screen_size_y(s) - ny, ny);
5306: window_copy_write_line(wme, &ctx, 0);
1.31 nicm 5307: if (screen_size_y(s) > 1)
1.208 nicm 5308: window_copy_write_line(wme, &ctx, 1);
1.31 nicm 5309: if (screen_size_y(s) > 3)
1.208 nicm 5310: window_copy_write_line(wme, &ctx, screen_size_y(s) - 2);
1.192 nicm 5311: if (s->sel != NULL && screen_size_y(s) > ny)
1.208 nicm 5312: window_copy_write_line(wme, &ctx, screen_size_y(s) - ny - 1);
1.212 nicm 5313: screen_write_cursormove(&ctx, data->cx, data->cy, 0);
1.1 nicm 5314: screen_write_stop(&ctx);
5315: }
5316:
1.157 nicm 5317: static void
1.208 nicm 5318: window_copy_scroll_down(struct window_mode_entry *wme, u_int ny)
1.1 nicm 5319: {
1.208 nicm 5320: struct window_pane *wp = wme->wp;
5321: struct window_copy_mode_data *data = wme->data;
1.1 nicm 5322: struct screen *s = &data->screen;
5323: struct screen_write_ctx ctx;
5324:
1.54 nicm 5325: if (ny > screen_hsize(data->backing))
1.1 nicm 5326: return;
5327:
1.54 nicm 5328: if (data->oy > screen_hsize(data->backing) - ny)
5329: ny = screen_hsize(data->backing) - data->oy;
1.1 nicm 5330: if (ny == 0)
5331: return;
5332: data->oy += ny;
5333:
1.264 nicm 5334: if (data->searchmark != NULL && !data->timeout)
1.296 nicm 5335: window_copy_search_marks(wme, NULL, data->searchregex, 1);
1.252 nicm 5336: window_copy_update_selection(wme, 0, 0);
1.96 nicm 5337:
1.283 nicm 5338: screen_write_start_pane(&ctx, wp, NULL);
1.212 nicm 5339: screen_write_cursormove(&ctx, 0, 0, 0);
1.159 nicm 5340: screen_write_insertline(&ctx, ny, 8);
1.208 nicm 5341: window_copy_write_lines(wme, &ctx, 0, ny);
1.192 nicm 5342: if (s->sel != NULL && screen_size_y(s) > ny)
1.208 nicm 5343: window_copy_write_line(wme, &ctx, ny);
1.96 nicm 5344: else if (ny == 1) /* nuke position */
1.208 nicm 5345: window_copy_write_line(wme, &ctx, 1);
1.212 nicm 5346: screen_write_cursormove(&ctx, data->cx, data->cy, 0);
1.1 nicm 5347: screen_write_stop(&ctx);
5348: }
1.42 nicm 5349:
1.157 nicm 5350: static void
1.313 nicm 5351: window_copy_rectangle_set(struct window_mode_entry *wme, int rectflag)
1.42 nicm 5352: {
1.208 nicm 5353: struct window_copy_mode_data *data = wme->data;
1.47 nicm 5354: u_int px, py;
1.42 nicm 5355:
1.313 nicm 5356: data->rectflag = rectflag;
1.47 nicm 5357:
1.54 nicm 5358: py = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 5359: px = window_copy_find_length(wme, py);
1.47 nicm 5360: if (data->cx > px)
1.208 nicm 5361: window_copy_update_cursor(wme, px, data->cy);
1.42 nicm 5362:
1.252 nicm 5363: window_copy_update_selection(wme, 1, 0);
1.208 nicm 5364: window_copy_redraw_screen(wme);
1.156 nicm 5365: }
5366:
1.157 nicm 5367: static void
1.156 nicm 5368: window_copy_move_mouse(struct mouse_event *m)
5369: {
1.211 nicm 5370: struct window_pane *wp;
5371: struct window_mode_entry *wme;
5372: u_int x, y;
1.156 nicm 5373:
5374: wp = cmd_mouse_pane(m, NULL, NULL);
1.211 nicm 5375: if (wp == NULL)
5376: return;
5377: wme = TAILQ_FIRST(&wp->modes);
1.223 nicm 5378: if (wme == NULL)
5379: return;
5380: if (wme->mode != &window_copy_mode && wme->mode != &window_view_mode)
1.156 nicm 5381: return;
5382:
1.183 nicm 5383: if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
1.156 nicm 5384: return;
5385:
1.211 nicm 5386: window_copy_update_cursor(wme, x, y);
1.126 nicm 5387: }
5388:
5389: void
1.141 nicm 5390: window_copy_start_drag(struct client *c, struct mouse_event *m)
1.126 nicm 5391: {
1.211 nicm 5392: struct window_pane *wp;
5393: struct window_mode_entry *wme;
1.247 nicm 5394: struct window_copy_mode_data *data;
1.248 nicm 5395: u_int x, y, yg;
1.126 nicm 5396:
1.155 nicm 5397: if (c == NULL)
5398: return;
5399:
1.126 nicm 5400: wp = cmd_mouse_pane(m, NULL, NULL);
1.211 nicm 5401: if (wp == NULL)
5402: return;
5403: wme = TAILQ_FIRST(&wp->modes);
1.223 nicm 5404: if (wme == NULL)
5405: return;
5406: if (wme->mode != &window_copy_mode && wme->mode != &window_view_mode)
1.126 nicm 5407: return;
5408:
5409: if (cmd_mouse_at(wp, m, &x, &y, 1) != 0)
5410: return;
5411:
5412: c->tty.mouse_drag_update = window_copy_drag_update;
1.217 nicm 5413: c->tty.mouse_drag_release = window_copy_drag_release;
1.126 nicm 5414:
1.247 nicm 5415: data = wme->data;
1.248 nicm 5416: yg = screen_hsize(data->backing) + y - data->oy;
5417: if (x < data->selrx || x > data->endselrx || yg != data->selry)
5418: data->selflag = SEL_CHAR;
1.247 nicm 5419: switch (data->selflag) {
1.311 nicm 5420: case SEL_WORD:
1.323 nicm 5421: if (data->separators != NULL) {
1.247 nicm 5422: window_copy_update_cursor(wme, x, y);
1.323 nicm 5423: window_copy_cursor_previous_word_pos(wme,
5424: data->separators, &x, &y);
1.311 nicm 5425: y -= screen_hsize(data->backing) - data->oy;
5426: }
5427: window_copy_update_cursor(wme, x, y);
5428: break;
5429: case SEL_LINE:
5430: window_copy_update_cursor(wme, 0, y);
5431: break;
5432: case SEL_CHAR:
5433: window_copy_update_cursor(wme, x, y);
5434: window_copy_start_selection(wme);
5435: break;
1.247 nicm 5436: }
5437:
1.211 nicm 5438: window_copy_redraw_screen(wme);
1.220 nicm 5439: window_copy_drag_update(c, m);
1.126 nicm 5440: }
5441:
1.157 nicm 5442: static void
1.211 nicm 5443: window_copy_drag_update(struct client *c, struct mouse_event *m)
1.126 nicm 5444: {
5445: struct window_pane *wp;
1.211 nicm 5446: struct window_mode_entry *wme;
1.126 nicm 5447: struct window_copy_mode_data *data;
1.217 nicm 5448: u_int x, y, old_cx, old_cy;
5449: struct timeval tv = {
5450: .tv_usec = WINDOW_COPY_DRAG_REPEAT_TIME
5451: };
1.126 nicm 5452:
1.211 nicm 5453: if (c == NULL)
5454: return;
5455:
1.126 nicm 5456: wp = cmd_mouse_pane(m, NULL, NULL);
1.211 nicm 5457: if (wp == NULL)
1.126 nicm 5458: return;
1.211 nicm 5459: wme = TAILQ_FIRST(&wp->modes);
1.223 nicm 5460: if (wme == NULL)
5461: return;
5462: if (wme->mode != &window_copy_mode && wme->mode != &window_view_mode)
1.211 nicm 5463: return;
1.217 nicm 5464:
1.211 nicm 5465: data = wme->data;
1.217 nicm 5466: evtimer_del(&data->dragtimer);
1.126 nicm 5467:
5468: if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
5469: return;
1.217 nicm 5470: old_cx = data->cx;
1.126 nicm 5471: old_cy = data->cy;
5472:
1.211 nicm 5473: window_copy_update_cursor(wme, x, y);
1.252 nicm 5474: if (window_copy_update_selection(wme, 1, 0))
1.211 nicm 5475: window_copy_redraw_selection(wme, old_cy);
1.217 nicm 5476: if (old_cy != data->cy || old_cx == data->cx) {
5477: if (y == 0) {
5478: evtimer_add(&data->dragtimer, &tv);
5479: window_copy_cursor_up(wme, 1);
5480: } else if (y == screen_size_y(&data->screen) - 1) {
5481: evtimer_add(&data->dragtimer, &tv);
5482: window_copy_cursor_down(wme, 1);
5483: }
5484: }
5485: }
5486:
5487: static void
5488: window_copy_drag_release(struct client *c, struct mouse_event *m)
5489: {
5490: struct window_pane *wp;
5491: struct window_mode_entry *wme;
5492: struct window_copy_mode_data *data;
5493:
5494: if (c == NULL)
5495: return;
5496:
5497: wp = cmd_mouse_pane(m, NULL, NULL);
5498: if (wp == NULL)
5499: return;
5500: wme = TAILQ_FIRST(&wp->modes);
1.223 nicm 5501: if (wme == NULL)
5502: return;
5503: if (wme->mode != &window_copy_mode && wme->mode != &window_view_mode)
1.217 nicm 5504: return;
5505:
5506: data = wme->data;
5507: evtimer_del(&data->dragtimer);
1.288 nicm 5508: }
5509:
5510: static void
5511: window_copy_jump_to_mark(struct window_mode_entry *wme)
5512: {
5513: struct window_copy_mode_data *data = wme->data;
5514: u_int tmx, tmy;
5515:
5516: tmx = data->cx;
5517: tmy = screen_hsize(data->backing) + data->cy - data->oy;
5518: data->cx = data->mx;
5519: if (data->my < screen_hsize(data->backing)) {
5520: data->cy = 0;
5521: data->oy = screen_hsize(data->backing) - data->my;
5522: } else {
5523: data->cy = data->my - screen_hsize(data->backing);
5524: data->oy = 0;
5525: }
5526: data->mx = tmx;
5527: data->my = tmy;
5528: data->showmark = 1;
5529: window_copy_update_selection(wme, 0, 0);
5530: window_copy_redraw_screen(wme);
1.315 nicm 5531: }
5532:
5533: /* Scroll up if the cursor went off the visible screen. */
5534: static void
5535: window_copy_acquire_cursor_up(struct window_mode_entry *wme, u_int hsize,
5536: u_int oy, u_int oldy, u_int px, u_int py)
5537: {
5538: u_int cy, yy, ny, nd;
5539:
5540: yy = hsize - oy;
5541: if (py < yy) {
5542: ny = yy - py;
5543: cy = 0;
5544: nd = 1;
5545: } else {
5546: ny = 0;
5547: cy = py - yy;
5548: nd = oldy - cy + 1;
5549: }
5550: while (ny > 0) {
5551: window_copy_cursor_up(wme, 1);
5552: ny--;
5553: }
5554: window_copy_update_cursor(wme, px, cy);
5555: if (window_copy_update_selection(wme, 1, 0))
5556: window_copy_redraw_lines(wme, cy, nd);
5557: }
5558:
5559: /* Scroll down if the cursor went off the visible screen. */
5560: static void
5561: window_copy_acquire_cursor_down(struct window_mode_entry *wme, u_int hsize,
5562: u_int sy, u_int oy, u_int oldy, u_int px, u_int py, int no_reset)
5563: {
5564: u_int cy, yy, ny, nd;
5565:
5566: cy = py - hsize + oy;
5567: yy = sy - 1;
5568: if (cy > yy) {
5569: ny = cy - yy;
5570: oldy = yy;
5571: nd = 1;
5572: } else {
5573: ny = 0;
5574: nd = cy - oldy + 1;
5575: }
5576: while (ny > 0) {
5577: window_copy_cursor_down(wme, 1);
5578: ny--;
5579: }
5580: if (cy > yy)
5581: window_copy_update_cursor(wme, px, yy);
5582: else
5583: window_copy_update_cursor(wme, px, cy);
5584: if (window_copy_update_selection(wme, 1, no_reset))
5585: window_copy_redraw_lines(wme, oldy, nd);
1.42 nicm 5586: }