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