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