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