Annotation of src/usr.bin/tmux/window-copy.c, Revision 1.213
1.213 ! nicm 1: /* $OpenBSD: window-copy.c,v 1.212 2019/03/12 20:02:47 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.21 nicm 22: #include <stdlib.h>
1.1 nicm 23: #include <string.h>
24:
25: #include "tmux.h"
26:
1.208 nicm 27: static const char *window_copy_key_table(struct window_mode_entry *);
28: static void window_copy_command(struct window_mode_entry *, struct client *,
1.205 nicm 29: struct session *, struct winlink *, struct args *,
30: struct mouse_event *);
1.208 nicm 31: static struct screen *window_copy_init(struct window_mode_entry *,
1.177 nicm 32: struct cmd_find_state *, struct args *);
1.210 nicm 33: static struct screen *window_copy_view_init(struct window_mode_entry *,
34: struct cmd_find_state *, struct args *);
1.208 nicm 35: static void window_copy_free(struct window_mode_entry *);
36: static void window_copy_resize(struct window_mode_entry *, u_int, u_int);
37: static void window_copy_formats(struct window_mode_entry *,
38: struct format_tree *);
39: static void window_copy_pageup1(struct window_mode_entry *, int);
40: static int window_copy_pagedown(struct window_mode_entry *, int, int);
41: static void window_copy_next_paragraph(struct window_mode_entry *);
42: static void window_copy_previous_paragraph(struct window_mode_entry *);
43:
44: static void window_copy_redraw_selection(struct window_mode_entry *, u_int);
45: static void window_copy_redraw_lines(struct window_mode_entry *, u_int,
46: u_int);
47: static void window_copy_redraw_screen(struct window_mode_entry *);
48: static void window_copy_write_line(struct window_mode_entry *,
1.157 nicm 49: struct screen_write_ctx *, u_int);
1.208 nicm 50: static void window_copy_write_lines(struct window_mode_entry *,
1.157 nicm 51: struct screen_write_ctx *, u_int, u_int);
52:
1.208 nicm 53: static void window_copy_scroll_to(struct window_mode_entry *, u_int, u_int);
1.157 nicm 54: static int window_copy_search_compare(struct grid *, u_int, u_int,
55: struct grid *, u_int, int);
56: static int window_copy_search_lr(struct grid *, struct grid *, u_int *,
57: u_int, u_int, u_int, int);
58: static int window_copy_search_rl(struct grid *, struct grid *, u_int *,
59: u_int, u_int, u_int, int);
1.208 nicm 60: static int window_copy_search_marks(struct window_mode_entry *,
61: struct screen *);
62: static void window_copy_clear_marks(struct window_mode_entry *);
1.157 nicm 63: static void window_copy_move_left(struct screen *, u_int *, u_int *);
64: static void window_copy_move_right(struct screen *, u_int *, u_int *);
65: static int window_copy_is_lowercase(const char *);
1.208 nicm 66: static int window_copy_search_jump(struct window_mode_entry *,
67: struct grid *, struct grid *, u_int, u_int, u_int, int, int,
68: int);
69: static int window_copy_search(struct window_mode_entry *, int);
70: static int window_copy_search_up(struct window_mode_entry *);
71: static int window_copy_search_down(struct window_mode_entry *);
72: static void window_copy_goto_line(struct window_mode_entry *, const char *);
73: static void window_copy_update_cursor(struct window_mode_entry *, u_int,
74: u_int);
75: static void window_copy_start_selection(struct window_mode_entry *);
76: static int window_copy_adjust_selection(struct window_mode_entry *,
77: u_int *, u_int *);
78: static int window_copy_set_selection(struct window_mode_entry *, int);
79: static int window_copy_update_selection(struct window_mode_entry *, int);
80: static void window_copy_synchronize_cursor(struct window_mode_entry *);
81: static void *window_copy_get_selection(struct window_mode_entry *, size_t *);
82: static void window_copy_copy_buffer(struct window_mode_entry *, void *,
83: size_t);
84: static void window_copy_copy_pipe(struct window_mode_entry *,
85: struct session *, const char *);
86: static void window_copy_copy_selection(struct window_mode_entry *);
87: static void window_copy_append_selection(struct window_mode_entry *);
88: static void window_copy_clear_selection(struct window_mode_entry *);
89: static void window_copy_copy_line(struct window_mode_entry *, char **,
90: size_t *, u_int, u_int, u_int);
91: static int window_copy_in_set(struct window_mode_entry *, u_int, u_int,
1.157 nicm 92: const char *);
1.208 nicm 93: static u_int window_copy_find_length(struct window_mode_entry *, u_int);
94: static void window_copy_cursor_start_of_line(struct window_mode_entry *);
95: static void window_copy_cursor_back_to_indentation(
96: struct window_mode_entry *);
97: static void window_copy_cursor_end_of_line(struct window_mode_entry *);
98: static void window_copy_other_end(struct window_mode_entry *);
99: static void window_copy_cursor_left(struct window_mode_entry *);
100: static void window_copy_cursor_right(struct window_mode_entry *);
101: static void window_copy_cursor_up(struct window_mode_entry *, int);
102: static void window_copy_cursor_down(struct window_mode_entry *, int);
103: static void window_copy_cursor_jump(struct window_mode_entry *);
104: static void window_copy_cursor_jump_back(struct window_mode_entry *);
105: static void window_copy_cursor_jump_to(struct window_mode_entry *);
106: static void window_copy_cursor_jump_to_back(struct window_mode_entry *);
107: static void window_copy_cursor_next_word(struct window_mode_entry *,
1.157 nicm 108: const char *);
1.208 nicm 109: static void window_copy_cursor_next_word_end(struct window_mode_entry *,
1.157 nicm 110: const char *);
1.208 nicm 111: static void window_copy_cursor_previous_word(struct window_mode_entry *,
1.157 nicm 112: const char *);
1.208 nicm 113: static void window_copy_scroll_up(struct window_mode_entry *, u_int);
114: static void window_copy_scroll_down(struct window_mode_entry *, u_int);
115: static void window_copy_rectangle_toggle(struct window_mode_entry *);
1.157 nicm 116: static void window_copy_move_mouse(struct mouse_event *);
117: static void window_copy_drag_update(struct client *, struct mouse_event *);
1.1 nicm 118:
119: const struct window_mode window_copy_mode = {
1.173 nicm 120: .name = "copy-mode",
121:
1.155 nicm 122: .init = window_copy_init,
123: .free = window_copy_free,
124: .resize = window_copy_resize,
125: .key_table = window_copy_key_table,
126: .command = window_copy_command,
1.206 nicm 127: .formats = window_copy_formats,
1.1 nicm 128: };
129:
1.210 nicm 130: const struct window_mode window_view_mode = {
131: .name = "view-mode",
132:
133: .init = window_copy_view_init,
134: .free = window_copy_free,
135: .resize = window_copy_resize,
136: .key_table = window_copy_key_table,
137: .command = window_copy_command,
138: .formats = window_copy_formats,
139: };
140:
1.155 nicm 141: enum {
1.21 nicm 142: WINDOW_COPY_OFF,
143: WINDOW_COPY_SEARCHUP,
144: WINDOW_COPY_SEARCHDOWN,
1.52 nicm 145: WINDOW_COPY_JUMPFORWARD,
1.155 nicm 146: WINDOW_COPY_JUMPBACKWARD,
1.76 nicm 147: WINDOW_COPY_JUMPTOFORWARD,
1.155 nicm 148: WINDOW_COPY_JUMPTOBACKWARD,
1.21 nicm 149: };
150:
1.161 nicm 151: enum {
152: WINDOW_COPY_REL_POS_ABOVE,
153: WINDOW_COPY_REL_POS_ON_SCREEN,
154: WINDOW_COPY_REL_POS_BELOW,
155: };
156:
1.213 ! nicm 157: enum window_copy_cmd_action {
! 158: WINDOW_COPY_CMD_NOTHING,
! 159: WINDOW_COPY_CMD_REDRAW,
! 160: WINDOW_COPY_CMD_CANCEL,
! 161: };
! 162:
! 163: struct window_copy_cmd_state {
! 164: struct window_mode_entry *wme;
! 165: struct args *args;
! 166: struct mouse_event *m;
! 167: struct client *c;
! 168: struct session *s;
! 169: };
! 170:
1.54 nicm 171: /*
1.161 nicm 172: * Copy mode's visible screen (the "screen" field) is filled from one of two
173: * sources: the original contents of the pane (used when we actually enter via
174: * the "copy-mode" command, to copy the contents of the current pane), or else
175: * a series of lines containing the output from an output-writing tmux command
176: * (such as any of the "show-*" or "list-*" commands).
1.54 nicm 177: *
1.161 nicm 178: * In either case, the full content of the copy-mode grid is pointed at by the
179: * "backing" field, and is copied into "screen" as needed (that is, when
180: * scrolling occurs). When copy-mode is backed by a pane, backing points
181: * directly at that pane's screen structure (&wp->base); when backed by a list
182: * of output-lines from a command, it points at a newly-allocated screen
183: * structure (which is deallocated when the mode ends).
1.54 nicm 184: */
1.1 nicm 185: struct window_copy_mode_data {
1.155 nicm 186: struct screen screen;
1.1 nicm 187:
1.155 nicm 188: struct screen *backing;
189: int backing_written; /* backing display started */
1.54 nicm 190:
1.192 nicm 191: u_int oy; /* number of lines scrolled up */
1.21 nicm 192:
1.192 nicm 193: u_int selx; /* beginning of selection */
1.155 nicm 194: u_int sely;
1.21 nicm 195:
1.192 nicm 196: u_int endselx; /* end of selection */
1.161 nicm 197: u_int endsely;
198:
199: enum {
200: CURSORDRAG_NONE, /* selection is independent of cursor */
201: CURSORDRAG_ENDSEL, /* end is synchronized with cursor */
202: CURSORDRAG_SEL, /* start is synchronized with cursor */
203: } cursordrag;
204:
1.192 nicm 205: int modekeys;
206: enum {
207: LINE_SEL_NONE,
208: LINE_SEL_LEFT_RIGHT,
209: LINE_SEL_RIGHT_LEFT,
210: } lineflag; /* line selection mode */
1.155 nicm 211: int rectflag; /* in rectangle copy mode? */
212: int scroll_exit; /* exit on scroll to end? */
1.1 nicm 213:
1.155 nicm 214: u_int cx;
215: u_int cy;
1.42 nicm 216:
1.192 nicm 217: u_int lastcx; /* position in last line w/ content */
218: u_int lastsx; /* size of last line w/ content */
1.1 nicm 219:
1.155 nicm 220: int searchtype;
221: char *searchstr;
1.162 nicm 222: bitstr_t *searchmark;
1.170 nicm 223: u_int searchcount;
224: int searchthis;
1.163 nicm 225: int searchx;
226: int searchy;
227: int searcho;
1.25 nicm 228:
1.155 nicm 229: int jumptype;
230: char jumpchar;
1.1 nicm 231: };
232:
1.210 nicm 233: static struct window_copy_mode_data *
234: window_copy_common_init(struct window_mode_entry *wme)
1.1 nicm 235: {
1.208 nicm 236: struct window_pane *wp = wme->wp;
1.1 nicm 237: struct window_copy_mode_data *data;
1.210 nicm 238: struct screen *base = &wp->base;
1.1 nicm 239:
1.208 nicm 240: wme->data = data = xcalloc(1, sizeof *data);
1.1 nicm 241:
1.161 nicm 242: data->cursordrag = CURSORDRAG_NONE;
1.193 nicm 243: data->lineflag = LINE_SEL_NONE;
1.42 nicm 244:
1.174 nicm 245: if (wp->searchstr != NULL) {
246: data->searchtype = WINDOW_COPY_SEARCHUP;
247: data->searchstr = xstrdup(wp->searchstr);
248: } else {
249: data->searchtype = WINDOW_COPY_OFF;
250: data->searchstr = NULL;
251: }
1.162 nicm 252: data->searchmark = NULL;
1.163 nicm 253: data->searchx = data->searchy = data->searcho = -1;
1.21 nicm 254:
1.52 nicm 255: data->jumptype = WINDOW_COPY_OFF;
256: data->jumpchar = '\0';
257:
1.210 nicm 258: screen_init(&data->screen, screen_size_x(base), screen_size_y(base), 0);
1.192 nicm 259: data->modekeys = options_get_number(wp->window->options, "mode-keys");
1.1 nicm 260:
1.210 nicm 261: return (data);
1.54 nicm 262: }
263:
1.210 nicm 264: static struct screen *
265: window_copy_init(struct window_mode_entry *wme,
266: __unused struct cmd_find_state *fs, struct args *args)
1.54 nicm 267: {
1.210 nicm 268: struct window_pane *wp = wme->wp;
269: struct window_copy_mode_data *data;
270: struct screen_write_ctx ctx;
1.54 nicm 271: u_int i;
272:
1.210 nicm 273: data = window_copy_common_init(wme);
274:
1.211 nicm 275: if (wp->fd != -1 && wp->disabled++ == 0)
1.210 nicm 276: bufferevent_disable(wp->event, EV_READ|EV_WRITE);
1.54 nicm 277:
278: data->backing = &wp->base;
279: data->cx = data->backing->cx;
280: data->cy = data->backing->cy;
281:
1.210 nicm 282: data->scroll_exit = args_has(args, 'e');
1.1 nicm 283:
1.210 nicm 284: data->screen.cx = data->cx;
285: data->screen.cy = data->cy;
286:
287: screen_write_start(&ctx, NULL, &data->screen);
288: for (i = 0; i < screen_size_y(&data->screen); i++)
1.208 nicm 289: window_copy_write_line(wme, &ctx, i);
1.212 nicm 290: screen_write_cursormove(&ctx, data->cx, data->cy, 0);
1.1 nicm 291: screen_write_stop(&ctx);
1.210 nicm 292:
293: return (&data->screen);
1.54 nicm 294: }
1.1 nicm 295:
1.210 nicm 296: static struct screen *
297: window_copy_view_init(struct window_mode_entry *wme,
298: __unused struct cmd_find_state *fs, __unused struct args *args)
1.54 nicm 299: {
1.210 nicm 300: struct window_pane *wp = wme->wp;
1.208 nicm 301: struct window_copy_mode_data *data;
1.210 nicm 302: struct screen *base = &wp->base;
303: struct screen *s;
1.54 nicm 304:
1.210 nicm 305: data = window_copy_common_init(wme);
1.208 nicm 306:
1.210 nicm 307: data->backing = s = xmalloc(sizeof *data->backing);
308: screen_init(s, screen_size_x(base), screen_size_y(base), UINT_MAX);
1.207 nicm 309:
1.210 nicm 310: return (&data->screen);
1.1 nicm 311: }
312:
1.157 nicm 313: static void
1.208 nicm 314: window_copy_free(struct window_mode_entry *wme)
1.1 nicm 315: {
1.208 nicm 316: struct window_pane *wp = wme->wp;
317: struct window_copy_mode_data *data = wme->data;
1.46 nicm 318:
1.211 nicm 319: if (wp->fd != -1 && --wp->disabled == 0)
1.61 nicm 320: bufferevent_enable(wp->event, EV_READ|EV_WRITE);
1.1 nicm 321:
1.162 nicm 322: free(data->searchmark);
1.81 nicm 323: free(data->searchstr);
1.21 nicm 324:
1.54 nicm 325: if (data->backing != &wp->base) {
326: screen_free(data->backing);
1.81 nicm 327: free(data->backing);
1.54 nicm 328: }
1.1 nicm 329: screen_free(&data->screen);
1.21 nicm 330:
1.81 nicm 331: free(data);
1.1 nicm 332: }
333:
334: void
1.54 nicm 335: window_copy_add(struct window_pane *wp, const char *fmt, ...)
336: {
337: va_list ap;
338:
339: va_start(ap, fmt);
340: window_copy_vadd(wp, fmt, ap);
341: va_end(ap);
342: }
343:
344: void
345: window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap)
346: {
1.211 nicm 347: struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
1.208 nicm 348: struct window_copy_mode_data *data = wme->data;
1.54 nicm 349: struct screen *backing = data->backing;
350: struct screen_write_ctx back_ctx, ctx;
351: struct grid_cell gc;
1.119 nicm 352: u_int old_hsize, old_cy;
1.54 nicm 353:
354: if (backing == &wp->base)
355: return;
356:
357: memcpy(&gc, &grid_default_cell, sizeof gc);
358:
359: old_hsize = screen_hsize(data->backing);
360: screen_write_start(&back_ctx, NULL, backing);
361: if (data->backing_written) {
362: /*
363: * On the second or later line, do a CRLF before writing
364: * (so it's on a new line).
365: */
366: screen_write_carriagereturn(&back_ctx);
1.175 nicm 367: screen_write_linefeed(&back_ctx, 0, 8);
1.54 nicm 368: } else
369: data->backing_written = 1;
1.119 nicm 370: old_cy = backing->cy;
1.139 nicm 371: screen_write_vnputs(&back_ctx, 0, &gc, fmt, ap);
1.54 nicm 372: screen_write_stop(&back_ctx);
373:
374: data->oy += screen_hsize(data->backing) - old_hsize;
375:
376: screen_write_start(&ctx, wp, &data->screen);
377:
378: /*
379: * If the history has changed, draw the top line.
380: * (If there's any history at all, it has changed.)
381: */
382: if (screen_hsize(data->backing))
1.208 nicm 383: window_copy_redraw_lines(wme, 0, 1);
1.54 nicm 384:
1.119 nicm 385: /* Write the new lines. */
1.208 nicm 386: window_copy_redraw_lines(wme, old_cy, backing->cy - old_cy + 1);
1.54 nicm 387:
388: screen_write_stop(&ctx);
389: }
390:
391: void
1.149 nicm 392: window_copy_pageup(struct window_pane *wp, int half_page)
1.1 nicm 393: {
1.211 nicm 394: window_copy_pageup1(TAILQ_FIRST(&wp->modes), half_page);
1.208 nicm 395: }
396:
397: static void
398: window_copy_pageup1(struct window_mode_entry *wme, int half_page)
399: {
400: struct window_copy_mode_data *data = wme->data;
1.1 nicm 401: struct screen *s = &data->screen;
1.162 nicm 402: u_int n, ox, oy, px, py;
1.147 nicm 403:
404: oy = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 405: ox = window_copy_find_length(wme, oy);
1.147 nicm 406:
407: if (data->cx != ox) {
408: data->lastcx = data->cx;
409: data->lastsx = ox;
410: }
411: data->cx = data->lastcx;
1.1 nicm 412:
1.19 nicm 413: n = 1;
1.149 nicm 414: if (screen_size_y(s) > 2) {
415: if (half_page)
416: n = screen_size_y(s) / 2;
417: else
418: n = screen_size_y(s) - 2;
419: }
1.147 nicm 420:
1.195 nicm 421: if (data->oy + n > screen_hsize(data->backing)) {
1.54 nicm 422: data->oy = screen_hsize(data->backing);
1.195 nicm 423: if (data->cy < n)
424: data->cy = 0;
425: else
426: data->cy -= n;
427: } else
1.19 nicm 428: data->oy += n;
1.147 nicm 429:
1.192 nicm 430: if (data->screen.sel == NULL || !data->rectflag) {
1.162 nicm 431: py = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 432: px = window_copy_find_length(wme, py);
1.162 nicm 433: if ((data->cx >= data->lastsx && data->cx != px) ||
434: data->cx > px)
1.208 nicm 435: window_copy_cursor_end_of_line(wme);
1.147 nicm 436: }
437:
1.208 nicm 438: window_copy_update_selection(wme, 1);
439: window_copy_redraw_screen(wme);
1.147 nicm 440: }
441:
1.166 nicm 442: static int
1.208 nicm 443: window_copy_pagedown(struct window_mode_entry *wme, int half_page,
444: int scroll_exit)
1.147 nicm 445: {
1.208 nicm 446: struct window_copy_mode_data *data = wme->data;
1.147 nicm 447: struct screen *s = &data->screen;
1.161 nicm 448: u_int n, ox, oy, px, py;
1.147 nicm 449:
450: oy = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 451: ox = window_copy_find_length(wme, oy);
1.147 nicm 452:
453: if (data->cx != ox) {
454: data->lastcx = data->cx;
455: data->lastsx = ox;
456: }
457: data->cx = data->lastcx;
458:
459: n = 1;
1.149 nicm 460: if (screen_size_y(s) > 2) {
461: if (half_page)
462: n = screen_size_y(s) / 2;
463: else
464: n = screen_size_y(s) - 2;
465: }
1.147 nicm 466:
1.195 nicm 467: if (data->oy < n) {
1.147 nicm 468: data->oy = 0;
1.195 nicm 469: if (data->cy + (n - data->oy) >= screen_size_y(data->backing))
470: data->cy = screen_size_y(data->backing) - 1;
471: else
472: data->cy += n - data->oy;
473: } else
1.147 nicm 474: data->oy -= n;
475:
1.192 nicm 476: if (data->screen.sel == NULL || !data->rectflag) {
1.161 nicm 477: py = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 478: px = window_copy_find_length(wme, py);
1.161 nicm 479: if ((data->cx >= data->lastsx && data->cx != px) ||
480: data->cx > px)
1.208 nicm 481: window_copy_cursor_end_of_line(wme);
1.147 nicm 482: }
483:
1.186 nicm 484: if (scroll_exit && data->oy == 0)
1.166 nicm 485: return (1);
1.208 nicm 486: window_copy_update_selection(wme, 1);
487: window_copy_redraw_screen(wme);
1.166 nicm 488: return (0);
1.1 nicm 489: }
490:
1.157 nicm 491: static void
1.208 nicm 492: window_copy_previous_paragraph(struct window_mode_entry *wme)
1.148 nicm 493: {
1.208 nicm 494: struct window_copy_mode_data *data = wme->data;
1.151 nicm 495: u_int oy;
1.148 nicm 496:
497: oy = screen_hsize(data->backing) + data->cy - data->oy;
498:
1.208 nicm 499: while (oy > 0 && window_copy_find_length(wme, oy) == 0)
1.148 nicm 500: oy--;
501:
1.208 nicm 502: while (oy > 0 && window_copy_find_length(wme, oy) > 0)
1.148 nicm 503: oy--;
504:
1.208 nicm 505: window_copy_scroll_to(wme, 0, oy);
1.148 nicm 506: }
507:
1.157 nicm 508: static void
1.208 nicm 509: window_copy_next_paragraph(struct window_mode_entry *wme)
1.148 nicm 510: {
1.208 nicm 511: struct window_copy_mode_data *data = wme->data;
1.148 nicm 512: struct screen *s = &data->screen;
513: u_int maxy, ox, oy;
514:
515: oy = screen_hsize(data->backing) + data->cy - data->oy;
516: maxy = screen_hsize(data->backing) + screen_size_y(s) - 1;
517:
1.208 nicm 518: while (oy < maxy && window_copy_find_length(wme, oy) == 0)
1.148 nicm 519: oy++;
520:
1.208 nicm 521: while (oy < maxy && window_copy_find_length(wme, oy) > 0)
1.148 nicm 522: oy++;
523:
1.208 nicm 524: ox = window_copy_find_length(wme, oy);
525: window_copy_scroll_to(wme, ox, oy);
1.148 nicm 526: }
527:
1.157 nicm 528: static void
1.208 nicm 529: window_copy_formats(struct window_mode_entry *wme, struct format_tree *ft)
1.206 nicm 530: {
1.208 nicm 531: struct window_copy_mode_data *data = wme->data;
1.206 nicm 532:
533: format_add(ft, "selection_present", "%d", data->screen.sel != NULL);
534: format_add(ft, "scroll_position", "%d", data->oy);
535: format_add(ft, "rectangle_toggle", "%d", data->rectflag);
536: }
537:
538: static void
1.208 nicm 539: window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
1.1 nicm 540: {
1.208 nicm 541: struct window_pane *wp = wme->wp;
542: struct window_copy_mode_data *data = wme->data;
1.1 nicm 543: struct screen *s = &data->screen;
544: struct screen_write_ctx ctx;
545:
1.119 nicm 546: screen_resize(s, sx, sy, 1);
1.54 nicm 547: if (data->backing != &wp->base)
1.119 nicm 548: screen_resize(data->backing, sx, sy, 1);
1.35 nicm 549:
1.18 nicm 550: if (data->cy > sy - 1)
551: data->cy = sy - 1;
552: if (data->cx > sx)
553: data->cx = sx;
1.63 nicm 554: if (data->oy > screen_hsize(data->backing))
555: data->oy = screen_hsize(data->backing);
1.18 nicm 556:
1.208 nicm 557: window_copy_clear_selection(wme);
1.18 nicm 558:
1.1 nicm 559: screen_write_start(&ctx, NULL, s);
1.208 nicm 560: window_copy_write_lines(wme, &ctx, 0, screen_size_y(s) - 1);
1.1 nicm 561: screen_write_stop(&ctx);
1.18 nicm 562:
1.162 nicm 563: if (data->searchmark != NULL)
1.208 nicm 564: window_copy_search_marks(wme, NULL);
1.163 nicm 565: data->searchx = data->cx;
566: data->searchy = data->cy;
567: data->searcho = data->oy;
1.162 nicm 568:
1.208 nicm 569: window_copy_redraw_screen(wme);
1.1 nicm 570: }
571:
1.157 nicm 572: static const char *
1.208 nicm 573: window_copy_key_table(struct window_mode_entry *wme)
1.155 nicm 574: {
1.208 nicm 575: struct window_pane *wp = wme->wp;
576:
1.155 nicm 577: if (options_get_number(wp->window->options, "mode-keys") == MODEKEY_VI)
578: return ("copy-mode-vi");
579: return ("copy-mode");
580: }
581:
1.213 ! nicm 582: static enum window_copy_cmd_action
! 583: window_copy_cmd_append_selection(struct window_copy_cmd_state *cs)
! 584: {
! 585: struct window_mode_entry *wme = cs->wme;
! 586: struct session *s = cs->s;
! 587:
! 588: if (s != NULL)
! 589: window_copy_append_selection(wme);
! 590: window_copy_clear_selection(wme);
! 591: return (WINDOW_COPY_CMD_REDRAW);
! 592: }
! 593:
! 594: static enum window_copy_cmd_action
! 595: window_copy_cmd_append_selection_and_cancel(struct window_copy_cmd_state *cs)
! 596: {
! 597: struct window_mode_entry *wme = cs->wme;
! 598: struct session *s = cs->s;
! 599:
! 600: if (s != NULL)
! 601: window_copy_append_selection(wme);
! 602: window_copy_clear_selection(wme);
! 603: return (WINDOW_COPY_CMD_CANCEL);
! 604: }
! 605:
! 606: static enum window_copy_cmd_action
! 607: window_copy_cmd_back_to_indentation(struct window_copy_cmd_state *cs)
! 608: {
! 609: struct window_mode_entry *wme = cs->wme;
! 610:
! 611: window_copy_cursor_back_to_indentation(wme);
! 612: return (WINDOW_COPY_CMD_NOTHING);
! 613: }
! 614:
! 615: static enum window_copy_cmd_action
! 616: window_copy_cmd_begin_selection(struct window_copy_cmd_state *cs)
! 617: {
! 618: struct window_mode_entry *wme = cs->wme;
! 619: struct client *c = cs->c;
! 620: struct mouse_event *m = cs->m;
! 621: struct window_copy_mode_data *data = wme->data;
! 622:
! 623: if (m != NULL) {
! 624: window_copy_start_drag(c, m);
! 625: return (WINDOW_COPY_CMD_NOTHING);
! 626: }
! 627:
! 628: data->lineflag = LINE_SEL_NONE;
! 629: window_copy_start_selection(wme);
! 630: return (WINDOW_COPY_CMD_REDRAW);
! 631: }
! 632:
! 633: static enum window_copy_cmd_action
! 634: window_copy_cmd_stop_selection(struct window_copy_cmd_state *cs)
! 635: {
! 636: struct window_mode_entry *wme = cs->wme;
! 637: struct window_copy_mode_data *data = wme->data;
! 638:
! 639: data->cursordrag = CURSORDRAG_NONE;
! 640: return (WINDOW_COPY_CMD_NOTHING);
! 641: }
! 642:
! 643: static enum window_copy_cmd_action
! 644: window_copy_cmd_bottom_line(struct window_copy_cmd_state *cs)
! 645: {
! 646: struct window_mode_entry *wme = cs->wme;
! 647: struct window_copy_mode_data *data = wme->data;
! 648:
! 649: data->cx = 0;
! 650: data->cy = screen_size_y(&data->screen) - 1;
! 651:
! 652: window_copy_update_selection(wme, 1);
! 653: return (WINDOW_COPY_CMD_REDRAW);
! 654: }
! 655:
! 656: static enum window_copy_cmd_action
! 657: window_copy_cmd_cancel(__unused struct window_copy_cmd_state *cs)
! 658: {
! 659: return (WINDOW_COPY_CMD_CANCEL);
! 660: }
! 661:
! 662: static enum window_copy_cmd_action
! 663: window_copy_cmd_clear_selection(struct window_copy_cmd_state *cs)
! 664: {
! 665: struct window_mode_entry *wme = cs->wme;
! 666:
! 667: window_copy_clear_selection(wme);
! 668: return (WINDOW_COPY_CMD_REDRAW);
! 669: }
! 670:
! 671: static enum window_copy_cmd_action
! 672: window_copy_cmd_copy_end_of_line(struct window_copy_cmd_state *cs)
! 673: {
! 674: struct window_mode_entry *wme = cs->wme;
! 675: struct session *s = cs->s;
! 676: u_int np = wme->prefix;
! 677:
! 678: window_copy_start_selection(wme);
! 679: for (; np > 1; np--)
! 680: window_copy_cursor_down(wme, 0);
! 681: window_copy_cursor_end_of_line(wme);
! 682:
! 683: if (s != NULL) {
! 684: window_copy_copy_selection(wme);
! 685: return (WINDOW_COPY_CMD_CANCEL);
! 686: }
! 687: return (WINDOW_COPY_CMD_REDRAW);
! 688: }
! 689:
! 690: static enum window_copy_cmd_action
! 691: window_copy_cmd_copy_line(struct window_copy_cmd_state *cs)
! 692: {
! 693: struct window_mode_entry *wme = cs->wme;
! 694: struct session *s = cs->s;
! 695: u_int np = wme->prefix;
! 696:
! 697: window_copy_cursor_start_of_line(wme);
! 698: window_copy_start_selection(wme);
! 699: for (; np > 1; np--)
! 700: window_copy_cursor_down(wme, 0);
! 701: window_copy_cursor_end_of_line(wme);
! 702:
! 703: if (s != NULL) {
! 704: window_copy_copy_selection(wme);
! 705: return (WINDOW_COPY_CMD_CANCEL);
! 706: }
! 707: return (WINDOW_COPY_CMD_REDRAW);
! 708: }
! 709:
! 710: static enum window_copy_cmd_action
! 711: window_copy_cmd_copy_selection(struct window_copy_cmd_state *cs)
! 712: {
! 713: struct window_mode_entry *wme = cs->wme;
! 714: struct session *s = cs->s;
! 715:
! 716: if (s != NULL)
! 717: window_copy_copy_selection(wme);
! 718: window_copy_clear_selection(wme);
! 719: return (WINDOW_COPY_CMD_REDRAW);
! 720: }
! 721:
! 722: static enum window_copy_cmd_action
! 723: window_copy_cmd_copy_selection_and_cancel(struct window_copy_cmd_state *cs)
! 724: {
! 725: struct window_mode_entry *wme = cs->wme;
! 726: struct session *s = cs->s;
! 727:
! 728: if (s != NULL)
! 729: window_copy_copy_selection(wme);
! 730: window_copy_clear_selection(wme);
! 731: return (WINDOW_COPY_CMD_CANCEL);
! 732: }
! 733:
! 734: static enum window_copy_cmd_action
! 735: window_copy_cmd_cursor_down(struct window_copy_cmd_state *cs)
! 736: {
! 737: struct window_mode_entry *wme = cs->wme;
! 738: u_int np = wme->prefix;
! 739:
! 740: for (; np != 0; np--)
! 741: window_copy_cursor_down(wme, 0);
! 742: return (WINDOW_COPY_CMD_NOTHING);
! 743: }
! 744:
! 745: static enum window_copy_cmd_action
! 746: window_copy_cmd_cursor_left(struct window_copy_cmd_state *cs)
! 747: {
! 748: struct window_mode_entry *wme = cs->wme;
! 749: u_int np = wme->prefix;
! 750:
! 751: for (; np != 0; np--)
! 752: window_copy_cursor_left(wme);
! 753: return (WINDOW_COPY_CMD_NOTHING);
! 754: }
! 755:
! 756: static enum window_copy_cmd_action
! 757: window_copy_cmd_cursor_right(struct window_copy_cmd_state *cs)
! 758: {
! 759: struct window_mode_entry *wme = cs->wme;
! 760: u_int np = wme->prefix;
! 761:
! 762: for (; np != 0; np--)
! 763: window_copy_cursor_right(wme);
! 764: return (WINDOW_COPY_CMD_NOTHING);
! 765: }
! 766:
! 767: static enum window_copy_cmd_action
! 768: window_copy_cmd_cursor_up(struct window_copy_cmd_state *cs)
! 769: {
! 770: struct window_mode_entry *wme = cs->wme;
! 771: u_int np = wme->prefix;
! 772:
! 773: for (; np != 0; np--)
! 774: window_copy_cursor_up(wme, 0);
! 775: return (WINDOW_COPY_CMD_NOTHING);
! 776: }
! 777:
! 778: static enum window_copy_cmd_action
! 779: window_copy_cmd_end_of_line(struct window_copy_cmd_state *cs)
! 780: {
! 781: struct window_mode_entry *wme = cs->wme;
! 782:
! 783: window_copy_cursor_end_of_line(wme);
! 784: return (WINDOW_COPY_CMD_NOTHING);
! 785: }
! 786:
! 787: static enum window_copy_cmd_action
! 788: window_copy_cmd_halfpage_down(struct window_copy_cmd_state *cs)
! 789: {
! 790: struct window_mode_entry *wme = cs->wme;
! 791: struct window_copy_mode_data *data = wme->data;
! 792: u_int np = wme->prefix;
! 793:
! 794: for (; np != 0; np--) {
! 795: if (window_copy_pagedown(wme, 1, data->scroll_exit))
! 796: return (WINDOW_COPY_CMD_CANCEL);
! 797: }
! 798: return (WINDOW_COPY_CMD_NOTHING);
! 799: }
! 800:
! 801: static enum window_copy_cmd_action
! 802: window_copy_cmd_halfpage_down_and_cancel(struct window_copy_cmd_state *cs)
! 803: {
! 804:
! 805: struct window_mode_entry *wme = cs->wme;
! 806: u_int np = wme->prefix;
! 807:
! 808: for (; np != 0; np--) {
! 809: if (window_copy_pagedown(wme, 1, 1))
! 810: return (WINDOW_COPY_CMD_CANCEL);
! 811: }
! 812: return (WINDOW_COPY_CMD_NOTHING);
! 813: }
! 814:
! 815: static enum window_copy_cmd_action
! 816: window_copy_cmd_halfpage_up(struct window_copy_cmd_state *cs)
! 817: {
! 818: struct window_mode_entry *wme = cs->wme;
! 819: u_int np = wme->prefix;
! 820:
! 821: for (; np != 0; np--)
! 822: window_copy_pageup1(wme, 1);
! 823: return (WINDOW_COPY_CMD_NOTHING);
! 824: }
! 825:
! 826: static enum window_copy_cmd_action
! 827: window_copy_cmd_history_bottom(struct window_copy_cmd_state *cs)
! 828: {
! 829: struct window_mode_entry *wme = cs->wme;
! 830: struct window_copy_mode_data *data = wme->data;
! 831:
! 832: data->cx = 0;
! 833: data->cy = screen_size_y(&data->screen) - 1;
! 834: data->oy = 0;
! 835:
! 836: window_copy_update_selection(wme, 1);
! 837: return (WINDOW_COPY_CMD_REDRAW);
! 838: }
! 839:
! 840: static enum window_copy_cmd_action
! 841: window_copy_cmd_history_top(struct window_copy_cmd_state *cs)
! 842: {
! 843: struct window_mode_entry *wme = cs->wme;
! 844: struct window_copy_mode_data *data = wme->data;
! 845:
! 846: data->cx = 0;
! 847: data->cy = 0;
! 848: data->oy = screen_hsize(data->backing);
! 849:
! 850: window_copy_update_selection(wme, 1);
! 851: return (WINDOW_COPY_CMD_REDRAW);
! 852: }
! 853:
! 854: static enum window_copy_cmd_action
! 855: window_copy_cmd_jump_again(struct window_copy_cmd_state *cs)
! 856: {
! 857: struct window_mode_entry *wme = cs->wme;
! 858: struct window_copy_mode_data *data = wme->data;
! 859: u_int np = wme->prefix;
! 860:
! 861: switch (data->jumptype) {
! 862: case WINDOW_COPY_JUMPFORWARD:
! 863: for (; np != 0; np--)
! 864: window_copy_cursor_jump(wme);
! 865: break;
! 866: case WINDOW_COPY_JUMPBACKWARD:
! 867: for (; np != 0; np--)
! 868: window_copy_cursor_jump_back(wme);
! 869: break;
! 870: case WINDOW_COPY_JUMPTOFORWARD:
! 871: for (; np != 0; np--)
! 872: window_copy_cursor_jump_to(wme);
! 873: break;
! 874: case WINDOW_COPY_JUMPTOBACKWARD:
! 875: for (; np != 0; np--)
! 876: window_copy_cursor_jump_to_back(wme);
! 877: break;
! 878: }
! 879: return (WINDOW_COPY_CMD_NOTHING);
! 880: }
! 881:
! 882: static enum window_copy_cmd_action
! 883: window_copy_cmd_jump_reverse(struct window_copy_cmd_state *cs)
! 884: {
! 885: struct window_mode_entry *wme = cs->wme;
! 886: struct window_copy_mode_data *data = wme->data;
! 887: u_int np = wme->prefix;
! 888:
! 889: switch (data->jumptype) {
! 890: case WINDOW_COPY_JUMPFORWARD:
! 891: for (; np != 0; np--)
! 892: window_copy_cursor_jump_back(wme);
! 893: break;
! 894: case WINDOW_COPY_JUMPBACKWARD:
! 895: for (; np != 0; np--)
! 896: window_copy_cursor_jump(wme);
! 897: break;
! 898: case WINDOW_COPY_JUMPTOFORWARD:
! 899: for (; np != 0; np--)
! 900: window_copy_cursor_jump_to_back(wme);
! 901: break;
! 902: case WINDOW_COPY_JUMPTOBACKWARD:
! 903: for (; np != 0; np--)
! 904: window_copy_cursor_jump_to(wme);
! 905: break;
! 906: }
! 907: return (WINDOW_COPY_CMD_NOTHING);
! 908: }
! 909:
! 910: static enum window_copy_cmd_action
! 911: window_copy_cmd_middle_line(struct window_copy_cmd_state *cs)
! 912: {
! 913: struct window_mode_entry *wme = cs->wme;
! 914: struct window_copy_mode_data *data = wme->data;
! 915:
! 916: data->cx = 0;
! 917: data->cy = (screen_size_y(&data->screen) - 1) / 2;
! 918:
! 919: window_copy_update_selection(wme, 1);
! 920: return (WINDOW_COPY_CMD_REDRAW);
! 921: }
! 922:
! 923: static enum window_copy_cmd_action
! 924: window_copy_cmd_next_paragraph(struct window_copy_cmd_state *cs)
! 925: {
! 926: struct window_mode_entry *wme = cs->wme;
! 927: u_int np = wme->prefix;
! 928:
! 929: for (; np != 0; np--)
! 930: window_copy_next_paragraph(wme);
! 931: return (WINDOW_COPY_CMD_NOTHING);
! 932: }
! 933:
! 934: static enum window_copy_cmd_action
! 935: window_copy_cmd_next_space(struct window_copy_cmd_state *cs)
! 936: {
! 937: struct window_mode_entry *wme = cs->wme;
! 938: u_int np = wme->prefix;
! 939:
! 940: for (; np != 0; np--)
! 941: window_copy_cursor_next_word(wme, " ");
! 942: return (WINDOW_COPY_CMD_NOTHING);
! 943: }
! 944:
! 945: static enum window_copy_cmd_action
! 946: window_copy_cmd_next_space_end(struct window_copy_cmd_state *cs)
! 947: {
! 948: struct window_mode_entry *wme = cs->wme;
! 949: u_int np = wme->prefix;
! 950:
! 951: for (; np != 0; np--)
! 952: window_copy_cursor_next_word_end(wme, " ");
! 953: return (WINDOW_COPY_CMD_NOTHING);
! 954: }
! 955:
! 956: static enum window_copy_cmd_action
! 957: window_copy_cmd_next_word(struct window_copy_cmd_state *cs)
! 958: {
! 959: struct window_mode_entry *wme = cs->wme;
! 960: struct session *s = cs->s;
! 961: u_int np = wme->prefix;
! 962: const char *ws;
! 963:
! 964: ws = options_get_string(s->options, "word-separators");
! 965: for (; np != 0; np--)
! 966: window_copy_cursor_next_word(wme, ws);
! 967: return (WINDOW_COPY_CMD_NOTHING);
! 968: }
! 969:
! 970: static enum window_copy_cmd_action
! 971: window_copy_cmd_next_word_end(struct window_copy_cmd_state *cs)
! 972: {
! 973: struct window_mode_entry *wme = cs->wme;
! 974: struct session *s = cs->s;
! 975: u_int np = wme->prefix;
! 976: const char *ws;
! 977:
! 978: ws = options_get_string(s->options, "word-separators");
! 979: for (; np != 0; np--)
! 980: window_copy_cursor_next_word_end(wme, ws);
! 981: return (WINDOW_COPY_CMD_NOTHING);
! 982: }
! 983:
! 984: static enum window_copy_cmd_action
! 985: window_copy_cmd_other_end(struct window_copy_cmd_state *cs)
! 986: {
! 987: struct window_mode_entry *wme = cs->wme;
! 988: u_int np = wme->prefix;
! 989:
! 990: if ((np % 2) != 0)
! 991: window_copy_other_end(wme);
! 992: return (WINDOW_COPY_CMD_NOTHING);
! 993: }
! 994:
! 995: static enum window_copy_cmd_action
! 996: window_copy_cmd_page_down(struct window_copy_cmd_state *cs)
! 997: {
! 998: struct window_mode_entry *wme = cs->wme;
! 999: struct window_copy_mode_data *data = wme->data;
! 1000: u_int np = wme->prefix;
! 1001:
! 1002: for (; np != 0; np--) {
! 1003: if (window_copy_pagedown(wme, 0, data->scroll_exit))
! 1004: return (WINDOW_COPY_CMD_CANCEL);
! 1005: }
! 1006: return (WINDOW_COPY_CMD_NOTHING);
! 1007: }
! 1008:
! 1009: static enum window_copy_cmd_action
! 1010: window_copy_cmd_page_down_and_cancel(struct window_copy_cmd_state *cs)
! 1011: {
! 1012: struct window_mode_entry *wme = cs->wme;
! 1013: u_int np = wme->prefix;
! 1014:
! 1015: for (; np != 0; np--) {
! 1016: if (window_copy_pagedown(wme, 0, 1))
! 1017: return (WINDOW_COPY_CMD_CANCEL);
! 1018: }
! 1019: return (WINDOW_COPY_CMD_NOTHING);
! 1020: }
! 1021:
! 1022: static enum window_copy_cmd_action
! 1023: window_copy_cmd_page_up(struct window_copy_cmd_state *cs)
! 1024: {
! 1025: struct window_mode_entry *wme = cs->wme;
! 1026: u_int np = wme->prefix;
! 1027:
! 1028: for (; np != 0; np--)
! 1029: window_copy_pageup1(wme, 0);
! 1030: return (WINDOW_COPY_CMD_NOTHING);
! 1031: }
! 1032:
! 1033: static enum window_copy_cmd_action
! 1034: window_copy_cmd_previous_paragraph(struct window_copy_cmd_state *cs)
! 1035: {
! 1036: struct window_mode_entry *wme = cs->wme;
! 1037: u_int np = wme->prefix;
! 1038:
! 1039: for (; np != 0; np--)
! 1040: window_copy_previous_paragraph(wme);
! 1041: return (WINDOW_COPY_CMD_NOTHING);
! 1042: }
! 1043:
! 1044: static enum window_copy_cmd_action
! 1045: window_copy_cmd_previous_space(struct window_copy_cmd_state *cs)
! 1046: {
! 1047: struct window_mode_entry *wme = cs->wme;
! 1048: u_int np = wme->prefix;
! 1049:
! 1050: for (; np != 0; np--)
! 1051: window_copy_cursor_previous_word(wme, " ");
! 1052: return (WINDOW_COPY_CMD_NOTHING);
! 1053: }
! 1054:
! 1055: static enum window_copy_cmd_action
! 1056: window_copy_cmd_previous_word(struct window_copy_cmd_state *cs)
! 1057: {
! 1058: struct window_mode_entry *wme = cs->wme;
! 1059: struct session *s = cs->s;
! 1060: u_int np = wme->prefix;
! 1061: const char *ws;
! 1062:
! 1063: ws = options_get_string(s->options, "word-separators");
! 1064: for (; np != 0; np--)
! 1065: window_copy_cursor_previous_word(wme, ws);
! 1066: return (WINDOW_COPY_CMD_NOTHING);
! 1067: }
! 1068:
! 1069: static enum window_copy_cmd_action
! 1070: window_copy_cmd_rectangle_toggle(struct window_copy_cmd_state *cs)
! 1071: {
! 1072: struct window_mode_entry *wme = cs->wme;
! 1073: struct window_copy_mode_data *data = wme->data;
! 1074:
! 1075: data->lineflag = LINE_SEL_NONE;
! 1076: window_copy_rectangle_toggle(wme);
! 1077:
! 1078: return (WINDOW_COPY_CMD_NOTHING);
! 1079: }
! 1080:
! 1081: static enum window_copy_cmd_action
! 1082: window_copy_cmd_scroll_down(struct window_copy_cmd_state *cs)
! 1083: {
! 1084: struct window_mode_entry *wme = cs->wme;
! 1085: struct window_copy_mode_data *data = wme->data;
! 1086: u_int np = wme->prefix;
! 1087:
! 1088: for (; np != 0; np--)
! 1089: window_copy_cursor_down(wme, 1);
! 1090: if (data->scroll_exit && data->oy == 0)
! 1091: return (WINDOW_COPY_CMD_CANCEL);
! 1092: return (WINDOW_COPY_CMD_NOTHING);
! 1093: }
! 1094:
! 1095: static enum window_copy_cmd_action
! 1096: window_copy_cmd_scroll_down_and_cancel(struct window_copy_cmd_state *cs)
! 1097: {
! 1098: struct window_mode_entry *wme = cs->wme;
! 1099: struct window_copy_mode_data *data = wme->data;
! 1100: u_int np = wme->prefix;
! 1101:
! 1102: for (; np != 0; np--)
! 1103: window_copy_cursor_down(wme, 1);
! 1104: if (data->oy == 0)
! 1105: return (WINDOW_COPY_CMD_CANCEL);
! 1106: return (WINDOW_COPY_CMD_NOTHING);
! 1107: }
! 1108:
! 1109: static enum window_copy_cmd_action
! 1110: window_copy_cmd_scroll_up(struct window_copy_cmd_state *cs)
! 1111: {
! 1112: struct window_mode_entry *wme = cs->wme;
! 1113: u_int np = wme->prefix;
! 1114:
! 1115: for (; np != 0; np--)
! 1116: window_copy_cursor_up(wme, 1);
! 1117: return (WINDOW_COPY_CMD_NOTHING);
! 1118: }
! 1119:
! 1120: static enum window_copy_cmd_action
! 1121: window_copy_cmd_search_again(struct window_copy_cmd_state *cs)
! 1122: {
! 1123: struct window_mode_entry *wme = cs->wme;
! 1124: struct window_copy_mode_data *data = wme->data;
! 1125: u_int np = wme->prefix;
! 1126:
! 1127: if (data->searchtype == WINDOW_COPY_SEARCHUP) {
! 1128: for (; np != 0; np--)
! 1129: window_copy_search_up(wme);
! 1130: } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
! 1131: for (; np != 0; np--)
! 1132: window_copy_search_down(wme);
! 1133: }
! 1134: return (WINDOW_COPY_CMD_NOTHING);
! 1135: }
! 1136:
! 1137: static enum window_copy_cmd_action
! 1138: window_copy_cmd_search_reverse(struct window_copy_cmd_state *cs)
! 1139: {
! 1140: struct window_mode_entry *wme = cs->wme;
! 1141: struct window_copy_mode_data *data = wme->data;
! 1142: u_int np = wme->prefix;
! 1143:
! 1144: if (data->searchtype == WINDOW_COPY_SEARCHUP) {
! 1145: for (; np != 0; np--)
! 1146: window_copy_search_down(wme);
! 1147: } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
! 1148: for (; np != 0; np--)
! 1149: window_copy_search_up(wme);
! 1150: }
! 1151: return (WINDOW_COPY_CMD_NOTHING);
! 1152: }
! 1153:
! 1154: static enum window_copy_cmd_action
! 1155: window_copy_cmd_select_line(struct window_copy_cmd_state *cs)
! 1156: {
! 1157: struct window_mode_entry *wme = cs->wme;
! 1158: struct window_copy_mode_data *data = wme->data;
! 1159: u_int np = wme->prefix;
! 1160:
! 1161: data->lineflag = LINE_SEL_LEFT_RIGHT;
! 1162: data->rectflag = 0;
! 1163:
! 1164: window_copy_cursor_start_of_line(wme);
! 1165: window_copy_start_selection(wme);
! 1166: for (; np > 1; np--)
! 1167: window_copy_cursor_down(wme, 0);
! 1168: window_copy_cursor_end_of_line(wme);
! 1169:
! 1170: return (WINDOW_COPY_CMD_REDRAW);
! 1171: }
! 1172:
! 1173: static enum window_copy_cmd_action
! 1174: window_copy_cmd_select_word(struct window_copy_cmd_state *cs)
! 1175: {
! 1176: struct window_mode_entry *wme = cs->wme;
! 1177: struct session *s = cs->s;
! 1178: struct window_copy_mode_data *data = wme->data;
! 1179: const char *ws;
! 1180:
! 1181: data->lineflag = LINE_SEL_LEFT_RIGHT;
! 1182: data->rectflag = 0;
! 1183:
! 1184: ws = options_get_string(s->options, "word-separators");
! 1185: window_copy_cursor_previous_word(wme, ws);
! 1186: window_copy_start_selection(wme);
! 1187: window_copy_cursor_next_word_end(wme, ws);
! 1188:
! 1189: return (WINDOW_COPY_CMD_REDRAW);
! 1190: }
! 1191:
! 1192: static enum window_copy_cmd_action
! 1193: window_copy_cmd_start_of_line(struct window_copy_cmd_state *cs)
! 1194: {
! 1195: struct window_mode_entry *wme = cs->wme;
! 1196:
! 1197: window_copy_cursor_start_of_line(wme);
! 1198: return (WINDOW_COPY_CMD_NOTHING);
! 1199: }
! 1200:
! 1201: static enum window_copy_cmd_action
! 1202: window_copy_cmd_top_line(struct window_copy_cmd_state *cs)
! 1203: {
! 1204: struct window_mode_entry *wme = cs->wme;
! 1205: struct window_copy_mode_data *data = wme->data;
! 1206:
! 1207: data->cx = 0;
! 1208: data->cy = 0;
! 1209:
! 1210: window_copy_update_selection(wme, 1);
! 1211: return (WINDOW_COPY_CMD_REDRAW);
! 1212: }
! 1213:
! 1214: static enum window_copy_cmd_action
! 1215: window_copy_cmd_copy_pipe(struct window_copy_cmd_state *cs)
! 1216: {
! 1217: struct window_mode_entry *wme = cs->wme;
! 1218: struct session *s = cs->s;
! 1219: const char *argument = cs->args->argv[1];
! 1220:
! 1221: if (s != NULL && *argument != '\0')
! 1222: window_copy_copy_pipe(wme, s, argument);
! 1223: return (WINDOW_COPY_CMD_NOTHING);
! 1224: }
! 1225:
! 1226: static enum window_copy_cmd_action
! 1227: window_copy_cmd_copy_pipe_and_cancel(struct window_copy_cmd_state *cs)
! 1228: {
! 1229: struct window_mode_entry *wme = cs->wme;
! 1230: struct session *s = cs->s;
! 1231: const char *argument = cs->args->argv[1];
! 1232:
! 1233: if (s != NULL && *argument != '\0') {
! 1234: window_copy_copy_pipe(wme, s, argument);
! 1235: return (WINDOW_COPY_CMD_CANCEL);
! 1236: }
! 1237: return (WINDOW_COPY_CMD_NOTHING);
! 1238: }
! 1239:
! 1240: static enum window_copy_cmd_action
! 1241: window_copy_cmd_goto_line(struct window_copy_cmd_state *cs)
! 1242: {
! 1243: struct window_mode_entry *wme = cs->wme;
! 1244: const char *argument = cs->args->argv[1];
! 1245:
! 1246: if (*argument != '\0')
! 1247: window_copy_goto_line(wme, argument);
! 1248: return (WINDOW_COPY_CMD_NOTHING);
! 1249: }
! 1250:
! 1251: static enum window_copy_cmd_action
! 1252: window_copy_cmd_jump_backward(struct window_copy_cmd_state *cs)
! 1253: {
! 1254: struct window_mode_entry *wme = cs->wme;
! 1255: struct window_copy_mode_data *data = wme->data;
! 1256: u_int np = wme->prefix;
! 1257: const char *argument = cs->args->argv[1];
! 1258:
! 1259: if (*argument != '\0') {
! 1260: data->jumptype = WINDOW_COPY_JUMPBACKWARD;
! 1261: data->jumpchar = *argument;
! 1262: for (; np != 0; np--)
! 1263: window_copy_cursor_jump_back(wme);
! 1264: }
! 1265: return (WINDOW_COPY_CMD_NOTHING);
! 1266: }
! 1267:
! 1268: static enum window_copy_cmd_action
! 1269: window_copy_cmd_jump_forward(struct window_copy_cmd_state *cs)
! 1270: {
! 1271: struct window_mode_entry *wme = cs->wme;
! 1272: struct window_copy_mode_data *data = wme->data;
! 1273: u_int np = wme->prefix;
! 1274: const char *argument = cs->args->argv[1];
! 1275:
! 1276: if (*argument != '\0') {
! 1277: data->jumptype = WINDOW_COPY_JUMPFORWARD;
! 1278: data->jumpchar = *argument;
! 1279: for (; np != 0; np--)
! 1280: window_copy_cursor_jump(wme);
! 1281: }
! 1282: return (WINDOW_COPY_CMD_NOTHING);
! 1283: }
! 1284:
! 1285: static enum window_copy_cmd_action
! 1286: window_copy_cmd_jump_to_backward(struct window_copy_cmd_state *cs)
! 1287: {
! 1288: struct window_mode_entry *wme = cs->wme;
! 1289: struct window_copy_mode_data *data = wme->data;
! 1290: u_int np = wme->prefix;
! 1291: const char *argument = cs->args->argv[1];
! 1292:
! 1293: if (*argument != '\0') {
! 1294: data->jumptype = WINDOW_COPY_JUMPTOBACKWARD;
! 1295: data->jumpchar = *argument;
! 1296: for (; np != 0; np--)
! 1297: window_copy_cursor_jump_to_back(wme);
! 1298: }
! 1299: return (WINDOW_COPY_CMD_NOTHING);
! 1300: }
! 1301:
! 1302: static enum window_copy_cmd_action
! 1303: window_copy_cmd_jump_to_forward(struct window_copy_cmd_state *cs)
! 1304: {
! 1305: struct window_mode_entry *wme = cs->wme;
! 1306: struct window_copy_mode_data *data = wme->data;
! 1307: u_int np = wme->prefix;
! 1308: const char *argument = cs->args->argv[1];
! 1309:
! 1310: if (*argument != '\0') {
! 1311: data->jumptype = WINDOW_COPY_JUMPTOFORWARD;
! 1312: data->jumpchar = *argument;
! 1313: for (; np != 0; np--)
! 1314: window_copy_cursor_jump_to(wme);
! 1315: }
! 1316: return (WINDOW_COPY_CMD_NOTHING);
! 1317: }
! 1318:
! 1319: static enum window_copy_cmd_action
! 1320: window_copy_cmd_search_backward(struct window_copy_cmd_state *cs)
! 1321: {
! 1322: struct window_mode_entry *wme = cs->wme;
! 1323: struct window_copy_mode_data *data = wme->data;
! 1324: u_int np = wme->prefix;
! 1325: const char *argument = cs->args->argv[1];
! 1326:
! 1327: if (*argument != '\0') {
! 1328: data->searchtype = WINDOW_COPY_SEARCHUP;
! 1329: free(data->searchstr);
! 1330: data->searchstr = xstrdup(argument);
! 1331: for (; np != 0; np--)
! 1332: window_copy_search_up(wme);
! 1333: }
! 1334: return (WINDOW_COPY_CMD_NOTHING);
! 1335: }
! 1336:
! 1337: static enum window_copy_cmd_action
! 1338: window_copy_cmd_search_forward(struct window_copy_cmd_state *cs)
! 1339: {
! 1340: struct window_mode_entry *wme = cs->wme;
! 1341: struct window_copy_mode_data *data = wme->data;
! 1342: u_int np = wme->prefix;
! 1343: const char *argument = cs->args->argv[1];
! 1344:
! 1345: if (*argument != '\0') {
! 1346: data->searchtype = WINDOW_COPY_SEARCHDOWN;
! 1347: free(data->searchstr);
! 1348: data->searchstr = xstrdup(argument);
! 1349: for (; np != 0; np--)
! 1350: window_copy_search_down(wme);
! 1351: }
! 1352: return (WINDOW_COPY_CMD_NOTHING);
! 1353: }
! 1354:
! 1355: static enum window_copy_cmd_action
! 1356: window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs)
! 1357: {
! 1358: struct window_mode_entry *wme = cs->wme;
! 1359: struct window_copy_mode_data *data = wme->data;
! 1360: const char *argument = cs->args->argv[1];
! 1361: enum window_copy_cmd_action action = WINDOW_COPY_CMD_NOTHING;
! 1362: const char *ss = data->searchstr;
! 1363:
! 1364: if (data->searchx == -1 || data->searchy == -1) {
! 1365: data->searchx = data->cx;
! 1366: data->searchy = data->cy;
! 1367: data->searcho = data->oy;
! 1368: } else if (ss != NULL && strcmp(argument, ss) != 0) {
! 1369: data->cx = data->searchx;
! 1370: data->cy = data->searchy;
! 1371: data->oy = data->searcho;
! 1372: action = WINDOW_COPY_CMD_REDRAW;
! 1373: }
! 1374:
! 1375: if (*argument == '\0') {
! 1376: window_copy_clear_marks(wme);
! 1377: return (WINDOW_COPY_CMD_REDRAW);
! 1378: }
! 1379:
! 1380: switch (*argument++) {
! 1381: case '=':
! 1382: case '-':
! 1383: data->searchtype = WINDOW_COPY_SEARCHUP;
! 1384: free(data->searchstr);
! 1385: data->searchstr = xstrdup(argument);
! 1386: if (!window_copy_search_up(wme)) {
! 1387: window_copy_clear_marks(wme);
! 1388: return (WINDOW_COPY_CMD_REDRAW);
! 1389: }
! 1390: break;
! 1391: case '+':
! 1392: data->searchtype = WINDOW_COPY_SEARCHDOWN;
! 1393: free(data->searchstr);
! 1394: data->searchstr = xstrdup(argument);
! 1395: if (!window_copy_search_down(wme)) {
! 1396: window_copy_clear_marks(wme);
! 1397: return (WINDOW_COPY_CMD_REDRAW);
! 1398: }
! 1399: break;
! 1400: }
! 1401: return (action);
! 1402: }
! 1403:
! 1404: static enum window_copy_cmd_action
! 1405: window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs)
! 1406: {
! 1407: struct window_mode_entry *wme = cs->wme;
! 1408: struct window_copy_mode_data *data = wme->data;
! 1409: const char *argument = cs->args->argv[1];
! 1410: enum window_copy_cmd_action action = WINDOW_COPY_CMD_NOTHING;
! 1411: const char *ss = data->searchstr;
! 1412:
! 1413: if (data->searchx == -1 || data->searchy == -1) {
! 1414: data->searchx = data->cx;
! 1415: data->searchy = data->cy;
! 1416: data->searcho = data->oy;
! 1417: } else if (ss != NULL && strcmp(argument, ss) != 0) {
! 1418: data->cx = data->searchx;
! 1419: data->cy = data->searchy;
! 1420: data->oy = data->searcho;
! 1421: action = WINDOW_COPY_CMD_REDRAW;
! 1422: }
! 1423:
! 1424: if (*argument == '\0') {
! 1425: window_copy_clear_marks(wme);
! 1426: return (WINDOW_COPY_CMD_REDRAW);
! 1427: }
! 1428:
! 1429: switch (*argument++) {
! 1430: case '=':
! 1431: case '+':
! 1432: data->searchtype = WINDOW_COPY_SEARCHDOWN;
! 1433: free(data->searchstr);
! 1434: data->searchstr = xstrdup(argument);
! 1435: if (!window_copy_search_down(wme)) {
! 1436: window_copy_clear_marks(wme);
! 1437: return (WINDOW_COPY_CMD_REDRAW);
! 1438: }
! 1439: break;
! 1440: case '-':
! 1441: data->searchtype = WINDOW_COPY_SEARCHUP;
! 1442: free(data->searchstr);
! 1443: data->searchstr = xstrdup(argument);
! 1444: if (!window_copy_search_up(wme)) {
! 1445: window_copy_clear_marks(wme);
! 1446: return (WINDOW_COPY_CMD_REDRAW);
! 1447: }
! 1448: }
! 1449: return (action);
! 1450: }
! 1451:
! 1452: static const struct {
! 1453: const char *command;
! 1454: int minargs;
! 1455: int maxargs;
! 1456: enum window_copy_cmd_action (*f)(struct window_copy_cmd_state *);
! 1457: } window_copy_cmd_table[] = {
! 1458: { "append-selection", 0, 0,
! 1459: window_copy_cmd_append_selection },
! 1460: { "append-selection-and-cancel", 0, 0,
! 1461: window_copy_cmd_append_selection_and_cancel },
! 1462: { "back-to-indentation", 0, 0,
! 1463: window_copy_cmd_back_to_indentation },
! 1464: { "begin-selection", 0, 0,
! 1465: window_copy_cmd_begin_selection },
! 1466: { "bottom-line", 0, 0,
! 1467: window_copy_cmd_bottom_line },
! 1468: { "cancel", 0, 0,
! 1469: window_copy_cmd_cancel },
! 1470: { "clear-selection", 0, 0,
! 1471: window_copy_cmd_clear_selection },
! 1472: { "copy-end-of-line", 0, 0,
! 1473: window_copy_cmd_copy_end_of_line },
! 1474: { "copy-line", 0, 0,
! 1475: window_copy_cmd_copy_line },
! 1476: { "copy-pipe", 1, 1,
! 1477: window_copy_cmd_copy_pipe },
! 1478: { "copy-pipe-and-cancel", 1, 1,
! 1479: window_copy_cmd_copy_pipe_and_cancel },
! 1480: { "copy-selection", 0, 0,
! 1481: window_copy_cmd_copy_selection },
! 1482: { "copy-selection-and-cancel", 0, 0,
! 1483: window_copy_cmd_copy_selection_and_cancel },
! 1484: { "cursor-down", 0, 0,
! 1485: window_copy_cmd_cursor_down },
! 1486: { "cursor-left", 0, 0,
! 1487: window_copy_cmd_cursor_left },
! 1488: { "cursor-right", 0, 0,
! 1489: window_copy_cmd_cursor_right },
! 1490: { "cursor-up", 0, 0,
! 1491: window_copy_cmd_cursor_up },
! 1492: { "end-of-line", 0, 0,
! 1493: window_copy_cmd_end_of_line },
! 1494: { "goto-line", 1, 1,
! 1495: window_copy_cmd_goto_line },
! 1496: { "halfpage-down", 0, 0,
! 1497: window_copy_cmd_halfpage_down },
! 1498: { "halfpage-down-and-cancel", 0, 0,
! 1499: window_copy_cmd_halfpage_down_and_cancel },
! 1500: { "halfpage-up", 0, 0,
! 1501: window_copy_cmd_halfpage_up },
! 1502: { "history-bottom", 0, 0,
! 1503: window_copy_cmd_history_bottom },
! 1504: { "history-top", 0, 0,
! 1505: window_copy_cmd_history_top },
! 1506: { "jump-again", 0, 0,
! 1507: window_copy_cmd_jump_again },
! 1508: { "jump-backward", 1, 1,
! 1509: window_copy_cmd_jump_backward },
! 1510: { "jump-forward", 1, 1,
! 1511: window_copy_cmd_jump_forward },
! 1512: { "jump-reverse", 0, 0,
! 1513: window_copy_cmd_jump_reverse },
! 1514: { "jump-to-backward", 1, 1,
! 1515: window_copy_cmd_jump_to_backward },
! 1516: { "jump-to-forward", 1, 1,
! 1517: window_copy_cmd_jump_to_forward },
! 1518: { "middle-line", 0, 0,
! 1519: window_copy_cmd_middle_line },
! 1520: { "next-paragraph", 0, 0,
! 1521: window_copy_cmd_next_paragraph },
! 1522: { "next-space", 0, 0,
! 1523: window_copy_cmd_next_space },
! 1524: { "next-space-end", 0, 0,
! 1525: window_copy_cmd_next_space_end },
! 1526: { "next-word", 0, 0,
! 1527: window_copy_cmd_next_word },
! 1528: { "next-word-end", 0, 0,
! 1529: window_copy_cmd_next_word_end },
! 1530: { "other-end", 0, 0,
! 1531: window_copy_cmd_other_end },
! 1532: { "page-down", 0, 0,
! 1533: window_copy_cmd_page_down },
! 1534: { "page-down-and-cancel", 0, 0,
! 1535: window_copy_cmd_page_down_and_cancel },
! 1536: { "page-up", 0, 0,
! 1537: window_copy_cmd_page_up },
! 1538: { "previous-paragraph", 0, 0,
! 1539: window_copy_cmd_previous_paragraph },
! 1540: { "previous-space", 0, 0,
! 1541: window_copy_cmd_previous_space },
! 1542: { "previous-word", 0, 0,
! 1543: window_copy_cmd_previous_word },
! 1544: { "rectangle-toggle", 0, 0,
! 1545: window_copy_cmd_rectangle_toggle },
! 1546: { "scroll-down", 0, 0,
! 1547: window_copy_cmd_scroll_down },
! 1548: { "scroll-down-and-cancel", 0, 0,
! 1549: window_copy_cmd_scroll_down_and_cancel },
! 1550: { "scroll-up", 0, 0,
! 1551: window_copy_cmd_scroll_up },
! 1552: { "search-again", 0, 0,
! 1553: window_copy_cmd_search_again },
! 1554: { "search-backward", 1, 1,
! 1555: window_copy_cmd_search_backward },
! 1556: { "search-backward-incremental", 1, 1,
! 1557: window_copy_cmd_search_backward_incremental },
! 1558: { "search-forward", 1, 1,
! 1559: window_copy_cmd_search_forward },
! 1560: { "search-forward-incremental", 1, 1,
! 1561: window_copy_cmd_search_forward_incremental },
! 1562: { "search-reverse", 0, 0,
! 1563: window_copy_cmd_search_reverse },
! 1564: { "select-line", 0, 0,
! 1565: window_copy_cmd_select_line },
! 1566: { "select-word", 0, 0,
! 1567: window_copy_cmd_select_word },
! 1568: { "start-of-line", 0, 0,
! 1569: window_copy_cmd_start_of_line },
! 1570: { "stop-selection", 0, 0,
! 1571: window_copy_cmd_stop_selection },
! 1572: { "top-line", 0, 0,
! 1573: window_copy_cmd_top_line },
! 1574: };
! 1575:
1.157 nicm 1576: static void
1.208 nicm 1577: window_copy_command(struct window_mode_entry *wme, struct client *c,
1578: struct session *s, __unused struct winlink *wl, struct args *args,
1579: struct mouse_event *m)
1.1 nicm 1580: {
1.208 nicm 1581: struct window_copy_mode_data *data = wme->data;
1.213 ! nicm 1582: struct window_copy_cmd_state cs;
! 1583: enum window_copy_cmd_action action;
! 1584: const char *command;
! 1585: u_int i;
1.155 nicm 1586:
1587: if (args->argc == 0)
1588: return;
1589: command = args->argv[0];
1.21 nicm 1590:
1.202 nicm 1591: if (m != NULL && m->valid && !MOUSE_WHEEL(m->b))
1.156 nicm 1592: window_copy_move_mouse(m);
1593:
1.213 ! nicm 1594: cs.wme = wme;
! 1595: cs.args = args;
! 1596: cs.m = m;
! 1597: cs.c = c;
! 1598: cs.s = s;
! 1599:
! 1600: action = WINDOW_COPY_CMD_NOTHING;
! 1601: for (i = 0; i < nitems(window_copy_cmd_table); i++) {
! 1602: if (strcmp(window_copy_cmd_table[i].command, command) == 0) {
! 1603: if (args->argc - 1 < window_copy_cmd_table[i].minargs ||
! 1604: args->argc - 1 > window_copy_cmd_table[i].maxargs)
1.155 nicm 1605: break;
1.213 ! nicm 1606: action = window_copy_cmd_table[i].f (&cs);
! 1607: break;
1.163 nicm 1608: }
1.1 nicm 1609: }
1.21 nicm 1610:
1.162 nicm 1611: if (strncmp(command, "search-", 7) != 0 && data->searchmark != NULL) {
1.208 nicm 1612: window_copy_clear_marks(wme);
1.213 ! nicm 1613: if (action == WINDOW_COPY_CMD_NOTHING)
! 1614: action = WINDOW_COPY_CMD_REDRAW;
1.163 nicm 1615: data->searchx = data->searchy = -1;
1.162 nicm 1616: }
1.209 nicm 1617: wme->prefix = 1;
1618:
1.213 ! nicm 1619: if (action == WINDOW_COPY_CMD_CANCEL)
! 1620: window_pane_reset_mode(wme->wp);
! 1621: else if (action == WINDOW_COPY_CMD_REDRAW)
1.208 nicm 1622: window_copy_redraw_screen(wme);
1.50 nicm 1623: }
1624:
1.157 nicm 1625: static void
1.208 nicm 1626: window_copy_scroll_to(struct window_mode_entry *wme, u_int px, u_int py)
1.21 nicm 1627: {
1.208 nicm 1628: struct window_copy_mode_data *data = wme->data;
1.54 nicm 1629: struct grid *gd = data->backing->grid;
1.21 nicm 1630: u_int offset, gap;
1631:
1632: data->cx = px;
1633:
1.185 nicm 1634: if (py >= gd->hsize - data->oy && py < gd->hsize - data->oy + gd->sy)
1635: data->cy = py - (gd->hsize - data->oy);
1636: else {
1637: gap = gd->sy / 4;
1638: if (py < gd->sy) {
1639: offset = 0;
1640: data->cy = py;
1641: } else if (py > gd->hsize + gd->sy - gap) {
1642: offset = gd->hsize;
1643: data->cy = py - gd->hsize;
1644: } else {
1645: offset = py + gap - gd->sy;
1646: data->cy = py - offset;
1647: }
1648: data->oy = gd->hsize - offset;
1.21 nicm 1649: }
1650:
1.208 nicm 1651: window_copy_update_selection(wme, 1);
1652: window_copy_redraw_screen(wme);
1.21 nicm 1653: }
1654:
1.157 nicm 1655: static int
1.118 nicm 1656: window_copy_search_compare(struct grid *gd, u_int px, u_int py,
1657: struct grid *sgd, u_int spx, int cis)
1.21 nicm 1658: {
1.140 nicm 1659: struct grid_cell gc, sgc;
1660: const struct utf8_data *ud, *sud;
1.21 nicm 1661:
1.140 nicm 1662: grid_get_cell(gd, px, py, &gc);
1663: ud = &gc.data;
1664: grid_get_cell(sgd, spx, 0, &sgc);
1665: sud = &sgc.data;
1.35 nicm 1666:
1.140 nicm 1667: if (ud->size != sud->size || ud->width != sud->width)
1.21 nicm 1668: return (0);
1.97 nicm 1669:
1.140 nicm 1670: if (cis && ud->size == 1)
1671: return (tolower(ud->data[0]) == sud->data[0]);
1.97 nicm 1672:
1.140 nicm 1673: return (memcmp(ud->data, sud->data, ud->size) == 0);
1.21 nicm 1674: }
1675:
1.157 nicm 1676: static int
1.21 nicm 1677: window_copy_search_lr(struct grid *gd,
1.97 nicm 1678: struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
1.21 nicm 1679: {
1680: u_int ax, bx, px;
1.97 nicm 1681: int matched;
1.21 nicm 1682:
1683: for (ax = first; ax < last; ax++) {
1.181 nicm 1684: if (ax + sgd->sx > gd->sx)
1.21 nicm 1685: break;
1686: for (bx = 0; bx < sgd->sx; bx++) {
1687: px = ax + bx;
1.97 nicm 1688: matched = window_copy_search_compare(gd, px, py, sgd,
1689: bx, cis);
1690: if (!matched)
1.21 nicm 1691: break;
1692: }
1693: if (bx == sgd->sx) {
1694: *ppx = ax;
1695: return (1);
1696: }
1697: }
1698: return (0);
1699: }
1700:
1.157 nicm 1701: static int
1.21 nicm 1702: window_copy_search_rl(struct grid *gd,
1.97 nicm 1703: struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
1.21 nicm 1704: {
1705: u_int ax, bx, px;
1.97 nicm 1706: int matched;
1.21 nicm 1707:
1708: for (ax = last + 1; ax > first; ax--) {
1.24 nicm 1709: if (gd->sx - (ax - 1) < sgd->sx)
1710: continue;
1.21 nicm 1711: for (bx = 0; bx < sgd->sx; bx++) {
1712: px = ax - 1 + bx;
1.97 nicm 1713: matched = window_copy_search_compare(gd, px, py, sgd,
1714: bx, cis);
1715: if (!matched)
1.21 nicm 1716: break;
1717: }
1718: if (bx == sgd->sx) {
1719: *ppx = ax - 1;
1720: return (1);
1721: }
1722: }
1723: return (0);
1724: }
1725:
1.157 nicm 1726: static void
1.150 nicm 1727: window_copy_move_left(struct screen *s, u_int *fx, u_int *fy)
1.21 nicm 1728: {
1.150 nicm 1729: if (*fx == 0) { /* left */
1730: if (*fy == 0) /* top */
1731: return;
1732: *fx = screen_size_x(s) - 1;
1733: *fy = *fy - 1;
1734: } else
1735: *fx = *fx - 1;
1736: }
1.21 nicm 1737:
1.157 nicm 1738: static void
1.150 nicm 1739: window_copy_move_right(struct screen *s, u_int *fx, u_int *fy)
1740: {
1741: if (*fx == screen_size_x(s) - 1) { /* right */
1742: if (*fy == screen_hsize(s) + screen_size_y(s)) /* bottom */
1.21 nicm 1743: return;
1.150 nicm 1744: *fx = 0;
1745: *fy = *fy + 1;
1.21 nicm 1746: } else
1.150 nicm 1747: *fx = *fx + 1;
1748: }
1.21 nicm 1749:
1.157 nicm 1750: static int
1.150 nicm 1751: window_copy_is_lowercase(const char *ptr)
1752: {
1753: while (*ptr != '\0') {
1754: if (*ptr != tolower((u_char)*ptr))
1755: return (0);
1756: ++ptr;
1.97 nicm 1757: }
1.150 nicm 1758: return (1);
1759: }
1.97 nicm 1760:
1.150 nicm 1761: /*
1762: * Search for text stored in sgd starting from position fx,fy up to endline. If
1763: * found, jump to it. If cis then ignore case. The direction is 0 for searching
1764: * up, down otherwise. If wrap then go to begin/end of grid and try again if
1765: * not found.
1766: */
1.163 nicm 1767: static int
1.208 nicm 1768: window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
1.150 nicm 1769: struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap,
1770: int direction)
1771: {
1772: u_int i, px;
1773: int found;
1774:
1775: found = 0;
1776: if (direction) {
1777: for (i = fy; i <= endline; i++) {
1778: found = window_copy_search_lr(gd, sgd, &px, i, fx,
1779: gd->sx, cis);
1780: if (found)
1781: break;
1782: fx = 0;
1783: }
1784: } else {
1785: for (i = fy + 1; endline < i; i--) {
1786: found = window_copy_search_rl(gd, sgd, &px, i - 1, 0,
1787: fx, cis);
1788: if (found) {
1789: i--;
1790: break;
1791: }
1792: fx = gd->sx;
1.21 nicm 1793: }
1794: }
1.150 nicm 1795:
1.163 nicm 1796: if (found) {
1.208 nicm 1797: window_copy_scroll_to(wme, px, i);
1.163 nicm 1798: return (1);
1799: }
1800: if (wrap) {
1.208 nicm 1801: return (window_copy_search_jump(wme, gd, sgd,
1.163 nicm 1802: direction ? 0 : gd->sx - 1,
1.150 nicm 1803: direction ? 0 : gd->hsize + gd->sy - 1, fy, cis, 0,
1.163 nicm 1804: direction));
1.21 nicm 1805: }
1.163 nicm 1806: return (0);
1.21 nicm 1807: }
1808:
1.150 nicm 1809: /*
1810: * Search in for text searchstr. If direction is 0 then search up, otherwise
1.184 nicm 1811: * down.
1.150 nicm 1812: */
1.163 nicm 1813: static int
1.208 nicm 1814: window_copy_search(struct window_mode_entry *wme, int direction)
1.21 nicm 1815: {
1.208 nicm 1816: struct window_pane *wp = wme->wp;
1817: struct window_copy_mode_data *data = wme->data;
1.54 nicm 1818: struct screen *s = data->backing, ss;
1.21 nicm 1819: struct screen_write_ctx ctx;
1.150 nicm 1820: struct grid *gd = s->grid;
1821: u_int fx, fy, endline;
1.163 nicm 1822: int wrapflag, cis, found;
1.21 nicm 1823:
1.174 nicm 1824: free(wp->searchstr);
1825: wp->searchstr = xstrdup(data->searchstr);
1826:
1.150 nicm 1827: fx = data->cx;
1828: fy = screen_hsize(data->backing) - data->oy + data->cy;
1.21 nicm 1829:
1.162 nicm 1830: screen_init(&ss, screen_write_strlen("%s", data->searchstr), 1, 0);
1.21 nicm 1831: screen_write_start(&ctx, NULL, &ss);
1.162 nicm 1832: screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", data->searchstr);
1.21 nicm 1833: screen_write_stop(&ctx);
1834:
1.184 nicm 1835: if (direction)
1836: window_copy_move_right(s, &fx, &fy);
1837: else
1838: window_copy_move_left(s, &fx, &fy);
1.150 nicm 1839:
1840: wrapflag = options_get_number(wp->window->options, "wrap-search");
1.162 nicm 1841: cis = window_copy_is_lowercase(data->searchstr);
1.21 nicm 1842:
1.150 nicm 1843: if (direction)
1844: endline = gd->hsize + gd->sy - 1;
1845: else
1846: endline = 0;
1.208 nicm 1847: found = window_copy_search_jump(wme, gd, ss.grid, fx, fy, endline, cis,
1.162 nicm 1848: wrapflag, direction);
1849:
1.208 nicm 1850: if (window_copy_search_marks(wme, &ss))
1851: window_copy_redraw_screen(wme);
1.21 nicm 1852:
1.150 nicm 1853: screen_free(&ss);
1.163 nicm 1854: return (found);
1.150 nicm 1855: }
1.97 nicm 1856:
1.162 nicm 1857: static int
1.208 nicm 1858: window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp)
1.162 nicm 1859: {
1.208 nicm 1860: struct window_copy_mode_data *data = wme->data;
1.162 nicm 1861: struct screen *s = data->backing, ss;
1862: struct screen_write_ctx ctx;
1863: struct grid *gd = s->grid;
1.170 nicm 1864: int found, cis, which = -1;
1.162 nicm 1865: u_int px, py, b, nfound = 0, width;
1866:
1867: if (ssp == NULL) {
1868: width = screen_write_strlen("%s", data->searchstr);
1869: screen_init(&ss, width, 1, 0);
1870: screen_write_start(&ctx, NULL, &ss);
1871: screen_write_nputs(&ctx, -1, &grid_default_cell, "%s",
1872: data->searchstr);
1873: screen_write_stop(&ctx);
1874: ssp = &ss;
1875: } else
1876: width = screen_size_x(ssp);
1877:
1878: cis = window_copy_is_lowercase(data->searchstr);
1879:
1880: free(data->searchmark);
1881: data->searchmark = bit_alloc((gd->hsize + gd->sy) * gd->sx);
1882:
1883: for (py = 0; py < gd->hsize + gd->sy; py++) {
1884: px = 0;
1885: for (;;) {
1886: found = window_copy_search_lr(gd, ssp->grid, &px, py,
1887: px, gd->sx, cis);
1888: if (!found)
1889: break;
1.170 nicm 1890:
1.162 nicm 1891: nfound++;
1.170 nicm 1892: if (px == data->cx && py == gd->hsize + data->cy - data->oy)
1893: which = nfound;
1.162 nicm 1894:
1895: b = (py * gd->sx) + px;
1896: bit_nset(data->searchmark, b, b + width - 1);
1897:
1898: px++;
1899: }
1900: }
1901:
1.170 nicm 1902: if (which != -1)
1903: data->searchthis = 1 + nfound - which;
1904: else
1905: data->searchthis = -1;
1906: data->searchcount = nfound;
1907:
1.162 nicm 1908: if (ssp == &ss)
1909: screen_free(&ss);
1910: return (nfound);
1911: }
1912:
1.157 nicm 1913: static void
1.208 nicm 1914: window_copy_clear_marks(struct window_mode_entry *wme)
1.163 nicm 1915: {
1.208 nicm 1916: struct window_copy_mode_data *data = wme->data;
1.163 nicm 1917:
1918: free(data->searchmark);
1919: data->searchmark = NULL;
1920: }
1921:
1922: static int
1.208 nicm 1923: window_copy_search_up(struct window_mode_entry *wme)
1.150 nicm 1924: {
1.208 nicm 1925: return (window_copy_search(wme, 0));
1.150 nicm 1926: }
1.21 nicm 1927:
1.163 nicm 1928: static int
1.208 nicm 1929: window_copy_search_down(struct window_mode_entry *wme)
1.150 nicm 1930: {
1.208 nicm 1931: return (window_copy_search(wme, 1));
1.21 nicm 1932: }
1933:
1.157 nicm 1934: static void
1.208 nicm 1935: window_copy_goto_line(struct window_mode_entry *wme, const char *linestr)
1.21 nicm 1936: {
1.208 nicm 1937: struct window_copy_mode_data *data = wme->data;
1.21 nicm 1938: const char *errstr;
1.199 nicm 1939: int lineno;
1.21 nicm 1940:
1.199 nicm 1941: lineno = strtonum(linestr, -1, INT_MAX, &errstr);
1.21 nicm 1942: if (errstr != NULL)
1943: return;
1.199 nicm 1944: if (lineno < 0 || (u_int)lineno > screen_hsize(data->backing))
1945: lineno = screen_hsize(data->backing);
1.35 nicm 1946:
1.21 nicm 1947: data->oy = lineno;
1.208 nicm 1948: window_copy_update_selection(wme, 1);
1949: window_copy_redraw_screen(wme);
1.21 nicm 1950: }
1951:
1.157 nicm 1952: static void
1.208 nicm 1953: window_copy_write_line(struct window_mode_entry *wme,
1954: struct screen_write_ctx *ctx, u_int py)
1.1 nicm 1955: {
1.208 nicm 1956: struct window_pane *wp = wme->wp;
1957: struct window_copy_mode_data *data = wme->data;
1.1 nicm 1958: struct screen *s = &data->screen;
1.136 nicm 1959: struct options *oo = wp->window->options;
1.1 nicm 1960: struct grid_cell gc;
1.100 nicm 1961: char hdr[512];
1.162 nicm 1962: size_t size = 0;
1.21 nicm 1963:
1.101 nicm 1964: style_apply(&gc, oo, "mode-style");
1.164 nicm 1965: gc.flags |= GRID_FLAG_NOPALETTE;
1.1 nicm 1966:
1.201 nicm 1967: if (py == 0 && s->rupper < s->rlower) {
1.170 nicm 1968: if (data->searchmark == NULL) {
1969: size = xsnprintf(hdr, sizeof hdr,
1970: "[%u/%u]", data->oy, screen_hsize(data->backing));
1971: } else {
1972: if (data->searchthis == -1) {
1973: size = xsnprintf(hdr, sizeof hdr,
1974: "(%u results) [%d/%u]", data->searchcount,
1975: data->oy, screen_hsize(data->backing));
1976: } else {
1977: size = xsnprintf(hdr, sizeof hdr,
1978: "(%u/%u results) [%d/%u]", data->searchthis,
1979: data->searchcount, data->oy,
1980: screen_hsize(data->backing));
1981: }
1982: }
1.62 nicm 1983: if (size > screen_size_x(s))
1984: size = screen_size_x(s);
1.212 nicm 1985: screen_write_cursormove(ctx, screen_size_x(s) - size, 0, 0);
1.1 nicm 1986: screen_write_puts(ctx, &gc, "%s", hdr);
1987: } else
1988: size = 0;
1989:
1.105 nicm 1990: if (size < screen_size_x(s)) {
1.212 nicm 1991: screen_write_cursormove(ctx, 0, py, 0);
1.162 nicm 1992: screen_write_copy(ctx, data->backing, 0,
1.105 nicm 1993: (screen_hsize(data->backing) - data->oy) + py,
1.162 nicm 1994: screen_size_x(s) - size, 1, data->searchmark, &gc);
1.105 nicm 1995: }
1.18 nicm 1996:
1997: if (py == data->cy && data->cx == screen_size_x(s)) {
1998: memcpy(&gc, &grid_default_cell, sizeof gc);
1.212 nicm 1999: screen_write_cursormove(ctx, screen_size_x(s) - 1, py, 0);
1.18 nicm 2000: screen_write_putc(ctx, &gc, '$');
2001: }
1.1 nicm 2002: }
2003:
1.157 nicm 2004: static void
1.208 nicm 2005: window_copy_write_lines(struct window_mode_entry *wme,
2006: struct screen_write_ctx *ctx, u_int py, u_int ny)
1.1 nicm 2007: {
2008: u_int yy;
2009:
2010: for (yy = py; yy < py + ny; yy++)
1.208 nicm 2011: window_copy_write_line(wme, ctx, py);
1.121 nicm 2012: }
2013:
1.157 nicm 2014: static void
1.208 nicm 2015: window_copy_redraw_selection(struct window_mode_entry *wme, u_int old_y)
1.121 nicm 2016: {
1.208 nicm 2017: struct window_copy_mode_data *data = wme->data;
1.121 nicm 2018: u_int new_y, start, end;
2019:
2020: new_y = data->cy;
2021: if (old_y <= new_y) {
2022: start = old_y;
2023: end = new_y;
2024: } else {
2025: start = new_y;
2026: end = old_y;
2027: }
1.208 nicm 2028: window_copy_redraw_lines(wme, start, end - start + 1);
1.1 nicm 2029: }
2030:
1.157 nicm 2031: static void
1.208 nicm 2032: window_copy_redraw_lines(struct window_mode_entry *wme, u_int py, u_int ny)
1.1 nicm 2033: {
1.208 nicm 2034: struct window_pane *wp = wme->wp;
2035: struct window_copy_mode_data *data = wme->data;
1.1 nicm 2036: struct screen_write_ctx ctx;
2037: u_int i;
2038:
2039: screen_write_start(&ctx, wp, NULL);
2040: for (i = py; i < py + ny; i++)
1.208 nicm 2041: window_copy_write_line(wme, &ctx, i);
1.212 nicm 2042: screen_write_cursormove(&ctx, data->cx, data->cy, 0);
1.1 nicm 2043: screen_write_stop(&ctx);
2044: }
2045:
1.157 nicm 2046: static void
1.208 nicm 2047: window_copy_redraw_screen(struct window_mode_entry *wme)
1.1 nicm 2048: {
1.208 nicm 2049: struct window_copy_mode_data *data = wme->data;
1.1 nicm 2050:
1.208 nicm 2051: window_copy_redraw_lines(wme, 0, screen_size_y(&data->screen));
1.1 nicm 2052: }
2053:
1.157 nicm 2054: static void
1.208 nicm 2055: window_copy_synchronize_cursor(struct window_mode_entry *wme)
1.161 nicm 2056: {
1.208 nicm 2057: struct window_copy_mode_data *data = wme->data;
1.161 nicm 2058: u_int xx, yy;
2059:
2060: xx = data->cx;
2061: yy = screen_hsize(data->backing) + data->cy - data->oy;
2062:
2063: switch (data->cursordrag) {
2064: case CURSORDRAG_ENDSEL:
2065: data->endselx = xx;
2066: data->endsely = yy;
2067: break;
2068: case CURSORDRAG_SEL:
2069: data->selx = xx;
2070: data->sely = yy;
2071: break;
2072: case CURSORDRAG_NONE:
2073: break;
2074: }
2075: }
2076:
2077: static void
1.208 nicm 2078: window_copy_update_cursor(struct window_mode_entry *wme, u_int cx, u_int cy)
1.1 nicm 2079: {
1.208 nicm 2080: struct window_pane *wp = wme->wp;
2081: struct window_copy_mode_data *data = wme->data;
1.18 nicm 2082: struct screen *s = &data->screen;
1.1 nicm 2083: struct screen_write_ctx ctx;
1.18 nicm 2084: u_int old_cx, old_cy;
1.1 nicm 2085:
1.18 nicm 2086: old_cx = data->cx; old_cy = data->cy;
2087: data->cx = cx; data->cy = cy;
2088: if (old_cx == screen_size_x(s))
1.208 nicm 2089: window_copy_redraw_lines(wme, old_cy, 1);
1.18 nicm 2090: if (data->cx == screen_size_x(s))
1.208 nicm 2091: window_copy_redraw_lines(wme, data->cy, 1);
1.18 nicm 2092: else {
2093: screen_write_start(&ctx, wp, NULL);
1.212 nicm 2094: screen_write_cursormove(&ctx, data->cx, data->cy, 0);
1.18 nicm 2095: screen_write_stop(&ctx);
2096: }
1.1 nicm 2097: }
2098:
1.157 nicm 2099: static void
1.208 nicm 2100: window_copy_start_selection(struct window_mode_entry *wme)
1.1 nicm 2101: {
1.208 nicm 2102: struct window_copy_mode_data *data = wme->data;
1.1 nicm 2103:
1.18 nicm 2104: data->selx = data->cx;
1.54 nicm 2105: data->sely = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 2106:
1.161 nicm 2107: data->endselx = data->selx;
2108: data->endsely = data->sely;
2109:
2110: data->cursordrag = CURSORDRAG_ENDSEL;
2111:
1.208 nicm 2112: window_copy_set_selection(wme, 1);
1.1 nicm 2113: }
2114:
1.157 nicm 2115: static int
1.208 nicm 2116: window_copy_adjust_selection(struct window_mode_entry *wme, u_int *selx,
2117: u_int *sely)
1.161 nicm 2118: {
1.208 nicm 2119: struct window_copy_mode_data *data = wme->data;
1.161 nicm 2120: struct screen *s = &data->screen;
2121: u_int sx, sy, ty;
2122: int relpos;
2123:
2124: sx = *selx;
2125: sy = *sely;
2126:
2127: ty = screen_hsize(data->backing) - data->oy;
2128: if (sy < ty) {
2129: relpos = WINDOW_COPY_REL_POS_ABOVE;
2130: if (!data->rectflag)
2131: sx = 0;
2132: sy = 0;
2133: } else if (sy > ty + screen_size_y(s) - 1) {
2134: relpos = WINDOW_COPY_REL_POS_BELOW;
2135: if (!data->rectflag)
2136: sx = screen_size_x(s) - 1;
2137: sy = screen_size_y(s) - 1;
2138: } else {
2139: relpos = WINDOW_COPY_REL_POS_ON_SCREEN;
2140: sy -= ty;
2141: }
2142:
2143: *selx = sx;
1.176 nicm 2144: *sely = sy;
1.161 nicm 2145: return (relpos);
2146: }
2147:
2148: static int
1.208 nicm 2149: window_copy_update_selection(struct window_mode_entry *wme, int may_redraw)
1.1 nicm 2150: {
1.208 nicm 2151: struct window_copy_mode_data *data = wme->data;
1.1 nicm 2152: struct screen *s = &data->screen;
1.192 nicm 2153:
2154: if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
2155: return (0);
1.208 nicm 2156: return (window_copy_set_selection(wme, may_redraw));
1.192 nicm 2157: }
2158:
2159: static int
1.208 nicm 2160: window_copy_set_selection(struct window_mode_entry *wme, int may_redraw)
1.192 nicm 2161: {
1.208 nicm 2162: struct window_pane *wp = wme->wp;
2163: struct window_copy_mode_data *data = wme->data;
1.192 nicm 2164: struct screen *s = &data->screen;
1.136 nicm 2165: struct options *oo = wp->window->options;
1.1 nicm 2166: struct grid_cell gc;
1.161 nicm 2167: u_int sx, sy, cy, endsx, endsy;
2168: int startrelpos, endrelpos;
1.1 nicm 2169:
1.208 nicm 2170: window_copy_synchronize_cursor(wme);
1.1 nicm 2171:
2172: /* Adjust the selection. */
2173: sx = data->selx;
2174: sy = data->sely;
1.208 nicm 2175: startrelpos = window_copy_adjust_selection(wme, &sx, &sy);
1.161 nicm 2176:
2177: /* Adjust the end of selection. */
2178: endsx = data->endselx;
2179: endsy = data->endsely;
1.208 nicm 2180: endrelpos = window_copy_adjust_selection(wme, &endsx, &endsy);
1.161 nicm 2181:
2182: /* Selection is outside of the current screen */
2183: if (startrelpos == endrelpos &&
2184: startrelpos != WINDOW_COPY_REL_POS_ON_SCREEN) {
2185: screen_hide_selection(s);
2186: return (0);
2187: }
1.1 nicm 2188:
1.161 nicm 2189: /* Set colours and selection. */
2190: style_apply(&gc, oo, "mode-style");
1.164 nicm 2191: gc.flags |= GRID_FLAG_NOPALETTE;
1.192 nicm 2192: screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag,
2193: data->modekeys, &gc);
1.42 nicm 2194:
1.96 nicm 2195: if (data->rectflag && may_redraw) {
1.42 nicm 2196: /*
2197: * Can't rely on the caller to redraw the right lines for
2198: * rectangle selection - find the highest line and the number
2199: * of lines, and redraw just past that in both directions
2200: */
2201: cy = data->cy;
1.182 nicm 2202: if (data->cursordrag == CURSORDRAG_ENDSEL) {
2203: if (sy < cy)
1.208 nicm 2204: window_copy_redraw_lines(wme, sy, cy - sy + 1);
1.182 nicm 2205: else
1.208 nicm 2206: window_copy_redraw_lines(wme, cy, sy - cy + 1);
1.182 nicm 2207: } else {
1.208 nicm 2208: if (endsy < cy) {
2209: window_copy_redraw_lines(wme, endsy,
2210: cy - endsy + 1);
2211: } else {
2212: window_copy_redraw_lines(wme, cy,
2213: endsy - cy + 1);
2214: }
1.182 nicm 2215: }
1.42 nicm 2216: }
2217:
1.1 nicm 2218: return (1);
2219: }
2220:
1.157 nicm 2221: static void *
1.208 nicm 2222: window_copy_get_selection(struct window_mode_entry *wme, size_t *len)
1.1 nicm 2223: {
1.208 nicm 2224: struct window_pane *wp = wme->wp;
2225: struct window_copy_mode_data *data = wme->data;
1.1 nicm 2226: struct screen *s = &data->screen;
2227: char *buf;
1.42 nicm 2228: size_t off;
1.111 nicm 2229: u_int i, xx, yy, sx, sy, ex, ey, ey_last;
1.188 nicm 2230: u_int firstsx, lastex, restex, restsx, selx;
1.69 nicm 2231: int keys;
1.1 nicm 2232:
1.192 nicm 2233: if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE)
1.89 nicm 2234: return (NULL);
1.1 nicm 2235:
2236: buf = xmalloc(1);
2237: off = 0;
2238:
2239: *buf = '\0';
2240:
2241: /*
2242: * The selection extends from selx,sely to (adjusted) cx,cy on
2243: * the base screen.
2244: */
2245:
2246: /* Find start and end. */
1.161 nicm 2247: xx = data->endselx;
2248: yy = data->endsely;
1.2 nicm 2249: if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
1.1 nicm 2250: sx = xx; sy = yy;
2251: ex = data->selx; ey = data->sely;
2252: } else {
2253: sx = data->selx; sy = data->sely;
2254: ex = xx; ey = yy;
2255: }
2256:
2257: /* Trim ex to end of line. */
1.208 nicm 2258: ey_last = window_copy_find_length(wme, ey);
1.111 nicm 2259: if (ex > ey_last)
2260: ex = ey_last;
1.1 nicm 2261:
1.42 nicm 2262: /*
2263: * Deal with rectangle-copy if necessary; four situations: start of
2264: * first line (firstsx), end of last line (lastex), start (restsx) and
2265: * end (restex) of all other lines.
2266: */
2267: xx = screen_size_x(s);
1.69 nicm 2268:
2269: /*
2270: * Behave according to mode-keys. If it is emacs, copy like emacs,
2271: * keeping the top-left-most character, and dropping the
2272: * bottom-right-most, regardless of copy direction. If it is vi, also
2273: * keep bottom-right-most character.
2274: */
1.136 nicm 2275: keys = options_get_number(wp->window->options, "mode-keys");
1.42 nicm 2276: if (data->rectflag) {
2277: /*
2278: * Need to ignore the column with the cursor in it, which for
2279: * rectangular copy means knowing which side the cursor is on.
2280: */
1.188 nicm 2281: if (data->cursordrag == CURSORDRAG_ENDSEL)
2282: selx = data->selx;
2283: else
2284: selx = data->endselx;
2285: if (selx < data->cx) {
1.42 nicm 2286: /* Selection start is on the left. */
1.69 nicm 2287: if (keys == MODEKEY_EMACS) {
2288: lastex = data->cx;
2289: restex = data->cx;
2290: }
2291: else {
2292: lastex = data->cx + 1;
2293: restex = data->cx + 1;
2294: }
1.188 nicm 2295: firstsx = selx;
2296: restsx = selx;
1.42 nicm 2297: } else {
2298: /* Cursor is on the left. */
1.188 nicm 2299: lastex = selx + 1;
2300: restex = selx + 1;
1.64 nicm 2301: firstsx = data->cx;
2302: restsx = data->cx;
1.42 nicm 2303: }
2304: } else {
1.69 nicm 2305: if (keys == MODEKEY_EMACS)
2306: lastex = ex;
1.74 nicm 2307: else
1.69 nicm 2308: lastex = ex + 1;
1.42 nicm 2309: restex = xx;
2310: firstsx = sx;
2311: restsx = 0;
2312: }
2313:
1.1 nicm 2314: /* Copy the lines. */
1.110 nicm 2315: for (i = sy; i <= ey; i++) {
1.208 nicm 2316: window_copy_copy_line(wme, &buf, &off, i,
1.110 nicm 2317: (i == sy ? firstsx : restsx),
2318: (i == ey ? lastex : restex));
1.1 nicm 2319: }
2320:
1.26 nicm 2321: /* Don't bother if no data. */
2322: if (off == 0) {
1.81 nicm 2323: free(buf);
1.89 nicm 2324: return (NULL);
1.26 nicm 2325: }
1.111 nicm 2326: if (keys == MODEKEY_EMACS || lastex <= ey_last)
2327: off -= 1; /* remove final \n (unless at end in vi mode) */
2328: *len = off;
1.89 nicm 2329: return (buf);
2330: }
2331:
1.157 nicm 2332: static void
1.208 nicm 2333: window_copy_copy_buffer(struct window_mode_entry *wme, void *buf, size_t len)
1.89 nicm 2334: {
1.208 nicm 2335: struct window_pane *wp = wme->wp;
2336: struct screen_write_ctx ctx;
1.72 nicm 2337:
1.178 nicm 2338: if (options_get_number(global_options, "set-clipboard") != 0) {
1.91 nicm 2339: screen_write_start(&ctx, wp, NULL);
2340: screen_write_setselection(&ctx, buf, len);
2341: screen_write_stop(&ctx);
1.179 nicm 2342: notify_pane("pane-set-clipboard", wp);
1.91 nicm 2343: }
1.1 nicm 2344:
1.203 nicm 2345: if (paste_set(buf, len, NULL, NULL) != 0)
1.102 nicm 2346: free(buf);
1.89 nicm 2347: }
2348:
1.157 nicm 2349: static void
1.208 nicm 2350: window_copy_copy_pipe(struct window_mode_entry *wme, struct session *s,
1.203 nicm 2351: const char *fmt)
1.89 nicm 2352: {
1.208 nicm 2353: struct window_pane *wp = wme->wp;
2354: void *buf;
2355: size_t len;
2356: struct job *job;
2357: char *expanded;
1.89 nicm 2358:
1.208 nicm 2359: buf = window_copy_get_selection(wme, &len);
1.89 nicm 2360: if (buf == NULL)
2361: return;
1.203 nicm 2362: expanded = format_single(NULL, fmt, NULL, s, NULL, wp);
1.89 nicm 2363:
1.187 nicm 2364: job = job_run(expanded, s, NULL, NULL, NULL, NULL, NULL, JOB_NOWAIT);
1.196 nicm 2365: bufferevent_write(job_get_event(job), buf, len);
1.120 nicm 2366:
2367: free(expanded);
1.208 nicm 2368: window_copy_copy_buffer(wme, buf, len);
1.89 nicm 2369: }
2370:
1.157 nicm 2371: static void
1.208 nicm 2372: window_copy_copy_selection(struct window_mode_entry *wme)
1.89 nicm 2373: {
1.203 nicm 2374: char *buf;
1.114 nicm 2375: size_t len;
1.89 nicm 2376:
1.208 nicm 2377: buf = window_copy_get_selection(wme, &len);
1.203 nicm 2378: if (buf != NULL)
1.208 nicm 2379: window_copy_copy_buffer(wme, buf, len);
1.103 nicm 2380: }
2381:
1.157 nicm 2382: static void
1.208 nicm 2383: window_copy_append_selection(struct window_mode_entry *wme)
1.103 nicm 2384: {
1.208 nicm 2385: struct window_pane *wp = wme->wp;
1.108 nicm 2386: char *buf;
2387: struct paste_buffer *pb;
1.203 nicm 2388: const char *bufdata, *bufname;
1.132 nicm 2389: size_t len, bufsize;
1.108 nicm 2390: struct screen_write_ctx ctx;
1.103 nicm 2391:
1.208 nicm 2392: buf = window_copy_get_selection(wme, &len);
1.103 nicm 2393: if (buf == NULL)
2394: return;
2395:
1.178 nicm 2396: if (options_get_number(global_options, "set-clipboard") != 0) {
1.103 nicm 2397: screen_write_start(&ctx, wp, NULL);
2398: screen_write_setselection(&ctx, buf, len);
2399: screen_write_stop(&ctx);
1.179 nicm 2400: notify_pane("pane-set-clipboard", wp);
1.103 nicm 2401: }
2402:
1.203 nicm 2403: pb = paste_get_top(&bufname);
1.103 nicm 2404: if (pb != NULL) {
1.132 nicm 2405: bufdata = paste_buffer_data(pb, &bufsize);
2406: buf = xrealloc(buf, len + bufsize);
2407: memmove(buf + bufsize, buf, len);
2408: memcpy(buf, bufdata, bufsize);
2409: len += bufsize;
1.103 nicm 2410: }
1.108 nicm 2411: if (paste_set(buf, len, bufname, NULL) != 0)
1.103 nicm 2412: free(buf);
1.1 nicm 2413: }
2414:
1.157 nicm 2415: static void
1.208 nicm 2416: window_copy_copy_line(struct window_mode_entry *wme, char **buf, size_t *off,
2417: u_int sy, u_int sx, u_int ex)
1.1 nicm 2418: {
1.208 nicm 2419: struct window_copy_mode_data *data = wme->data;
1.54 nicm 2420: struct grid *gd = data->backing->grid;
1.140 nicm 2421: struct grid_cell gc;
1.54 nicm 2422: struct grid_line *gl;
1.86 nicm 2423: struct utf8_data ud;
1.54 nicm 2424: u_int i, xx, wrapped = 0;
1.115 nicm 2425: const char *s;
1.1 nicm 2426:
2427: if (sx > ex)
2428: return;
2429:
1.16 nicm 2430: /*
2431: * Work out if the line was wrapped at the screen edge and all of it is
2432: * on screen.
2433: */
1.190 nicm 2434: gl = grid_get_line(gd, sy);
1.35 nicm 2435: if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
1.16 nicm 2436: wrapped = 1;
2437:
2438: /* If the line was wrapped, don't strip spaces (use the full length). */
2439: if (wrapped)
2440: xx = gl->cellsize;
2441: else
1.208 nicm 2442: xx = window_copy_find_length(wme, sy);
1.1 nicm 2443: if (ex > xx)
2444: ex = xx;
2445: if (sx > xx)
2446: sx = xx;
2447:
2448: if (sx < ex) {
2449: for (i = sx; i < ex; i++) {
1.140 nicm 2450: grid_get_cell(gd, i, sy, &gc);
2451: if (gc.flags & GRID_FLAG_PADDING)
1.1 nicm 2452: continue;
1.140 nicm 2453: utf8_copy(&ud, &gc.data);
2454: if (ud.size == 1 && (gc.attr & GRID_ATTR_CHARSET)) {
1.115 nicm 2455: s = tty_acs_get(NULL, ud.data[0]);
2456: if (s != NULL && strlen(s) <= sizeof ud.data) {
2457: ud.size = strlen(s);
1.117 nicm 2458: memcpy(ud.data, s, ud.size);
1.115 nicm 2459: }
2460: }
1.86 nicm 2461:
1.116 nicm 2462: *buf = xrealloc(*buf, (*off) + ud.size);
1.86 nicm 2463: memcpy(*buf + *off, ud.data, ud.size);
2464: *off += ud.size;
1.1 nicm 2465: }
2466: }
2467:
1.16 nicm 2468: /* Only add a newline if the line wasn't wrapped. */
1.44 nicm 2469: if (!wrapped || ex != xx) {
1.116 nicm 2470: *buf = xrealloc(*buf, (*off) + 1);
1.16 nicm 2471: (*buf)[(*off)++] = '\n';
2472: }
1.1 nicm 2473: }
2474:
1.157 nicm 2475: static void
1.208 nicm 2476: window_copy_clear_selection(struct window_mode_entry *wme)
1.47 nicm 2477: {
1.208 nicm 2478: struct window_copy_mode_data *data = wme->data;
1.47 nicm 2479: u_int px, py;
2480:
2481: screen_clear_selection(&data->screen);
2482:
1.161 nicm 2483: data->cursordrag = CURSORDRAG_NONE;
1.197 nicm 2484: data->lineflag = LINE_SEL_NONE;
1.161 nicm 2485:
1.54 nicm 2486: py = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 2487: px = window_copy_find_length(wme, py);
1.47 nicm 2488: if (data->cx > px)
1.208 nicm 2489: window_copy_update_cursor(wme, px, data->cy);
1.47 nicm 2490: }
2491:
1.157 nicm 2492: static int
1.208 nicm 2493: window_copy_in_set(struct window_mode_entry *wme, u_int px, u_int py,
2494: const char *set)
1.1 nicm 2495: {
1.208 nicm 2496: struct window_copy_mode_data *data = wme->data;
1.140 nicm 2497: struct grid_cell gc;
2498: const struct utf8_data *ud;
1.204 nicm 2499: struct utf8_data *copy;
2500: struct utf8_data *loop;
2501: int found = 0;
1.140 nicm 2502:
2503: grid_get_cell(data->backing->grid, px, py, &gc);
1.204 nicm 2504: if (gc.flags & GRID_FLAG_PADDING)
2505: return (0);
2506: ud = &gc.data;
1.1 nicm 2507:
1.204 nicm 2508: copy = utf8_fromcstr(set);
2509: for (loop = copy; loop->size != 0; loop++) {
2510: if (loop->size != ud->size)
2511: continue;
2512: if (memcmp(loop->data, ud->data, loop->size) == 0) {
2513: found = 1;
2514: break;
2515: }
2516: }
2517: free(copy);
2518:
2519: return (found);
1.1 nicm 2520: }
2521:
1.157 nicm 2522: static u_int
1.208 nicm 2523: window_copy_find_length(struct window_mode_entry *wme, u_int py)
1.1 nicm 2524: {
1.208 nicm 2525: struct window_copy_mode_data *data = wme->data;
1.54 nicm 2526: struct screen *s = data->backing;
1.140 nicm 2527: struct grid_cell gc;
1.54 nicm 2528: u_int px;
1.1 nicm 2529:
1.4 nicm 2530: /*
2531: * If the pane has been resized, its grid can contain old overlong
2532: * lines. grid_peek_cell does not allow accessing cells beyond the
2533: * width of the grid, and screen_write_copy treats them as spaces, so
2534: * ignore them here too.
2535: */
1.190 nicm 2536: px = grid_get_line(s->grid, py)->cellsize;
1.54 nicm 2537: if (px > screen_size_x(s))
2538: px = screen_size_x(s);
1.1 nicm 2539: while (px > 0) {
1.140 nicm 2540: grid_get_cell(s->grid, px - 1, py, &gc);
2541: if (gc.data.size != 1 || *gc.data.data != ' ')
1.1 nicm 2542: break;
2543: px--;
2544: }
2545: return (px);
2546: }
2547:
1.157 nicm 2548: static void
1.208 nicm 2549: window_copy_cursor_start_of_line(struct window_mode_entry *wme)
1.5 nicm 2550: {
1.208 nicm 2551: struct window_copy_mode_data *data = wme->data;
1.58 nicm 2552: struct screen *back_s = data->backing;
2553: struct grid *gd = back_s->grid;
2554: u_int py;
2555:
1.192 nicm 2556: if (data->cx == 0 && data->lineflag == LINE_SEL_NONE) {
1.58 nicm 2557: py = screen_hsize(back_s) + data->cy - data->oy;
1.118 nicm 2558: while (py > 0 &&
1.190 nicm 2559: grid_get_line(gd, py - 1)->flags & GRID_LINE_WRAPPED) {
1.208 nicm 2560: window_copy_cursor_up(wme, 0);
1.58 nicm 2561: py = screen_hsize(back_s) + data->cy - data->oy;
2562: }
2563: }
1.208 nicm 2564: window_copy_update_cursor(wme, 0, data->cy);
2565: if (window_copy_update_selection(wme, 1))
2566: window_copy_redraw_lines(wme, data->cy, 1);
1.6 nicm 2567: }
2568:
1.157 nicm 2569: static void
1.208 nicm 2570: window_copy_cursor_back_to_indentation(struct window_mode_entry *wme)
1.6 nicm 2571: {
1.208 nicm 2572: struct window_copy_mode_data *data = wme->data;
1.6 nicm 2573: u_int px, py, xx;
1.140 nicm 2574: struct grid_cell gc;
1.6 nicm 2575:
2576: px = 0;
1.54 nicm 2577: py = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 2578: xx = window_copy_find_length(wme, py);
1.6 nicm 2579:
2580: while (px < xx) {
1.140 nicm 2581: grid_get_cell(data->backing->grid, px, py, &gc);
2582: if (gc.data.size != 1 || *gc.data.data != ' ')
1.6 nicm 2583: break;
2584: px++;
2585: }
2586:
1.208 nicm 2587: window_copy_update_cursor(wme, px, data->cy);
2588: if (window_copy_update_selection(wme, 1))
2589: window_copy_redraw_lines(wme, data->cy, 1);
1.5 nicm 2590: }
2591:
1.157 nicm 2592: static void
1.208 nicm 2593: window_copy_cursor_end_of_line(struct window_mode_entry *wme)
1.5 nicm 2594: {
1.208 nicm 2595: struct window_copy_mode_data *data = wme->data;
1.54 nicm 2596: struct screen *back_s = data->backing;
2597: struct grid *gd = back_s->grid;
1.190 nicm 2598: struct grid_line *gl;
1.5 nicm 2599: u_int px, py;
2600:
1.54 nicm 2601: py = screen_hsize(back_s) + data->cy - data->oy;
1.208 nicm 2602: px = window_copy_find_length(wme, py);
1.5 nicm 2603:
1.192 nicm 2604: if (data->cx == px && data->lineflag == LINE_SEL_NONE) {
2605: if (data->screen.sel != NULL && data->rectflag)
1.54 nicm 2606: px = screen_size_x(back_s);
1.190 nicm 2607: gl = grid_get_line(gd, py);
2608: if (gl->flags & GRID_LINE_WRAPPED) {
2609: while (py < gd->sy + gd->hsize) {
2610: gl = grid_get_line(gd, py);
2611: if (~gl->flags & GRID_LINE_WRAPPED)
2612: break;
1.208 nicm 2613: window_copy_cursor_down(wme, 0);
1.190 nicm 2614: py = screen_hsize(back_s) + data->cy - data->oy;
1.49 nicm 2615: }
1.208 nicm 2616: px = window_copy_find_length(wme, py);
1.49 nicm 2617: }
2618: }
1.208 nicm 2619: window_copy_update_cursor(wme, px, data->cy);
1.49 nicm 2620:
1.208 nicm 2621: if (window_copy_update_selection(wme, 1))
2622: window_copy_redraw_lines(wme, data->cy, 1);
1.95 nicm 2623: }
2624:
1.157 nicm 2625: static void
1.208 nicm 2626: window_copy_other_end(struct window_mode_entry *wme)
1.95 nicm 2627: {
1.208 nicm 2628: struct window_copy_mode_data *data = wme->data;
1.95 nicm 2629: struct screen *s = &data->screen;
1.161 nicm 2630: u_int selx, sely, cy, yy, hsize;
1.95 nicm 2631:
1.192 nicm 2632: if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
1.95 nicm 2633: return;
2634:
1.192 nicm 2635: if (data->lineflag == LINE_SEL_LEFT_RIGHT)
2636: data->lineflag = LINE_SEL_RIGHT_LEFT;
2637: else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
2638: data->lineflag = LINE_SEL_LEFT_RIGHT;
1.118 nicm 2639:
1.161 nicm 2640: switch (data->cursordrag) {
2641: case CURSORDRAG_NONE:
2642: case CURSORDRAG_SEL:
2643: data->cursordrag = CURSORDRAG_ENDSEL;
2644: break;
2645: case CURSORDRAG_ENDSEL:
2646: data->cursordrag = CURSORDRAG_SEL;
2647: break;
2648: }
2649:
2650: selx = data->endselx;
2651: sely = data->endsely;
2652: if (data->cursordrag == CURSORDRAG_SEL) {
2653: selx = data->selx;
2654: sely = data->sely;
2655: }
2656:
1.95 nicm 2657: cy = data->cy;
2658: yy = screen_hsize(data->backing) + data->cy - data->oy;
2659:
2660: data->cx = selx;
2661:
1.122 nicm 2662: hsize = screen_hsize(data->backing);
1.161 nicm 2663: if (sely < hsize - data->oy) { /* above */
1.122 nicm 2664: data->oy = hsize - sely;
1.95 nicm 2665: data->cy = 0;
1.161 nicm 2666: } else if (sely > hsize - data->oy + screen_size_y(s)) { /* below */
1.122 nicm 2667: data->oy = hsize - sely + screen_size_y(s) - 1;
1.95 nicm 2668: data->cy = screen_size_y(s) - 1;
2669: } else
2670: data->cy = cy + sely - yy;
2671:
1.208 nicm 2672: window_copy_update_selection(wme, 1);
2673: window_copy_redraw_screen(wme);
1.5 nicm 2674: }
2675:
1.157 nicm 2676: static void
1.208 nicm 2677: window_copy_cursor_left(struct window_mode_entry *wme)
1.1 nicm 2678: {
1.208 nicm 2679: struct window_copy_mode_data *data = wme->data;
1.168 nicm 2680: u_int py, cx;
2681: struct grid_cell gc;
1.1 nicm 2682:
1.145 nicm 2683: py = screen_hsize(data->backing) + data->cy - data->oy;
1.168 nicm 2684: cx = data->cx;
2685: while (cx > 0) {
2686: grid_get_cell(data->backing->grid, cx, py, &gc);
2687: if (~gc.flags & GRID_FLAG_PADDING)
2688: break;
2689: cx--;
2690: }
2691: if (cx == 0 && py > 0) {
1.208 nicm 2692: window_copy_cursor_up(wme, 0);
2693: window_copy_cursor_end_of_line(wme);
1.168 nicm 2694: } else if (cx > 0) {
1.208 nicm 2695: window_copy_update_cursor(wme, cx - 1, data->cy);
2696: if (window_copy_update_selection(wme, 1))
2697: window_copy_redraw_lines(wme, data->cy, 1);
1.1 nicm 2698: }
2699: }
2700:
1.157 nicm 2701: static void
1.208 nicm 2702: window_copy_cursor_right(struct window_mode_entry *wme)
1.1 nicm 2703: {
1.208 nicm 2704: struct window_copy_mode_data *data = wme->data;
1.168 nicm 2705: u_int px, py, yy, cx, cy;
2706: struct grid_cell gc;
1.1 nicm 2707:
1.145 nicm 2708: py = screen_hsize(data->backing) + data->cy - data->oy;
2709: yy = screen_hsize(data->backing) + screen_size_y(data->backing) - 1;
1.192 nicm 2710: if (data->screen.sel != NULL && data->rectflag)
1.47 nicm 2711: px = screen_size_x(&data->screen);
1.168 nicm 2712: else
1.208 nicm 2713: px = window_copy_find_length(wme, py);
1.1 nicm 2714:
1.145 nicm 2715: if (data->cx >= px && py < yy) {
1.208 nicm 2716: window_copy_cursor_start_of_line(wme);
2717: window_copy_cursor_down(wme, 0);
1.145 nicm 2718: } else if (data->cx < px) {
1.168 nicm 2719: cx = data->cx + 1;
2720: cy = screen_hsize(data->backing) + data->cy - data->oy;
2721: while (cx < px) {
2722: grid_get_cell(data->backing->grid, cx, cy, &gc);
2723: if (~gc.flags & GRID_FLAG_PADDING)
2724: break;
2725: cx++;
2726: }
1.208 nicm 2727: window_copy_update_cursor(wme, cx, data->cy);
2728: if (window_copy_update_selection(wme, 1))
2729: window_copy_redraw_lines(wme, data->cy, 1);
1.1 nicm 2730: }
2731: }
2732:
1.157 nicm 2733: static void
1.208 nicm 2734: window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only)
1.1 nicm 2735: {
1.208 nicm 2736: struct window_copy_mode_data *data = wme->data;
1.36 nicm 2737: struct screen *s = &data->screen;
1.1 nicm 2738: u_int ox, oy, px, py;
2739:
1.54 nicm 2740: oy = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 2741: ox = window_copy_find_length(wme, oy);
1.77 nicm 2742: if (data->cx != ox) {
1.25 nicm 2743: data->lastcx = data->cx;
2744: data->lastsx = ox;
2745: }
1.1 nicm 2746:
1.192 nicm 2747: if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
1.208 nicm 2748: window_copy_other_end(wme);
1.118 nicm 2749:
1.25 nicm 2750: data->cx = data->lastcx;
1.28 nicm 2751: if (scroll_only || data->cy == 0) {
1.208 nicm 2752: window_copy_scroll_down(wme, 1);
1.36 nicm 2753: if (scroll_only) {
2754: if (data->cy == screen_size_y(s) - 1)
1.208 nicm 2755: window_copy_redraw_lines(wme, data->cy, 1);
1.36 nicm 2756: else
1.208 nicm 2757: window_copy_redraw_lines(wme, data->cy, 2);
1.36 nicm 2758: }
1.28 nicm 2759: } else {
1.208 nicm 2760: window_copy_update_cursor(wme, data->cx, data->cy - 1);
2761: if (window_copy_update_selection(wme, 1)) {
1.36 nicm 2762: if (data->cy == screen_size_y(s) - 1)
1.208 nicm 2763: window_copy_redraw_lines(wme, data->cy, 1);
1.36 nicm 2764: else
1.208 nicm 2765: window_copy_redraw_lines(wme, data->cy, 2);
1.36 nicm 2766: }
1.1 nicm 2767: }
2768:
1.198 nicm 2769: if (data->screen.sel == NULL || !data->rectflag) {
1.54 nicm 2770: py = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 2771: px = window_copy_find_length(wme, py);
1.49 nicm 2772: if ((data->cx >= data->lastsx && data->cx != px) ||
2773: data->cx > px)
1.208 nicm 2774: window_copy_cursor_end_of_line(wme);
1.47 nicm 2775: }
1.118 nicm 2776:
1.192 nicm 2777: if (data->lineflag == LINE_SEL_LEFT_RIGHT)
1.208 nicm 2778: window_copy_cursor_end_of_line(wme);
1.192 nicm 2779: else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
1.208 nicm 2780: window_copy_cursor_start_of_line(wme);
1.1 nicm 2781: }
2782:
1.157 nicm 2783: static void
1.208 nicm 2784: window_copy_cursor_down(struct window_mode_entry *wme, int scroll_only)
1.1 nicm 2785: {
1.208 nicm 2786: struct window_copy_mode_data *data = wme->data;
1.1 nicm 2787: struct screen *s = &data->screen;
2788: u_int ox, oy, px, py;
2789:
1.54 nicm 2790: oy = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 2791: ox = window_copy_find_length(wme, oy);
1.77 nicm 2792: if (data->cx != ox) {
1.25 nicm 2793: data->lastcx = data->cx;
2794: data->lastsx = ox;
2795: }
1.1 nicm 2796:
1.192 nicm 2797: if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
1.208 nicm 2798: window_copy_other_end(wme);
1.118 nicm 2799:
1.25 nicm 2800: data->cx = data->lastcx;
1.28 nicm 2801: if (scroll_only || data->cy == screen_size_y(s) - 1) {
1.208 nicm 2802: window_copy_scroll_up(wme, 1);
1.31 nicm 2803: if (scroll_only && data->cy > 0)
1.208 nicm 2804: window_copy_redraw_lines(wme, data->cy - 1, 2);
1.28 nicm 2805: } else {
1.208 nicm 2806: window_copy_update_cursor(wme, data->cx, data->cy + 1);
2807: if (window_copy_update_selection(wme, 1))
2808: window_copy_redraw_lines(wme, data->cy - 1, 2);
1.1 nicm 2809: }
2810:
1.192 nicm 2811: if (data->screen.sel == NULL || !data->rectflag) {
1.54 nicm 2812: py = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 2813: px = window_copy_find_length(wme, py);
1.49 nicm 2814: if ((data->cx >= data->lastsx && data->cx != px) ||
2815: data->cx > px)
1.208 nicm 2816: window_copy_cursor_end_of_line(wme);
1.52 nicm 2817: }
1.118 nicm 2818:
1.192 nicm 2819: if (data->lineflag == LINE_SEL_LEFT_RIGHT)
1.208 nicm 2820: window_copy_cursor_end_of_line(wme);
1.192 nicm 2821: else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
1.208 nicm 2822: window_copy_cursor_start_of_line(wme);
1.52 nicm 2823: }
2824:
1.157 nicm 2825: static void
1.208 nicm 2826: window_copy_cursor_jump(struct window_mode_entry *wme)
1.52 nicm 2827: {
1.208 nicm 2828: struct window_copy_mode_data *data = wme->data;
1.54 nicm 2829: struct screen *back_s = data->backing;
1.140 nicm 2830: struct grid_cell gc;
1.67 nicm 2831: u_int px, py, xx;
1.52 nicm 2832:
2833: px = data->cx + 1;
1.54 nicm 2834: py = screen_hsize(back_s) + data->cy - data->oy;
1.208 nicm 2835: xx = window_copy_find_length(wme, py);
1.52 nicm 2836:
2837: while (px < xx) {
1.140 nicm 2838: grid_get_cell(back_s->grid, px, py, &gc);
2839: if (!(gc.flags & GRID_FLAG_PADDING) &&
2840: gc.data.size == 1 && *gc.data.data == data->jumpchar) {
1.208 nicm 2841: window_copy_update_cursor(wme, px, data->cy);
2842: if (window_copy_update_selection(wme, 1))
2843: window_copy_redraw_lines(wme, data->cy, 1);
1.52 nicm 2844: return;
2845: }
2846: px++;
2847: }
2848: }
2849:
1.157 nicm 2850: static void
1.208 nicm 2851: window_copy_cursor_jump_back(struct window_mode_entry *wme)
1.52 nicm 2852: {
1.208 nicm 2853: struct window_copy_mode_data *data = wme->data;
1.54 nicm 2854: struct screen *back_s = data->backing;
1.140 nicm 2855: struct grid_cell gc;
1.67 nicm 2856: u_int px, py;
1.52 nicm 2857:
2858: px = data->cx;
1.54 nicm 2859: py = screen_hsize(back_s) + data->cy - data->oy;
1.52 nicm 2860:
2861: if (px > 0)
2862: px--;
2863:
2864: for (;;) {
1.140 nicm 2865: grid_get_cell(back_s->grid, px, py, &gc);
2866: if (!(gc.flags & GRID_FLAG_PADDING) &&
2867: gc.data.size == 1 && *gc.data.data == data->jumpchar) {
1.208 nicm 2868: window_copy_update_cursor(wme, px, data->cy);
2869: if (window_copy_update_selection(wme, 1))
2870: window_copy_redraw_lines(wme, data->cy, 1);
1.76 nicm 2871: return;
2872: }
2873: if (px == 0)
2874: break;
2875: px--;
2876: }
2877: }
2878:
1.157 nicm 2879: static void
1.208 nicm 2880: window_copy_cursor_jump_to(struct window_mode_entry *wme)
1.76 nicm 2881: {
1.208 nicm 2882: struct window_copy_mode_data *data = wme->data;
1.76 nicm 2883: struct screen *back_s = data->backing;
1.140 nicm 2884: struct grid_cell gc;
1.76 nicm 2885: u_int px, py, xx;
2886:
1.184 nicm 2887: px = data->cx + 2;
1.76 nicm 2888: py = screen_hsize(back_s) + data->cy - data->oy;
1.208 nicm 2889: xx = window_copy_find_length(wme, py);
1.76 nicm 2890:
2891: while (px < xx) {
1.140 nicm 2892: grid_get_cell(back_s->grid, px, py, &gc);
2893: if (!(gc.flags & GRID_FLAG_PADDING) &&
2894: gc.data.size == 1 && *gc.data.data == data->jumpchar) {
1.208 nicm 2895: window_copy_update_cursor(wme, px - 1, data->cy);
2896: if (window_copy_update_selection(wme, 1))
2897: window_copy_redraw_lines(wme, data->cy, 1);
1.76 nicm 2898: return;
2899: }
2900: px++;
2901: }
2902: }
2903:
1.157 nicm 2904: static void
1.208 nicm 2905: window_copy_cursor_jump_to_back(struct window_mode_entry *wme)
1.76 nicm 2906: {
1.208 nicm 2907: struct window_copy_mode_data *data = wme->data;
1.76 nicm 2908: struct screen *back_s = data->backing;
1.140 nicm 2909: struct grid_cell gc;
1.76 nicm 2910: u_int px, py;
2911:
2912: px = data->cx;
2913: py = screen_hsize(back_s) + data->cy - data->oy;
2914:
2915: if (px > 0)
1.127 nicm 2916: px--;
2917:
1.184 nicm 2918: if (px > 0)
1.76 nicm 2919: px--;
2920:
2921: for (;;) {
1.140 nicm 2922: grid_get_cell(back_s->grid, px, py, &gc);
2923: if (!(gc.flags & GRID_FLAG_PADDING) &&
2924: gc.data.size == 1 && *gc.data.data == data->jumpchar) {
1.208 nicm 2925: window_copy_update_cursor(wme, px + 1, data->cy);
2926: if (window_copy_update_selection(wme, 1))
2927: window_copy_redraw_lines(wme, data->cy, 1);
1.52 nicm 2928: return;
2929: }
2930: if (px == 0)
2931: break;
2932: px--;
1.47 nicm 2933: }
1.1 nicm 2934: }
2935:
1.157 nicm 2936: static void
1.208 nicm 2937: window_copy_cursor_next_word(struct window_mode_entry *wme,
2938: const char *separators)
1.40 nicm 2939: {
1.208 nicm 2940: struct window_copy_mode_data *data = wme->data;
1.54 nicm 2941: struct screen *back_s = data->backing;
1.40 nicm 2942: u_int px, py, xx, yy;
1.48 nicm 2943: int expected = 0;
1.40 nicm 2944:
2945: px = data->cx;
1.54 nicm 2946: py = screen_hsize(back_s) + data->cy - data->oy;
1.208 nicm 2947: xx = window_copy_find_length(wme, py);
1.54 nicm 2948: yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
1.40 nicm 2949:
1.48 nicm 2950: /*
2951: * First skip past any nonword characters and then any word characters.
2952: *
2953: * expected is initially set to 0 for the former and then 1 for the
2954: * latter.
2955: */
2956: do {
2957: while (px > xx ||
1.208 nicm 2958: window_copy_in_set(wme, px, py, separators) == expected) {
1.48 nicm 2959: /* Move down if we're past the end of the line. */
2960: if (px > xx) {
2961: if (py == yy)
2962: return;
1.208 nicm 2963: window_copy_cursor_down(wme, 0);
1.48 nicm 2964: px = 0;
2965:
1.54 nicm 2966: py = screen_hsize(back_s) + data->cy - data->oy;
1.208 nicm 2967: xx = window_copy_find_length(wme, py);
1.48 nicm 2968: } else
2969: px++;
2970: }
2971: expected = !expected;
2972: } while (expected == 1);
1.40 nicm 2973:
1.208 nicm 2974: window_copy_update_cursor(wme, px, data->cy);
2975: if (window_copy_update_selection(wme, 1))
2976: window_copy_redraw_lines(wme, data->cy, 1);
1.40 nicm 2977: }
2978:
1.157 nicm 2979: static void
1.208 nicm 2980: window_copy_cursor_next_word_end(struct window_mode_entry *wme,
1.106 nicm 2981: const char *separators)
1.1 nicm 2982: {
1.208 nicm 2983: struct window_pane *wp = wme->wp;
2984: struct window_copy_mode_data *data = wme->data;
1.136 nicm 2985: struct options *oo = wp->window->options;
1.54 nicm 2986: struct screen *back_s = data->backing;
1.39 nicm 2987: u_int px, py, xx, yy;
1.94 nicm 2988: int keys, expected = 1;
1.1 nicm 2989:
1.18 nicm 2990: px = data->cx;
1.54 nicm 2991: py = screen_hsize(back_s) + data->cy - data->oy;
1.208 nicm 2992: xx = window_copy_find_length(wme, py);
1.54 nicm 2993: yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
1.1 nicm 2994:
1.94 nicm 2995: keys = options_get_number(oo, "mode-keys");
1.208 nicm 2996: if (keys == MODEKEY_VI && !window_copy_in_set(wme, px, py, separators))
1.94 nicm 2997: px++;
2998:
1.48 nicm 2999: /*
3000: * First skip past any word characters, then any nonword characters.
3001: *
3002: * expected is initially set to 1 for the former and then 0 for the
3003: * latter.
3004: */
3005: do {
3006: while (px > xx ||
1.208 nicm 3007: window_copy_in_set(wme, px, py, separators) == expected) {
1.48 nicm 3008: /* Move down if we're past the end of the line. */
3009: if (px > xx) {
3010: if (py == yy)
3011: return;
1.208 nicm 3012: window_copy_cursor_down(wme, 0);
1.48 nicm 3013: px = 0;
3014:
1.54 nicm 3015: py = screen_hsize(back_s) + data->cy - data->oy;
1.208 nicm 3016: xx = window_copy_find_length(wme, py);
1.48 nicm 3017: } else
3018: px++;
3019: }
3020: expected = !expected;
3021: } while (expected == 0);
1.92 nicm 3022:
1.94 nicm 3023: if (keys == MODEKEY_VI && px != 0)
1.92 nicm 3024: px--;
1.18 nicm 3025:
1.208 nicm 3026: window_copy_update_cursor(wme, px, data->cy);
3027: if (window_copy_update_selection(wme, 1))
3028: window_copy_redraw_lines(wme, data->cy, 1);
1.1 nicm 3029: }
3030:
1.8 nicm 3031: /* Move to the previous place where a word begins. */
1.157 nicm 3032: static void
1.208 nicm 3033: window_copy_cursor_previous_word(struct window_mode_entry *wme,
1.106 nicm 3034: const char *separators)
1.1 nicm 3035: {
1.208 nicm 3036: struct window_copy_mode_data *data = wme->data;
1.8 nicm 3037: u_int px, py;
1.1 nicm 3038:
1.18 nicm 3039: px = data->cx;
1.54 nicm 3040: py = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 3041:
1.8 nicm 3042: /* Move back to the previous word character. */
1.1 nicm 3043: for (;;) {
1.8 nicm 3044: if (px > 0) {
3045: px--;
1.208 nicm 3046: if (!window_copy_in_set(wme, px, py, separators))
1.1 nicm 3047: break;
1.8 nicm 3048: } else {
3049: if (data->cy == 0 &&
1.54 nicm 3050: (screen_hsize(data->backing) == 0 ||
3051: data->oy >= screen_hsize(data->backing) - 1))
1.8 nicm 3052: goto out;
1.208 nicm 3053: window_copy_cursor_up(wme, 0);
1.1 nicm 3054:
1.54 nicm 3055: py = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 3056: px = window_copy_find_length(wme, py);
1.1 nicm 3057: }
1.8 nicm 3058: }
1.1 nicm 3059:
1.8 nicm 3060: /* Move back to the beginning of this word. */
1.208 nicm 3061: while (px > 0 && !window_copy_in_set(wme, px - 1, py, separators))
1.1 nicm 3062: px--;
1.8 nicm 3063:
1.1 nicm 3064: out:
1.208 nicm 3065: window_copy_update_cursor(wme, px, data->cy);
3066: if (window_copy_update_selection(wme, 1))
3067: window_copy_redraw_lines(wme, data->cy, 1);
1.1 nicm 3068: }
3069:
1.157 nicm 3070: static void
1.208 nicm 3071: window_copy_scroll_up(struct window_mode_entry *wme, u_int ny)
1.1 nicm 3072: {
1.208 nicm 3073: struct window_pane *wp = wme->wp;
3074: struct window_copy_mode_data *data = wme->data;
1.1 nicm 3075: struct screen *s = &data->screen;
3076: struct screen_write_ctx ctx;
3077:
3078: if (data->oy < ny)
3079: ny = data->oy;
3080: if (ny == 0)
3081: return;
3082: data->oy -= ny;
3083:
1.208 nicm 3084: window_copy_update_selection(wme, 0);
1.96 nicm 3085:
1.1 nicm 3086: screen_write_start(&ctx, wp, NULL);
1.212 nicm 3087: screen_write_cursormove(&ctx, 0, 0, 0);
1.159 nicm 3088: screen_write_deleteline(&ctx, ny, 8);
1.208 nicm 3089: window_copy_write_lines(wme, &ctx, screen_size_y(s) - ny, ny);
3090: window_copy_write_line(wme, &ctx, 0);
1.31 nicm 3091: if (screen_size_y(s) > 1)
1.208 nicm 3092: window_copy_write_line(wme, &ctx, 1);
1.31 nicm 3093: if (screen_size_y(s) > 3)
1.208 nicm 3094: window_copy_write_line(wme, &ctx, screen_size_y(s) - 2);
1.192 nicm 3095: if (s->sel != NULL && screen_size_y(s) > ny)
1.208 nicm 3096: window_copy_write_line(wme, &ctx, screen_size_y(s) - ny - 1);
1.212 nicm 3097: screen_write_cursormove(&ctx, data->cx, data->cy, 0);
1.1 nicm 3098: screen_write_stop(&ctx);
3099: }
3100:
1.157 nicm 3101: static void
1.208 nicm 3102: window_copy_scroll_down(struct window_mode_entry *wme, u_int ny)
1.1 nicm 3103: {
1.208 nicm 3104: struct window_pane *wp = wme->wp;
3105: struct window_copy_mode_data *data = wme->data;
1.1 nicm 3106: struct screen *s = &data->screen;
3107: struct screen_write_ctx ctx;
3108:
1.54 nicm 3109: if (ny > screen_hsize(data->backing))
1.1 nicm 3110: return;
3111:
1.54 nicm 3112: if (data->oy > screen_hsize(data->backing) - ny)
3113: ny = screen_hsize(data->backing) - data->oy;
1.1 nicm 3114: if (ny == 0)
3115: return;
3116: data->oy += ny;
3117:
1.208 nicm 3118: window_copy_update_selection(wme, 0);
1.96 nicm 3119:
1.1 nicm 3120: screen_write_start(&ctx, wp, NULL);
1.212 nicm 3121: screen_write_cursormove(&ctx, 0, 0, 0);
1.159 nicm 3122: screen_write_insertline(&ctx, ny, 8);
1.208 nicm 3123: window_copy_write_lines(wme, &ctx, 0, ny);
1.192 nicm 3124: if (s->sel != NULL && screen_size_y(s) > ny)
1.208 nicm 3125: window_copy_write_line(wme, &ctx, ny);
1.96 nicm 3126: else if (ny == 1) /* nuke position */
1.208 nicm 3127: window_copy_write_line(wme, &ctx, 1);
1.212 nicm 3128: screen_write_cursormove(&ctx, data->cx, data->cy, 0);
1.1 nicm 3129: screen_write_stop(&ctx);
3130: }
1.42 nicm 3131:
1.157 nicm 3132: static void
1.208 nicm 3133: window_copy_rectangle_toggle(struct window_mode_entry *wme)
1.42 nicm 3134: {
1.208 nicm 3135: struct window_copy_mode_data *data = wme->data;
1.47 nicm 3136: u_int px, py;
1.42 nicm 3137:
3138: data->rectflag = !data->rectflag;
1.47 nicm 3139:
1.54 nicm 3140: py = screen_hsize(data->backing) + data->cy - data->oy;
1.208 nicm 3141: px = window_copy_find_length(wme, py);
1.47 nicm 3142: if (data->cx > px)
1.208 nicm 3143: window_copy_update_cursor(wme, px, data->cy);
1.42 nicm 3144:
1.208 nicm 3145: window_copy_update_selection(wme, 1);
3146: window_copy_redraw_screen(wme);
1.156 nicm 3147: }
3148:
1.157 nicm 3149: static void
1.156 nicm 3150: window_copy_move_mouse(struct mouse_event *m)
3151: {
1.211 nicm 3152: struct window_pane *wp;
3153: struct window_mode_entry *wme;
3154: u_int x, y;
1.156 nicm 3155:
3156: wp = cmd_mouse_pane(m, NULL, NULL);
1.211 nicm 3157: if (wp == NULL)
3158: return;
3159: wme = TAILQ_FIRST(&wp->modes);
3160: if (wme == NULL || wme->mode != &window_copy_mode)
1.156 nicm 3161: return;
3162:
1.183 nicm 3163: if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
1.156 nicm 3164: return;
3165:
1.211 nicm 3166: window_copy_update_cursor(wme, x, y);
1.126 nicm 3167: }
3168:
3169: void
1.141 nicm 3170: window_copy_start_drag(struct client *c, struct mouse_event *m)
1.126 nicm 3171: {
1.211 nicm 3172: struct window_pane *wp;
3173: struct window_mode_entry *wme;
3174: u_int x, y;
1.126 nicm 3175:
1.155 nicm 3176: if (c == NULL)
3177: return;
3178:
1.126 nicm 3179: wp = cmd_mouse_pane(m, NULL, NULL);
1.211 nicm 3180: if (wp == NULL)
3181: return;
3182: wme = TAILQ_FIRST(&wp->modes);
3183: if (wme == NULL || wme->mode != &window_copy_mode)
1.126 nicm 3184: return;
3185:
3186: if (cmd_mouse_at(wp, m, &x, &y, 1) != 0)
3187: return;
3188:
3189: c->tty.mouse_drag_update = window_copy_drag_update;
1.155 nicm 3190: c->tty.mouse_drag_release = NULL; /* will fire MouseDragEnd key */
1.126 nicm 3191:
1.211 nicm 3192: window_copy_update_cursor(wme, x, y);
3193: window_copy_start_selection(wme);
3194: window_copy_redraw_screen(wme);
1.126 nicm 3195: }
3196:
1.157 nicm 3197: static void
1.211 nicm 3198: window_copy_drag_update(struct client *c, struct mouse_event *m)
1.126 nicm 3199: {
3200: struct window_pane *wp;
1.211 nicm 3201: struct window_mode_entry *wme;
1.126 nicm 3202: struct window_copy_mode_data *data;
3203: u_int x, y, old_cy;
3204:
1.211 nicm 3205: if (c == NULL)
3206: return;
3207:
1.126 nicm 3208: wp = cmd_mouse_pane(m, NULL, NULL);
1.211 nicm 3209: if (wp == NULL)
1.126 nicm 3210: return;
1.211 nicm 3211: wme = TAILQ_FIRST(&wp->modes);
3212: if (wme == NULL || wme->mode != &window_copy_mode)
3213: return;
3214: data = wme->data;
1.126 nicm 3215:
3216: if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
3217: return;
3218: old_cy = data->cy;
3219:
1.211 nicm 3220: window_copy_update_cursor(wme, x, y);
3221: if (window_copy_update_selection(wme, 1))
3222: window_copy_redraw_selection(wme, old_cy);
1.42 nicm 3223: }