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