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