Annotation of src/usr.bin/tmux/window-copy.c, Revision 1.192
1.192 ! nicm 1: /* $OpenBSD: window-copy.c,v 1.191 2018/07/06 07:11:23 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.157 nicm 27: static const char *window_copy_key_table(struct window_pane *);
28: static void window_copy_command(struct window_pane *, struct client *,
29: struct session *, struct args *, struct mouse_event *);
1.177 nicm 30: static struct screen *window_copy_init(struct window_pane *,
31: struct cmd_find_state *, struct args *);
1.157 nicm 32: static void window_copy_free(struct window_pane *);
1.186 nicm 33: static int window_copy_pagedown(struct window_pane *, int, int);
1.157 nicm 34: static void window_copy_next_paragraph(struct window_pane *);
35: static void window_copy_previous_paragraph(struct window_pane *);
36: static void window_copy_resize(struct window_pane *, u_int, u_int);
37:
38: static void window_copy_redraw_selection(struct window_pane *, u_int);
39: static void window_copy_redraw_lines(struct window_pane *, u_int, u_int);
40: static void window_copy_redraw_screen(struct window_pane *);
41: static void window_copy_write_line(struct window_pane *,
42: struct screen_write_ctx *, u_int);
43: static void window_copy_write_lines(struct window_pane *,
44: struct screen_write_ctx *, u_int, u_int);
45:
46: static void window_copy_scroll_to(struct window_pane *, u_int, u_int);
47: static int window_copy_search_compare(struct grid *, u_int, u_int,
48: struct grid *, u_int, int);
49: static int window_copy_search_lr(struct grid *, struct grid *, u_int *,
50: u_int, u_int, u_int, int);
51: static int window_copy_search_rl(struct grid *, struct grid *, u_int *,
52: u_int, u_int, u_int, int);
1.162 nicm 53: static int window_copy_search_marks(struct window_pane *, struct screen *);
1.163 nicm 54: static void window_copy_clear_marks(struct window_pane *);
1.157 nicm 55: static void window_copy_move_left(struct screen *, u_int *, u_int *);
56: static void window_copy_move_right(struct screen *, u_int *, u_int *);
57: static int window_copy_is_lowercase(const char *);
1.163 nicm 58: static int window_copy_search_jump(struct window_pane *, struct grid *,
1.157 nicm 59: struct grid *, u_int, u_int, u_int, int, int, int);
1.184 nicm 60: static int window_copy_search(struct window_pane *, int);
61: static int window_copy_search_up(struct window_pane *);
62: static int window_copy_search_down(struct window_pane *);
1.157 nicm 63: static void window_copy_goto_line(struct window_pane *, const char *);
64: static void window_copy_update_cursor(struct window_pane *, u_int, u_int);
65: static void window_copy_start_selection(struct window_pane *);
1.161 nicm 66: static int window_copy_adjust_selection(struct window_pane *, u_int *,
67: u_int *);
1.192 ! nicm 68: static int window_copy_set_selection(struct window_pane *, int);
1.157 nicm 69: static int window_copy_update_selection(struct window_pane *, int);
1.192 ! nicm 70: static void window_copy_synchronize_cursor(struct window_pane *);
1.160 nicm 71: static void *window_copy_get_selection(struct window_pane *, size_t *);
1.157 nicm 72: static void window_copy_copy_buffer(struct window_pane *, const char *,
73: void *, size_t);
74: static void window_copy_copy_pipe(struct window_pane *, struct session *,
75: const char *, const char *);
76: static void window_copy_copy_selection(struct window_pane *, const char *);
77: static void window_copy_append_selection(struct window_pane *,
78: const char *);
79: static void window_copy_clear_selection(struct window_pane *);
80: static void window_copy_copy_line(struct window_pane *, char **, size_t *,
81: u_int, u_int, u_int);
82: static int window_copy_in_set(struct window_pane *, u_int, u_int,
83: const char *);
84: static u_int window_copy_find_length(struct window_pane *, u_int);
85: static void window_copy_cursor_start_of_line(struct window_pane *);
86: static void window_copy_cursor_back_to_indentation(struct window_pane *);
87: static void window_copy_cursor_end_of_line(struct window_pane *);
88: static void window_copy_other_end(struct window_pane *);
89: static void window_copy_cursor_left(struct window_pane *);
90: static void window_copy_cursor_right(struct window_pane *);
91: static void window_copy_cursor_up(struct window_pane *, int);
92: static void window_copy_cursor_down(struct window_pane *, int);
93: static void window_copy_cursor_jump(struct window_pane *);
94: static void window_copy_cursor_jump_back(struct window_pane *);
1.184 nicm 95: static void window_copy_cursor_jump_to(struct window_pane *);
96: static void window_copy_cursor_jump_to_back(struct window_pane *);
1.157 nicm 97: static void window_copy_cursor_next_word(struct window_pane *,
98: const char *);
99: static void window_copy_cursor_next_word_end(struct window_pane *,
100: const char *);
101: static void window_copy_cursor_previous_word(struct window_pane *,
102: const char *);
103: static void window_copy_scroll_up(struct window_pane *, u_int);
104: static void window_copy_scroll_down(struct window_pane *, u_int);
105: static void window_copy_rectangle_toggle(struct window_pane *);
106: static void window_copy_move_mouse(struct mouse_event *);
107: static void window_copy_drag_update(struct client *, struct mouse_event *);
1.1 nicm 108:
109: const struct window_mode window_copy_mode = {
1.173 nicm 110: .name = "copy-mode",
111:
1.155 nicm 112: .init = window_copy_init,
113: .free = window_copy_free,
114: .resize = window_copy_resize,
115: .key_table = window_copy_key_table,
116: .command = window_copy_command,
1.1 nicm 117: };
118:
1.155 nicm 119: enum {
1.21 nicm 120: WINDOW_COPY_OFF,
121: WINDOW_COPY_SEARCHUP,
122: WINDOW_COPY_SEARCHDOWN,
1.52 nicm 123: WINDOW_COPY_JUMPFORWARD,
1.155 nicm 124: WINDOW_COPY_JUMPBACKWARD,
1.76 nicm 125: WINDOW_COPY_JUMPTOFORWARD,
1.155 nicm 126: WINDOW_COPY_JUMPTOBACKWARD,
1.21 nicm 127: };
128:
1.161 nicm 129: enum {
130: WINDOW_COPY_REL_POS_ABOVE,
131: WINDOW_COPY_REL_POS_ON_SCREEN,
132: WINDOW_COPY_REL_POS_BELOW,
133: };
134:
1.54 nicm 135: /*
1.161 nicm 136: * Copy mode's visible screen (the "screen" field) is filled from one of two
137: * sources: the original contents of the pane (used when we actually enter via
138: * the "copy-mode" command, to copy the contents of the current pane), or else
139: * a series of lines containing the output from an output-writing tmux command
140: * (such as any of the "show-*" or "list-*" commands).
1.54 nicm 141: *
1.161 nicm 142: * In either case, the full content of the copy-mode grid is pointed at by the
143: * "backing" field, and is copied into "screen" as needed (that is, when
144: * scrolling occurs). When copy-mode is backed by a pane, backing points
145: * directly at that pane's screen structure (&wp->base); when backed by a list
146: * of output-lines from a command, it points at a newly-allocated screen
147: * structure (which is deallocated when the mode ends).
1.54 nicm 148: */
1.1 nicm 149: struct window_copy_mode_data {
1.155 nicm 150: struct screen screen;
1.1 nicm 151:
1.155 nicm 152: struct screen *backing;
153: int backing_written; /* backing display started */
1.54 nicm 154:
1.192 ! nicm 155: u_int oy; /* number of lines scrolled up */
1.21 nicm 156:
1.192 ! nicm 157: u_int selx; /* beginning of selection */
1.155 nicm 158: u_int sely;
1.21 nicm 159:
1.192 ! nicm 160: u_int endselx; /* end of selection */
1.161 nicm 161: u_int endsely;
162:
163: enum {
164: CURSORDRAG_NONE, /* selection is independent of cursor */
165: CURSORDRAG_ENDSEL, /* end is synchronized with cursor */
166: CURSORDRAG_SEL, /* start is synchronized with cursor */
167: } cursordrag;
168:
1.192 ! nicm 169: int modekeys;
! 170: enum {
! 171: LINE_SEL_NONE,
! 172: LINE_SEL_LEFT_RIGHT,
! 173: LINE_SEL_RIGHT_LEFT,
! 174: } lineflag; /* line selection mode */
1.155 nicm 175: int rectflag; /* in rectangle copy mode? */
176: int scroll_exit; /* exit on scroll to end? */
1.1 nicm 177:
1.155 nicm 178: u_int cx;
179: u_int cy;
1.42 nicm 180:
1.192 ! nicm 181: u_int lastcx; /* position in last line w/ content */
! 182: u_int lastsx; /* size of last line w/ content */
1.1 nicm 183:
1.155 nicm 184: int searchtype;
185: char *searchstr;
1.162 nicm 186: bitstr_t *searchmark;
1.170 nicm 187: u_int searchcount;
188: int searchthis;
1.163 nicm 189: int searchx;
190: int searchy;
191: int searcho;
1.25 nicm 192:
1.155 nicm 193: int jumptype;
194: char jumpchar;
1.1 nicm 195: };
196:
1.157 nicm 197: static struct screen *
1.177 nicm 198: window_copy_init(struct window_pane *wp, __unused struct cmd_find_state *fs,
199: __unused struct args *args)
1.1 nicm 200: {
201: struct window_copy_mode_data *data;
202: struct screen *s;
203:
204: wp->modedata = data = xmalloc(sizeof *data);
1.162 nicm 205:
1.1 nicm 206: data->oy = 0;
1.54 nicm 207: data->cx = 0;
208: data->cy = 0;
1.1 nicm 209:
1.161 nicm 210: data->cursordrag = CURSORDRAG_NONE;
211:
1.25 nicm 212: data->lastcx = 0;
213: data->lastsx = 0;
214:
1.54 nicm 215: data->backing_written = 0;
216:
1.42 nicm 217: data->rectflag = 0;
1.133 nicm 218: data->scroll_exit = 0;
1.42 nicm 219:
1.174 nicm 220: if (wp->searchstr != NULL) {
221: data->searchtype = WINDOW_COPY_SEARCHUP;
222: data->searchstr = xstrdup(wp->searchstr);
223: } else {
224: data->searchtype = WINDOW_COPY_OFF;
225: data->searchstr = NULL;
226: }
1.162 nicm 227: data->searchmark = NULL;
1.163 nicm 228: data->searchx = data->searchy = data->searcho = -1;
1.21 nicm 229:
1.61 nicm 230: if (wp->fd != -1)
231: bufferevent_disable(wp->event, EV_READ|EV_WRITE);
1.46 nicm 232:
1.52 nicm 233: data->jumptype = WINDOW_COPY_OFF;
234: data->jumpchar = '\0';
235:
1.1 nicm 236: s = &data->screen;
237: screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
1.192 ! nicm 238: data->modekeys = options_get_number(wp->window->options, "mode-keys");
1.1 nicm 239:
1.54 nicm 240: data->backing = NULL;
241:
242: return (s);
243: }
244:
245: void
1.134 nicm 246: window_copy_init_from_pane(struct window_pane *wp, int scroll_exit)
1.54 nicm 247: {
248: struct window_copy_mode_data *data = wp->modedata;
249: struct screen *s = &data->screen;
250: struct screen_write_ctx ctx;
251: u_int i;
252:
253: if (wp->mode != &window_copy_mode)
254: fatalx("not in copy mode");
255:
256: data->backing = &wp->base;
257: data->cx = data->backing->cx;
258: data->cy = data->backing->cy;
1.133 nicm 259: data->scroll_exit = scroll_exit;
1.54 nicm 260:
1.1 nicm 261: s->cx = data->cx;
262: s->cy = data->cy;
263:
264: screen_write_start(&ctx, NULL, s);
265: for (i = 0; i < screen_size_y(s); i++)
266: window_copy_write_line(wp, &ctx, i);
267: screen_write_cursormove(&ctx, data->cx, data->cy);
268: screen_write_stop(&ctx);
1.54 nicm 269: }
1.1 nicm 270:
1.54 nicm 271: void
272: window_copy_init_for_output(struct window_pane *wp)
273: {
274: struct window_copy_mode_data *data = wp->modedata;
275:
276: data->backing = xmalloc(sizeof *data->backing);
277: screen_init(data->backing, screen_size_x(&wp->base),
278: screen_size_y(&wp->base), UINT_MAX);
1.1 nicm 279: }
280:
1.157 nicm 281: static void
1.1 nicm 282: window_copy_free(struct window_pane *wp)
283: {
284: struct window_copy_mode_data *data = wp->modedata;
1.46 nicm 285:
1.61 nicm 286: if (wp->fd != -1)
287: bufferevent_enable(wp->event, EV_READ|EV_WRITE);
1.1 nicm 288:
1.162 nicm 289: free(data->searchmark);
1.81 nicm 290: free(data->searchstr);
1.21 nicm 291:
1.54 nicm 292: if (data->backing != &wp->base) {
293: screen_free(data->backing);
1.81 nicm 294: free(data->backing);
1.54 nicm 295: }
1.1 nicm 296: screen_free(&data->screen);
1.21 nicm 297:
1.81 nicm 298: free(data);
1.1 nicm 299: }
300:
301: void
1.54 nicm 302: window_copy_add(struct window_pane *wp, const char *fmt, ...)
303: {
304: va_list ap;
305:
306: va_start(ap, fmt);
307: window_copy_vadd(wp, fmt, ap);
308: va_end(ap);
309: }
310:
311: void
312: window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap)
313: {
314: struct window_copy_mode_data *data = wp->modedata;
315: struct screen *backing = data->backing;
316: struct screen_write_ctx back_ctx, ctx;
317: struct grid_cell gc;
1.119 nicm 318: u_int old_hsize, old_cy;
1.54 nicm 319:
320: if (backing == &wp->base)
321: return;
322:
323: memcpy(&gc, &grid_default_cell, sizeof gc);
324:
325: old_hsize = screen_hsize(data->backing);
326: screen_write_start(&back_ctx, NULL, backing);
327: if (data->backing_written) {
328: /*
329: * On the second or later line, do a CRLF before writing
330: * (so it's on a new line).
331: */
332: screen_write_carriagereturn(&back_ctx);
1.175 nicm 333: screen_write_linefeed(&back_ctx, 0, 8);
1.54 nicm 334: } else
335: data->backing_written = 1;
1.119 nicm 336: old_cy = backing->cy;
1.139 nicm 337: screen_write_vnputs(&back_ctx, 0, &gc, fmt, ap);
1.54 nicm 338: screen_write_stop(&back_ctx);
339:
340: data->oy += screen_hsize(data->backing) - old_hsize;
341:
342: screen_write_start(&ctx, wp, &data->screen);
343:
344: /*
345: * If the history has changed, draw the top line.
346: * (If there's any history at all, it has changed.)
347: */
348: if (screen_hsize(data->backing))
349: window_copy_redraw_lines(wp, 0, 1);
350:
1.119 nicm 351: /* Write the new lines. */
352: window_copy_redraw_lines(wp, old_cy, backing->cy - old_cy + 1);
1.54 nicm 353:
354: screen_write_stop(&ctx);
355: }
356:
357: void
1.149 nicm 358: window_copy_pageup(struct window_pane *wp, int half_page)
1.1 nicm 359: {
360: struct window_copy_mode_data *data = wp->modedata;
361: struct screen *s = &data->screen;
1.162 nicm 362: u_int n, ox, oy, px, py;
1.147 nicm 363:
364: oy = screen_hsize(data->backing) + data->cy - data->oy;
365: ox = window_copy_find_length(wp, oy);
366:
1.192 ! nicm 367: if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
1.147 nicm 368: window_copy_other_end(wp);
369:
370: if (data->cx != ox) {
371: data->lastcx = data->cx;
372: data->lastsx = ox;
373: }
374: data->cx = data->lastcx;
1.1 nicm 375:
1.19 nicm 376: n = 1;
1.149 nicm 377: if (screen_size_y(s) > 2) {
378: if (half_page)
379: n = screen_size_y(s) / 2;
380: else
381: n = screen_size_y(s) - 2;
382: }
1.147 nicm 383:
1.54 nicm 384: if (data->oy + n > screen_hsize(data->backing))
385: data->oy = screen_hsize(data->backing);
1.1 nicm 386: else
1.19 nicm 387: data->oy += n;
1.147 nicm 388:
1.192 ! nicm 389: if (data->screen.sel == NULL || !data->rectflag) {
1.162 nicm 390: py = screen_hsize(data->backing) + data->cy - data->oy;
391: px = window_copy_find_length(wp, py);
392: if ((data->cx >= data->lastsx && data->cx != px) ||
393: data->cx > px)
1.147 nicm 394: window_copy_cursor_end_of_line(wp);
395: }
396:
397: window_copy_update_selection(wp, 1);
398: window_copy_redraw_screen(wp);
399: }
400:
1.166 nicm 401: static int
1.186 nicm 402: window_copy_pagedown(struct window_pane *wp, int half_page, int scroll_exit)
1.147 nicm 403: {
404: struct window_copy_mode_data *data = wp->modedata;
405: struct screen *s = &data->screen;
1.161 nicm 406: u_int n, ox, oy, px, py;
1.147 nicm 407:
408: oy = screen_hsize(data->backing) + data->cy - data->oy;
409: ox = window_copy_find_length(wp, oy);
410:
1.192 ! nicm 411: if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->sely)
1.147 nicm 412: window_copy_other_end(wp);
413:
414: if (data->cx != ox) {
415: data->lastcx = data->cx;
416: data->lastsx = ox;
417: }
418: data->cx = data->lastcx;
419:
420: n = 1;
1.149 nicm 421: if (screen_size_y(s) > 2) {
422: if (half_page)
423: n = screen_size_y(s) / 2;
424: else
425: n = screen_size_y(s) - 2;
426: }
1.147 nicm 427:
428: if (data->oy < n)
429: data->oy = 0;
430: else
431: data->oy -= n;
432:
1.192 ! nicm 433: if (data->screen.sel == NULL || !data->rectflag) {
1.161 nicm 434: py = screen_hsize(data->backing) + data->cy - data->oy;
435: px = window_copy_find_length(wp, py);
436: if ((data->cx >= data->lastsx && data->cx != px) ||
437: data->cx > px)
1.147 nicm 438: window_copy_cursor_end_of_line(wp);
439: }
440:
1.186 nicm 441: if (scroll_exit && data->oy == 0)
1.166 nicm 442: return (1);
1.96 nicm 443: window_copy_update_selection(wp, 1);
1.1 nicm 444: window_copy_redraw_screen(wp);
1.166 nicm 445: return (0);
1.1 nicm 446: }
447:
1.157 nicm 448: static void
1.148 nicm 449: window_copy_previous_paragraph(struct window_pane *wp)
450: {
451: struct window_copy_mode_data *data = wp->modedata;
1.151 nicm 452: u_int oy;
1.148 nicm 453:
454: oy = screen_hsize(data->backing) + data->cy - data->oy;
455:
456: while (oy > 0 && window_copy_find_length(wp, oy) == 0)
457: oy--;
458:
459: while (oy > 0 && window_copy_find_length(wp, oy) > 0)
460: oy--;
461:
462: window_copy_scroll_to(wp, 0, oy);
463: }
464:
1.157 nicm 465: static void
1.148 nicm 466: window_copy_next_paragraph(struct window_pane *wp)
467: {
468: struct window_copy_mode_data *data = wp->modedata;
469: struct screen *s = &data->screen;
470: u_int maxy, ox, oy;
471:
472: oy = screen_hsize(data->backing) + data->cy - data->oy;
473: maxy = screen_hsize(data->backing) + screen_size_y(s) - 1;
474:
475: while (oy < maxy && window_copy_find_length(wp, oy) == 0)
476: oy++;
477:
478: while (oy < maxy && window_copy_find_length(wp, oy) > 0)
479: oy++;
480:
481: ox = window_copy_find_length(wp, oy);
482: window_copy_scroll_to(wp, ox, oy);
483: }
484:
1.157 nicm 485: static void
1.1 nicm 486: window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
487: {
488: struct window_copy_mode_data *data = wp->modedata;
489: struct screen *s = &data->screen;
490: struct screen_write_ctx ctx;
491:
1.119 nicm 492: screen_resize(s, sx, sy, 1);
1.54 nicm 493: if (data->backing != &wp->base)
1.119 nicm 494: screen_resize(data->backing, sx, sy, 1);
1.35 nicm 495:
1.18 nicm 496: if (data->cy > sy - 1)
497: data->cy = sy - 1;
498: if (data->cx > sx)
499: data->cx = sx;
1.63 nicm 500: if (data->oy > screen_hsize(data->backing))
501: data->oy = screen_hsize(data->backing);
1.18 nicm 502:
1.47 nicm 503: window_copy_clear_selection(wp);
1.18 nicm 504:
1.1 nicm 505: screen_write_start(&ctx, NULL, s);
506: window_copy_write_lines(wp, &ctx, 0, screen_size_y(s) - 1);
507: screen_write_stop(&ctx);
1.18 nicm 508:
1.162 nicm 509: if (data->searchmark != NULL)
510: window_copy_search_marks(wp, NULL);
1.163 nicm 511: data->searchx = data->cx;
512: data->searchy = data->cy;
513: data->searcho = data->oy;
1.162 nicm 514:
1.17 nicm 515: window_copy_redraw_screen(wp);
1.1 nicm 516: }
517:
1.157 nicm 518: static const char *
1.155 nicm 519: window_copy_key_table(struct window_pane *wp)
520: {
521: if (options_get_number(wp->window->options, "mode-keys") == MODEKEY_VI)
522: return ("copy-mode-vi");
523: return ("copy-mode");
524: }
525:
1.157 nicm 526: static void
1.155 nicm 527: window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
528: struct args *args, struct mouse_event *m)
1.1 nicm 529: {
530: struct window_copy_mode_data *data = wp->modedata;
1.155 nicm 531: struct screen *sn = &data->screen;
1.162 nicm 532: const char *command, *argument, *ws;
1.155 nicm 533: u_int np = wp->modeprefix;
1.186 nicm 534: int cancel = 0, redraw = 0, scroll_exit;
1.163 nicm 535: char prefix;
1.155 nicm 536:
537: if (args->argc == 0)
538: return;
539: command = args->argv[0];
1.21 nicm 540:
1.156 nicm 541: if (m != NULL && m->valid)
542: window_copy_move_mouse(m);
543:
1.155 nicm 544: if (args->argc == 1) {
545: if (strcmp(command, "append-selection") == 0) {
546: if (s != NULL)
547: window_copy_append_selection(wp, NULL);
548: window_copy_clear_selection(wp);
1.163 nicm 549: redraw = 1;
1.155 nicm 550: }
551: if (strcmp(command, "append-selection-and-cancel") == 0) {
552: if (s != NULL)
553: window_copy_append_selection(wp, NULL);
554: window_copy_clear_selection(wp);
1.163 nicm 555: redraw = 1;
1.162 nicm 556: cancel = 1;
1.155 nicm 557: }
558: if (strcmp(command, "back-to-indentation") == 0)
559: window_copy_cursor_back_to_indentation(wp);
560: if (strcmp(command, "begin-selection") == 0) {
561: if (m != NULL)
562: window_copy_start_drag(c, m);
563: else {
1.192 ! nicm 564: data->lineflag = LINE_SEL_NONE;
1.155 nicm 565: window_copy_start_selection(wp);
1.163 nicm 566: redraw = 1;
1.122 nicm 567: }
1.155 nicm 568: }
1.161 nicm 569: if (strcmp(command, "stop-selection") == 0)
570: data->cursordrag = CURSORDRAG_NONE;
1.155 nicm 571: if (strcmp(command, "bottom-line") == 0) {
572: data->cx = 0;
573: data->cy = screen_size_y(sn) - 1;
574: window_copy_update_selection(wp, 1);
1.163 nicm 575: redraw = 1;
1.155 nicm 576: }
577: if (strcmp(command, "cancel") == 0)
1.162 nicm 578: cancel = 1;
1.155 nicm 579: if (strcmp(command, "clear-selection") == 0) {
580: window_copy_clear_selection(wp);
1.163 nicm 581: redraw = 1;
1.155 nicm 582: }
583: if (strcmp(command, "copy-end-of-line") == 0) {
584: window_copy_start_selection(wp);
585: for (; np > 1; np--)
586: window_copy_cursor_down(wp, 0);
587: window_copy_cursor_end_of_line(wp);
1.163 nicm 588: redraw = 1;
1.155 nicm 589:
590: if (s != NULL) {
591: window_copy_copy_selection(wp, NULL);
1.162 nicm 592: cancel = 1;
1.52 nicm 593: }
594: }
1.155 nicm 595: if (strcmp(command, "copy-line") == 0) {
596: window_copy_cursor_start_of_line(wp);
597: window_copy_start_selection(wp);
598: for (; np > 1; np--)
599: window_copy_cursor_down(wp, 0);
600: window_copy_cursor_end_of_line(wp);
1.163 nicm 601: redraw = 1;
1.1 nicm 602:
1.155 nicm 603: if (s != NULL) {
604: window_copy_copy_selection(wp, NULL);
1.162 nicm 605: cancel = 1;
1.125 nicm 606: }
1.155 nicm 607: }
608: if (strcmp(command, "copy-selection") == 0) {
609: if (s != NULL)
610: window_copy_copy_selection(wp, NULL);
1.125 nicm 611: window_copy_clear_selection(wp);
1.163 nicm 612: redraw = 1;
1.103 nicm 613: }
1.155 nicm 614: if (strcmp(command, "copy-selection-and-cancel") == 0) {
615: if (s != NULL)
616: window_copy_copy_selection(wp, NULL);
617: window_copy_clear_selection(wp);
1.163 nicm 618: redraw = 1;
1.162 nicm 619: cancel = 1;
1.133 nicm 620: }
1.155 nicm 621: if (strcmp(command, "cursor-down") == 0) {
622: for (; np != 0; np--)
623: window_copy_cursor_down(wp, 0);
624: }
625: if (strcmp(command, "cursor-left") == 0) {
626: for (; np != 0; np--)
627: window_copy_cursor_left(wp);
628: }
629: if (strcmp(command, "cursor-right") == 0) {
630: for (; np != 0; np--)
631: window_copy_cursor_right(wp);
632: }
633: if (strcmp(command, "cursor-up") == 0) {
634: for (; np != 0; np--)
635: window_copy_cursor_up(wp, 0);
636: }
637: if (strcmp(command, "end-of-line") == 0)
638: window_copy_cursor_end_of_line(wp);
1.186 nicm 639: if (strcmp(command, "halfpage-down") == 0 ||
640: strcmp(command, "halfpage-down-and-cancel") == 0) {
641: if (strcmp(command, "halfpage-down-and-cancel") == 0)
642: scroll_exit = 1;
643: else
644: scroll_exit = data->scroll_exit;
1.166 nicm 645: for (; np != 0; np--) {
1.186 nicm 646: if (window_copy_pagedown(wp, 1, scroll_exit)) {
1.166 nicm 647: cancel = 1;
648: break;
649: }
650: }
1.155 nicm 651: }
652: if (strcmp(command, "halfpage-up") == 0) {
653: for (; np != 0; np--)
654: window_copy_pageup(wp, 1);
655: }
656: if (strcmp(command, "history-bottom") == 0) {
657: data->cx = 0;
658: data->cy = screen_size_y(sn) - 1;
659: data->oy = 0;
660: window_copy_update_selection(wp, 1);
1.163 nicm 661: redraw = 1;
1.126 nicm 662: }
1.155 nicm 663: if (strcmp(command, "history-top") == 0) {
664: data->cx = 0;
665: data->cy = 0;
666: data->oy = screen_hsize(data->backing);
667: window_copy_update_selection(wp, 1);
1.163 nicm 668: redraw = 1;
1.71 nicm 669: }
1.155 nicm 670: if (strcmp(command, "jump-again") == 0) {
671: switch (data->jumptype) {
672: case WINDOW_COPY_JUMPFORWARD:
673: for (; np != 0; np--)
674: window_copy_cursor_jump(wp);
675: break;
676: case WINDOW_COPY_JUMPBACKWARD:
677: for (; np != 0; np--)
678: window_copy_cursor_jump_back(wp);
679: break;
680: case WINDOW_COPY_JUMPTOFORWARD:
681: for (; np != 0; np--)
1.184 nicm 682: window_copy_cursor_jump_to(wp);
1.155 nicm 683: break;
684: case WINDOW_COPY_JUMPTOBACKWARD:
685: for (; np != 0; np--)
1.184 nicm 686: window_copy_cursor_jump_to_back(wp);
1.155 nicm 687: break;
688: }
1.89 nicm 689: }
1.155 nicm 690: if (strcmp(command, "jump-reverse") == 0) {
691: switch (data->jumptype) {
692: case WINDOW_COPY_JUMPFORWARD:
693: for (; np != 0; np--)
694: window_copy_cursor_jump_back(wp);
695: break;
696: case WINDOW_COPY_JUMPBACKWARD:
697: for (; np != 0; np--)
698: window_copy_cursor_jump(wp);
699: break;
700: case WINDOW_COPY_JUMPTOFORWARD:
701: for (; np != 0; np--)
1.184 nicm 702: window_copy_cursor_jump_to_back(wp);
1.155 nicm 703: break;
704: case WINDOW_COPY_JUMPTOBACKWARD:
705: for (; np != 0; np--)
1.184 nicm 706: window_copy_cursor_jump_to(wp);
1.155 nicm 707: break;
1.125 nicm 708: }
1.155 nicm 709: }
710: if (strcmp(command, "middle-line") == 0) {
711: data->cx = 0;
712: data->cy = (screen_size_y(sn) - 1) / 2;
713: window_copy_update_selection(wp, 1);
1.163 nicm 714: redraw = 1;
1.1 nicm 715: }
1.155 nicm 716: if (strcmp(command, "next-paragraph") == 0) {
717: for (; np != 0; np--)
718: window_copy_next_paragraph(wp);
719: }
720: if (strcmp(command, "next-space") == 0) {
721: for (; np != 0; np--)
722: window_copy_cursor_next_word(wp, " ");
723: }
724: if (strcmp(command, "next-space-end") == 0) {
725: for (; np != 0; np--)
726: window_copy_cursor_next_word_end(wp, " ");
727: }
728: if (strcmp(command, "next-word") == 0) {
729: ws = options_get_string(s->options, "word-separators");
730: for (; np != 0; np--)
731: window_copy_cursor_next_word(wp, ws);
732: }
733: if (strcmp(command, "next-word-end") == 0) {
734: ws = options_get_string(s->options, "word-separators");
1.52 nicm 735: for (; np != 0; np--)
1.155 nicm 736: window_copy_cursor_next_word_end(wp, ws);
737: }
738: if (strcmp(command, "other-end") == 0) {
739: if ((np % 2) != 0)
740: window_copy_other_end(wp);
741: }
1.186 nicm 742: if (strcmp(command, "page-down") == 0 ||
743: strcmp(command, "page-down-and-cancel") == 0) {
744: if (strcmp(command, "page-down-and-cancel") == 0)
745: scroll_exit = 1;
746: else
747: scroll_exit = data->scroll_exit;
1.166 nicm 748: for (; np != 0; np--) {
1.186 nicm 749: if (window_copy_pagedown(wp, 0, scroll_exit)) {
1.166 nicm 750: cancel = 1;
751: break;
752: }
753: }
1.155 nicm 754: }
755: if (strcmp(command, "page-up") == 0) {
1.76 nicm 756: for (; np != 0; np--)
1.155 nicm 757: window_copy_pageup(wp, 0);
758: }
759: if (strcmp(command, "previous-paragraph") == 0) {
1.76 nicm 760: for (; np != 0; np--)
1.155 nicm 761: window_copy_previous_paragraph(wp);
1.52 nicm 762: }
1.155 nicm 763: if (strcmp(command, "previous-space") == 0) {
1.52 nicm 764: for (; np != 0; np--)
1.155 nicm 765: window_copy_cursor_previous_word(wp, " ");
766: }
767: if (strcmp(command, "previous-word") == 0) {
768: ws = options_get_string(s->options, "word-separators");
1.52 nicm 769: for (; np != 0; np--)
1.155 nicm 770: window_copy_cursor_previous_word(wp, ws);
771: }
772: if (strcmp(command, "rectangle-toggle") == 0) {
1.192 ! nicm 773: data->lineflag = LINE_SEL_NONE;
1.155 nicm 774: window_copy_rectangle_toggle(wp);
775: }
1.186 nicm 776: if (strcmp(command, "scroll-down") == 0 ||
777: strcmp(command, "scroll-down-and-cancel") == 0) {
778: if (strcmp(command, "scroll-down-and-cancel") == 0)
779: scroll_exit = 1;
780: else
781: scroll_exit = data->scroll_exit;
1.76 nicm 782: for (; np != 0; np--)
1.155 nicm 783: window_copy_cursor_down(wp, 1);
1.186 nicm 784: if (scroll_exit && data->oy == 0)
1.162 nicm 785: cancel = 1;
1.155 nicm 786: }
787: if (strcmp(command, "scroll-up") == 0) {
1.76 nicm 788: for (; np != 0; np--)
1.155 nicm 789: window_copy_cursor_up(wp, 1);
1.52 nicm 790: }
1.155 nicm 791: if (strcmp(command, "search-again") == 0) {
792: if (data->searchtype == WINDOW_COPY_SEARCHUP) {
1.118 nicm 793: for (; np != 0; np--)
1.184 nicm 794: window_copy_search_up(wp);
1.155 nicm 795: } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
1.118 nicm 796: for (; np != 0; np--)
1.184 nicm 797: window_copy_search_down(wp);
1.50 nicm 798: }
1.155 nicm 799: }
800: if (strcmp(command, "search-reverse") == 0) {
801: if (data->searchtype == WINDOW_COPY_SEARCHUP) {
1.118 nicm 802: for (; np != 0; np--)
1.184 nicm 803: window_copy_search_down(wp);
1.155 nicm 804: } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
1.118 nicm 805: for (; np != 0; np--)
1.184 nicm 806: window_copy_search_up(wp);
1.50 nicm 807: }
1.21 nicm 808: }
1.155 nicm 809: if (strcmp(command, "select-line") == 0) {
1.192 ! nicm 810: data->lineflag = LINE_SEL_LEFT_RIGHT;
1.155 nicm 811: data->rectflag = 0;
812: window_copy_cursor_start_of_line(wp);
813: window_copy_start_selection(wp);
814: for (; np > 1; np--)
815: window_copy_cursor_down(wp, 0);
816: window_copy_cursor_end_of_line(wp);
1.163 nicm 817: redraw = 1;
1.155 nicm 818: }
1.156 nicm 819: if (strcmp(command, "select-word") == 0) {
1.192 ! nicm 820: data->lineflag = LINE_SEL_LEFT_RIGHT;
1.156 nicm 821: data->rectflag = 0;
822: ws = options_get_string(s->options, "word-separators");
823: window_copy_cursor_previous_word(wp, ws);
824: window_copy_start_selection(wp);
825: window_copy_cursor_next_word_end(wp, ws);
1.163 nicm 826: redraw = 1;
1.156 nicm 827: }
828: if (strcmp(command, "start-of-line") == 0)
1.155 nicm 829: window_copy_cursor_start_of_line(wp);
830: if (strcmp(command, "top-line") == 0) {
831: data->cx = 0;
832: data->cy = 0;
833: window_copy_update_selection(wp, 1);
1.163 nicm 834: redraw = 1;
1.155 nicm 835: }
836: } else if (args->argc == 2 && *args->argv[1] != '\0') {
837: argument = args->argv[1];
838: if (strcmp(command, "copy-pipe") == 0) {
1.160 nicm 839: if (s != NULL)
840: window_copy_copy_pipe(wp, s, NULL, argument);
841: }
842: if (strcmp(command, "copy-pipe-and-cancel") == 0) {
1.155 nicm 843: if (s != NULL) {
844: window_copy_copy_pipe(wp, s, NULL, argument);
1.162 nicm 845: cancel = 1;
1.155 nicm 846: }
847: }
848: if (strcmp(command, "goto-line") == 0)
849: window_copy_goto_line(wp, argument);
850: if (strcmp(command, "jump-backward") == 0) {
851: data->jumptype = WINDOW_COPY_JUMPBACKWARD;
852: data->jumpchar = *argument;
853: for (; np != 0; np--)
854: window_copy_cursor_jump_back(wp);
855: }
856: if (strcmp(command, "jump-forward") == 0) {
857: data->jumptype = WINDOW_COPY_JUMPFORWARD;
858: data->jumpchar = *argument;
859: for (; np != 0; np--)
860: window_copy_cursor_jump(wp);
861: }
862: if (strcmp(command, "jump-to-backward") == 0) {
863: data->jumptype = WINDOW_COPY_JUMPTOBACKWARD;
864: data->jumpchar = *argument;
865: for (; np != 0; np--)
1.184 nicm 866: window_copy_cursor_jump_to_back(wp);
1.50 nicm 867: }
1.155 nicm 868: if (strcmp(command, "jump-to-forward") == 0) {
869: data->jumptype = WINDOW_COPY_JUMPTOFORWARD;
870: data->jumpchar = *argument;
871: for (; np != 0; np--)
1.184 nicm 872: window_copy_cursor_jump_to(wp);
1.100 nicm 873: }
1.155 nicm 874: if (strcmp(command, "search-backward") == 0) {
875: data->searchtype = WINDOW_COPY_SEARCHUP;
1.163 nicm 876: free(data->searchstr);
1.155 nicm 877: data->searchstr = xstrdup(argument);
1.150 nicm 878: for (; np != 0; np--)
1.184 nicm 879: window_copy_search_up(wp);
1.155 nicm 880: }
881: if (strcmp(command, "search-forward") == 0) {
882: data->searchtype = WINDOW_COPY_SEARCHDOWN;
1.163 nicm 883: free(data->searchstr);
1.155 nicm 884: data->searchstr = xstrdup(argument);
1.150 nicm 885: for (; np != 0; np--)
1.184 nicm 886: window_copy_search_down(wp);
1.21 nicm 887: }
1.163 nicm 888: if (strcmp(command, "search-backward-incremental") == 0) {
889: prefix = *argument++;
890: if (data->searchx == -1 || data->searchy == -1) {
891: data->searchx = data->cx;
892: data->searchy = data->cy;
893: data->searcho = data->oy;
894: } else if (data->searchstr != NULL &&
895: strcmp(argument, data->searchstr) != 0) {
896: data->cx = data->searchx;
897: data->cy = data->searchy;
898: data->oy = data->searcho;
899: redraw = 1;
900: }
901: if (*argument == '\0') {
902: window_copy_clear_marks(wp);
903: redraw = 1;
904: } else if (prefix == '=' || prefix == '-') {
905: data->searchtype = WINDOW_COPY_SEARCHUP;
906: free(data->searchstr);
907: data->searchstr = xstrdup(argument);
1.184 nicm 908: if (!window_copy_search_up(wp)) {
1.163 nicm 909: window_copy_clear_marks(wp);
910: redraw = 1;
911: }
912: } else if (prefix == '+') {
913: data->searchtype = WINDOW_COPY_SEARCHDOWN;
914: free(data->searchstr);
915: data->searchstr = xstrdup(argument);
1.184 nicm 916: if (!window_copy_search_down(wp)) {
1.163 nicm 917: window_copy_clear_marks(wp);
918: redraw = 1;
919: }
920: }
921: }
922: if (strcmp(command, "search-forward-incremental") == 0) {
923: prefix = *argument++;
924: if (data->searchx == -1 || data->searchy == -1) {
925: data->searchx = data->cx;
926: data->searchy = data->cy;
927: data->searcho = data->oy;
928: } else if (data->searchstr != NULL &&
929: strcmp(argument, data->searchstr) != 0) {
930: data->cx = data->searchx;
931: data->cy = data->searchy;
932: data->oy = data->searcho;
933: redraw = 1;
934: }
935: if (*argument == '\0') {
936: window_copy_clear_marks(wp);
937: redraw = 1;
938: } else if (prefix == '=' || prefix == '+') {
939: data->searchtype = WINDOW_COPY_SEARCHDOWN;
940: free(data->searchstr);
941: data->searchstr = xstrdup(argument);
1.184 nicm 942: if (!window_copy_search_down(wp)) {
1.163 nicm 943: window_copy_clear_marks(wp);
944: redraw = 1;
945: }
946: } else if (prefix == '-') {
947: data->searchtype = WINDOW_COPY_SEARCHUP;
948: free(data->searchstr);
949: data->searchstr = xstrdup(argument);
1.184 nicm 950: if (!window_copy_search_up(wp)) {
1.163 nicm 951: window_copy_clear_marks(wp);
952: redraw = 1;
953: }
954: }
955: }
1.1 nicm 956: }
1.21 nicm 957:
1.162 nicm 958: if (strncmp(command, "search-", 7) != 0 && data->searchmark != NULL) {
1.163 nicm 959: window_copy_clear_marks(wp);
960: redraw = 1;
961: data->searchx = data->searchy = -1;
1.162 nicm 962: }
963:
964: if (cancel)
965: window_pane_reset_mode(wp);
1.163 nicm 966: else if (redraw)
967: window_copy_redraw_screen(wp);
1.155 nicm 968: wp->modeprefix = 1;
1.50 nicm 969: }
970:
1.157 nicm 971: static void
1.21 nicm 972: window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py)
973: {
974: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 975: struct grid *gd = data->backing->grid;
1.21 nicm 976: u_int offset, gap;
977:
978: data->cx = px;
979:
1.185 nicm 980: if (py >= gd->hsize - data->oy && py < gd->hsize - data->oy + gd->sy)
981: data->cy = py - (gd->hsize - data->oy);
982: else {
983: gap = gd->sy / 4;
984: if (py < gd->sy) {
985: offset = 0;
986: data->cy = py;
987: } else if (py > gd->hsize + gd->sy - gap) {
988: offset = gd->hsize;
989: data->cy = py - gd->hsize;
990: } else {
991: offset = py + gap - gd->sy;
992: data->cy = py - offset;
993: }
994: data->oy = gd->hsize - offset;
1.21 nicm 995: }
996:
1.96 nicm 997: window_copy_update_selection(wp, 1);
1.21 nicm 998: window_copy_redraw_screen(wp);
999: }
1000:
1.157 nicm 1001: static int
1.118 nicm 1002: window_copy_search_compare(struct grid *gd, u_int px, u_int py,
1003: struct grid *sgd, u_int spx, int cis)
1.21 nicm 1004: {
1.140 nicm 1005: struct grid_cell gc, sgc;
1006: const struct utf8_data *ud, *sud;
1.21 nicm 1007:
1.140 nicm 1008: grid_get_cell(gd, px, py, &gc);
1009: ud = &gc.data;
1010: grid_get_cell(sgd, spx, 0, &sgc);
1011: sud = &sgc.data;
1.35 nicm 1012:
1.140 nicm 1013: if (ud->size != sud->size || ud->width != sud->width)
1.21 nicm 1014: return (0);
1.97 nicm 1015:
1.140 nicm 1016: if (cis && ud->size == 1)
1017: return (tolower(ud->data[0]) == sud->data[0]);
1.97 nicm 1018:
1.140 nicm 1019: return (memcmp(ud->data, sud->data, ud->size) == 0);
1.21 nicm 1020: }
1021:
1.157 nicm 1022: static int
1.21 nicm 1023: window_copy_search_lr(struct grid *gd,
1.97 nicm 1024: struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
1.21 nicm 1025: {
1026: u_int ax, bx, px;
1.97 nicm 1027: int matched;
1.21 nicm 1028:
1029: for (ax = first; ax < last; ax++) {
1.181 nicm 1030: if (ax + sgd->sx > gd->sx)
1.21 nicm 1031: break;
1032: for (bx = 0; bx < sgd->sx; bx++) {
1033: px = ax + bx;
1.97 nicm 1034: matched = window_copy_search_compare(gd, px, py, sgd,
1035: bx, cis);
1036: if (!matched)
1.21 nicm 1037: break;
1038: }
1039: if (bx == sgd->sx) {
1040: *ppx = ax;
1041: return (1);
1042: }
1043: }
1044: return (0);
1045: }
1046:
1.157 nicm 1047: static int
1.21 nicm 1048: window_copy_search_rl(struct grid *gd,
1.97 nicm 1049: struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
1.21 nicm 1050: {
1051: u_int ax, bx, px;
1.97 nicm 1052: int matched;
1.21 nicm 1053:
1054: for (ax = last + 1; ax > first; ax--) {
1.24 nicm 1055: if (gd->sx - (ax - 1) < sgd->sx)
1056: continue;
1.21 nicm 1057: for (bx = 0; bx < sgd->sx; bx++) {
1058: px = ax - 1 + bx;
1.97 nicm 1059: matched = window_copy_search_compare(gd, px, py, sgd,
1060: bx, cis);
1061: if (!matched)
1.21 nicm 1062: break;
1063: }
1064: if (bx == sgd->sx) {
1065: *ppx = ax - 1;
1066: return (1);
1067: }
1068: }
1069: return (0);
1070: }
1071:
1.157 nicm 1072: static void
1.150 nicm 1073: window_copy_move_left(struct screen *s, u_int *fx, u_int *fy)
1.21 nicm 1074: {
1.150 nicm 1075: if (*fx == 0) { /* left */
1076: if (*fy == 0) /* top */
1077: return;
1078: *fx = screen_size_x(s) - 1;
1079: *fy = *fy - 1;
1080: } else
1081: *fx = *fx - 1;
1082: }
1.21 nicm 1083:
1.157 nicm 1084: static void
1.150 nicm 1085: window_copy_move_right(struct screen *s, u_int *fx, u_int *fy)
1086: {
1087: if (*fx == screen_size_x(s) - 1) { /* right */
1088: if (*fy == screen_hsize(s) + screen_size_y(s)) /* bottom */
1.21 nicm 1089: return;
1.150 nicm 1090: *fx = 0;
1091: *fy = *fy + 1;
1.21 nicm 1092: } else
1.150 nicm 1093: *fx = *fx + 1;
1094: }
1.21 nicm 1095:
1.157 nicm 1096: static int
1.150 nicm 1097: window_copy_is_lowercase(const char *ptr)
1098: {
1099: while (*ptr != '\0') {
1100: if (*ptr != tolower((u_char)*ptr))
1101: return (0);
1102: ++ptr;
1.97 nicm 1103: }
1.150 nicm 1104: return (1);
1105: }
1.97 nicm 1106:
1.150 nicm 1107: /*
1108: * Search for text stored in sgd starting from position fx,fy up to endline. If
1109: * found, jump to it. If cis then ignore case. The direction is 0 for searching
1110: * up, down otherwise. If wrap then go to begin/end of grid and try again if
1111: * not found.
1112: */
1.163 nicm 1113: static int
1.150 nicm 1114: window_copy_search_jump(struct window_pane *wp, struct grid *gd,
1115: struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap,
1116: int direction)
1117: {
1118: u_int i, px;
1119: int found;
1120:
1121: found = 0;
1122: if (direction) {
1123: for (i = fy; i <= endline; i++) {
1124: found = window_copy_search_lr(gd, sgd, &px, i, fx,
1125: gd->sx, cis);
1126: if (found)
1127: break;
1128: fx = 0;
1129: }
1130: } else {
1131: for (i = fy + 1; endline < i; i--) {
1132: found = window_copy_search_rl(gd, sgd, &px, i - 1, 0,
1133: fx, cis);
1134: if (found) {
1135: i--;
1136: break;
1137: }
1138: fx = gd->sx;
1.21 nicm 1139: }
1140: }
1.150 nicm 1141:
1.163 nicm 1142: if (found) {
1.150 nicm 1143: window_copy_scroll_to(wp, px, i);
1.163 nicm 1144: return (1);
1145: }
1146: if (wrap) {
1147: return (window_copy_search_jump(wp, gd, sgd,
1148: direction ? 0 : gd->sx - 1,
1.150 nicm 1149: direction ? 0 : gd->hsize + gd->sy - 1, fy, cis, 0,
1.163 nicm 1150: direction));
1.21 nicm 1151: }
1.163 nicm 1152: return (0);
1.21 nicm 1153: }
1154:
1.150 nicm 1155: /*
1156: * Search in for text searchstr. If direction is 0 then search up, otherwise
1.184 nicm 1157: * down.
1.150 nicm 1158: */
1.163 nicm 1159: static int
1.184 nicm 1160: window_copy_search(struct window_pane *wp, int direction)
1.21 nicm 1161: {
1162: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1163: struct screen *s = data->backing, ss;
1.21 nicm 1164: struct screen_write_ctx ctx;
1.150 nicm 1165: struct grid *gd = s->grid;
1166: u_int fx, fy, endline;
1.163 nicm 1167: int wrapflag, cis, found;
1.21 nicm 1168:
1.174 nicm 1169: free(wp->searchstr);
1170: wp->searchstr = xstrdup(data->searchstr);
1171:
1.150 nicm 1172: fx = data->cx;
1173: fy = screen_hsize(data->backing) - data->oy + data->cy;
1.21 nicm 1174:
1.162 nicm 1175: screen_init(&ss, screen_write_strlen("%s", data->searchstr), 1, 0);
1.21 nicm 1176: screen_write_start(&ctx, NULL, &ss);
1.162 nicm 1177: screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", data->searchstr);
1.21 nicm 1178: screen_write_stop(&ctx);
1179:
1.184 nicm 1180: if (direction)
1181: window_copy_move_right(s, &fx, &fy);
1182: else
1183: window_copy_move_left(s, &fx, &fy);
1.150 nicm 1184: window_copy_clear_selection(wp);
1185:
1186: wrapflag = options_get_number(wp->window->options, "wrap-search");
1.162 nicm 1187: cis = window_copy_is_lowercase(data->searchstr);
1.21 nicm 1188:
1.150 nicm 1189: if (direction)
1190: endline = gd->hsize + gd->sy - 1;
1191: else
1192: endline = 0;
1.163 nicm 1193: found = window_copy_search_jump(wp, gd, ss.grid, fx, fy, endline, cis,
1.162 nicm 1194: wrapflag, direction);
1195:
1196: if (window_copy_search_marks(wp, &ss))
1197: window_copy_redraw_screen(wp);
1.21 nicm 1198:
1.150 nicm 1199: screen_free(&ss);
1.163 nicm 1200: return (found);
1.150 nicm 1201: }
1.97 nicm 1202:
1.162 nicm 1203: static int
1204: window_copy_search_marks(struct window_pane *wp, struct screen *ssp)
1205: {
1206: struct window_copy_mode_data *data = wp->modedata;
1207: struct screen *s = data->backing, ss;
1208: struct screen_write_ctx ctx;
1209: struct grid *gd = s->grid;
1.170 nicm 1210: int found, cis, which = -1;
1.162 nicm 1211: u_int px, py, b, nfound = 0, width;
1212:
1213: if (ssp == NULL) {
1214: width = screen_write_strlen("%s", data->searchstr);
1215: screen_init(&ss, width, 1, 0);
1216: screen_write_start(&ctx, NULL, &ss);
1217: screen_write_nputs(&ctx, -1, &grid_default_cell, "%s",
1218: data->searchstr);
1219: screen_write_stop(&ctx);
1220: ssp = &ss;
1221: } else
1222: width = screen_size_x(ssp);
1223:
1224: cis = window_copy_is_lowercase(data->searchstr);
1225:
1226: free(data->searchmark);
1227: data->searchmark = bit_alloc((gd->hsize + gd->sy) * gd->sx);
1228:
1229: for (py = 0; py < gd->hsize + gd->sy; py++) {
1230: px = 0;
1231: for (;;) {
1232: found = window_copy_search_lr(gd, ssp->grid, &px, py,
1233: px, gd->sx, cis);
1234: if (!found)
1235: break;
1.170 nicm 1236:
1.162 nicm 1237: nfound++;
1.170 nicm 1238: if (px == data->cx && py == gd->hsize + data->cy - data->oy)
1239: which = nfound;
1.162 nicm 1240:
1241: b = (py * gd->sx) + px;
1242: bit_nset(data->searchmark, b, b + width - 1);
1243:
1244: px++;
1245: }
1246: }
1247:
1.170 nicm 1248: if (which != -1)
1249: data->searchthis = 1 + nfound - which;
1250: else
1251: data->searchthis = -1;
1252: data->searchcount = nfound;
1253:
1.162 nicm 1254: if (ssp == &ss)
1255: screen_free(&ss);
1256: return (nfound);
1257: }
1258:
1.157 nicm 1259: static void
1.163 nicm 1260: window_copy_clear_marks(struct window_pane *wp)
1261: {
1262: struct window_copy_mode_data *data = wp->modedata;
1263:
1264: free(data->searchmark);
1265: data->searchmark = NULL;
1266: }
1267:
1268: static int
1.184 nicm 1269: window_copy_search_up(struct window_pane *wp)
1.150 nicm 1270: {
1.184 nicm 1271: return (window_copy_search(wp, 0));
1.150 nicm 1272: }
1.21 nicm 1273:
1.163 nicm 1274: static int
1.184 nicm 1275: window_copy_search_down(struct window_pane *wp)
1.150 nicm 1276: {
1.184 nicm 1277: return (window_copy_search(wp, 1));
1.21 nicm 1278: }
1279:
1.157 nicm 1280: static void
1.21 nicm 1281: window_copy_goto_line(struct window_pane *wp, const char *linestr)
1282: {
1283: struct window_copy_mode_data *data = wp->modedata;
1284: const char *errstr;
1285: u_int lineno;
1286:
1.54 nicm 1287: lineno = strtonum(linestr, 0, screen_hsize(data->backing), &errstr);
1.21 nicm 1288: if (errstr != NULL)
1289: return;
1.35 nicm 1290:
1.21 nicm 1291: data->oy = lineno;
1.96 nicm 1292: window_copy_update_selection(wp, 1);
1.21 nicm 1293: window_copy_redraw_screen(wp);
1294: }
1295:
1.157 nicm 1296: static void
1.118 nicm 1297: window_copy_write_line(struct window_pane *wp, struct screen_write_ctx *ctx,
1298: u_int py)
1.1 nicm 1299: {
1300: struct window_copy_mode_data *data = wp->modedata;
1301: struct screen *s = &data->screen;
1.136 nicm 1302: struct options *oo = wp->window->options;
1.1 nicm 1303: struct grid_cell gc;
1.100 nicm 1304: char hdr[512];
1.162 nicm 1305: size_t size = 0;
1.21 nicm 1306:
1.101 nicm 1307: style_apply(&gc, oo, "mode-style");
1.164 nicm 1308: gc.flags |= GRID_FLAG_NOPALETTE;
1.1 nicm 1309:
1310: if (py == 0) {
1.170 nicm 1311: if (data->searchmark == NULL) {
1312: size = xsnprintf(hdr, sizeof hdr,
1313: "[%u/%u]", data->oy, screen_hsize(data->backing));
1314: } else {
1315: if (data->searchthis == -1) {
1316: size = xsnprintf(hdr, sizeof hdr,
1317: "(%u results) [%d/%u]", data->searchcount,
1318: data->oy, screen_hsize(data->backing));
1319: } else {
1320: size = xsnprintf(hdr, sizeof hdr,
1321: "(%u/%u results) [%d/%u]", data->searchthis,
1322: data->searchcount, data->oy,
1323: screen_hsize(data->backing));
1324: }
1325: }
1.62 nicm 1326: if (size > screen_size_x(s))
1327: size = screen_size_x(s);
1.1 nicm 1328: screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
1329: screen_write_puts(ctx, &gc, "%s", hdr);
1330: } else
1331: size = 0;
1332:
1.105 nicm 1333: if (size < screen_size_x(s)) {
1.162 nicm 1334: screen_write_cursormove(ctx, 0, py);
1335: screen_write_copy(ctx, data->backing, 0,
1.105 nicm 1336: (screen_hsize(data->backing) - data->oy) + py,
1.162 nicm 1337: screen_size_x(s) - size, 1, data->searchmark, &gc);
1.105 nicm 1338: }
1.18 nicm 1339:
1340: if (py == data->cy && data->cx == screen_size_x(s)) {
1341: memcpy(&gc, &grid_default_cell, sizeof gc);
1342: screen_write_cursormove(ctx, screen_size_x(s) - 1, py);
1343: screen_write_putc(ctx, &gc, '$');
1344: }
1.1 nicm 1345: }
1346:
1.157 nicm 1347: static void
1.118 nicm 1348: window_copy_write_lines(struct window_pane *wp, struct screen_write_ctx *ctx,
1349: u_int py, u_int ny)
1.1 nicm 1350: {
1351: u_int yy;
1352:
1353: for (yy = py; yy < py + ny; yy++)
1354: window_copy_write_line(wp, ctx, py);
1.121 nicm 1355: }
1356:
1.157 nicm 1357: static void
1.121 nicm 1358: window_copy_redraw_selection(struct window_pane *wp, u_int old_y)
1359: {
1360: struct window_copy_mode_data *data = wp->modedata;
1361: u_int new_y, start, end;
1362:
1363: new_y = data->cy;
1364: if (old_y <= new_y) {
1365: start = old_y;
1366: end = new_y;
1367: } else {
1368: start = new_y;
1369: end = old_y;
1370: }
1371: window_copy_redraw_lines(wp, start, end - start + 1);
1.1 nicm 1372: }
1373:
1.157 nicm 1374: static void
1.1 nicm 1375: window_copy_redraw_lines(struct window_pane *wp, u_int py, u_int ny)
1376: {
1377: struct window_copy_mode_data *data = wp->modedata;
1378: struct screen_write_ctx ctx;
1379: u_int i;
1380:
1381: screen_write_start(&ctx, wp, NULL);
1382: for (i = py; i < py + ny; i++)
1383: window_copy_write_line(wp, &ctx, i);
1384: screen_write_cursormove(&ctx, data->cx, data->cy);
1385: screen_write_stop(&ctx);
1386: }
1387:
1.157 nicm 1388: static void
1.1 nicm 1389: window_copy_redraw_screen(struct window_pane *wp)
1390: {
1391: struct window_copy_mode_data *data = wp->modedata;
1392:
1393: window_copy_redraw_lines(wp, 0, screen_size_y(&data->screen));
1394: }
1395:
1.157 nicm 1396: static void
1.161 nicm 1397: window_copy_synchronize_cursor(struct window_pane *wp)
1398: {
1399: struct window_copy_mode_data *data = wp->modedata;
1400: u_int xx, yy;
1401:
1402: xx = data->cx;
1403: yy = screen_hsize(data->backing) + data->cy - data->oy;
1404:
1405: switch (data->cursordrag) {
1406: case CURSORDRAG_ENDSEL:
1407: data->endselx = xx;
1408: data->endsely = yy;
1409: break;
1410: case CURSORDRAG_SEL:
1411: data->selx = xx;
1412: data->sely = yy;
1413: break;
1414: case CURSORDRAG_NONE:
1415: break;
1416: }
1417: }
1418:
1419: static void
1.18 nicm 1420: window_copy_update_cursor(struct window_pane *wp, u_int cx, u_int cy)
1.1 nicm 1421: {
1422: struct window_copy_mode_data *data = wp->modedata;
1.18 nicm 1423: struct screen *s = &data->screen;
1.1 nicm 1424: struct screen_write_ctx ctx;
1.18 nicm 1425: u_int old_cx, old_cy;
1.1 nicm 1426:
1.18 nicm 1427: old_cx = data->cx; old_cy = data->cy;
1428: data->cx = cx; data->cy = cy;
1429: if (old_cx == screen_size_x(s))
1430: window_copy_redraw_lines(wp, old_cy, 1);
1431: if (data->cx == screen_size_x(s))
1432: window_copy_redraw_lines(wp, data->cy, 1);
1433: else {
1434: screen_write_start(&ctx, wp, NULL);
1435: screen_write_cursormove(&ctx, data->cx, data->cy);
1436: screen_write_stop(&ctx);
1437: }
1.1 nicm 1438: }
1439:
1.157 nicm 1440: static void
1.1 nicm 1441: window_copy_start_selection(struct window_pane *wp)
1442: {
1443: struct window_copy_mode_data *data = wp->modedata;
1444:
1.18 nicm 1445: data->selx = data->cx;
1.54 nicm 1446: data->sely = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 1447:
1.161 nicm 1448: data->endselx = data->selx;
1449: data->endsely = data->sely;
1450:
1451: data->cursordrag = CURSORDRAG_ENDSEL;
1452:
1.192 ! nicm 1453: window_copy_set_selection(wp, 1);
1.1 nicm 1454: }
1455:
1.157 nicm 1456: static int
1.161 nicm 1457: window_copy_adjust_selection(struct window_pane *wp, u_int *selx, u_int *sely)
1458: {
1459: struct window_copy_mode_data *data = wp->modedata;
1460: struct screen *s = &data->screen;
1461: u_int sx, sy, ty;
1462: int relpos;
1463:
1464: sx = *selx;
1465: sy = *sely;
1466:
1467: ty = screen_hsize(data->backing) - data->oy;
1468: if (sy < ty) {
1469: relpos = WINDOW_COPY_REL_POS_ABOVE;
1470: if (!data->rectflag)
1471: sx = 0;
1472: sy = 0;
1473: } else if (sy > ty + screen_size_y(s) - 1) {
1474: relpos = WINDOW_COPY_REL_POS_BELOW;
1475: if (!data->rectflag)
1476: sx = screen_size_x(s) - 1;
1477: sy = screen_size_y(s) - 1;
1478: } else {
1479: relpos = WINDOW_COPY_REL_POS_ON_SCREEN;
1480: sy -= ty;
1481: }
1482:
1483: *selx = sx;
1.176 nicm 1484: *sely = sy;
1.161 nicm 1485: return (relpos);
1486: }
1487:
1488: static int
1.96 nicm 1489: window_copy_update_selection(struct window_pane *wp, int may_redraw)
1.1 nicm 1490: {
1491: struct window_copy_mode_data *data = wp->modedata;
1492: struct screen *s = &data->screen;
1.192 ! nicm 1493:
! 1494: if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
! 1495: return (0);
! 1496: return (window_copy_set_selection(wp, may_redraw));
! 1497: }
! 1498:
! 1499: static int
! 1500: window_copy_set_selection(struct window_pane *wp, int may_redraw)
! 1501: {
! 1502: struct window_copy_mode_data *data = wp->modedata;
! 1503: struct screen *s = &data->screen;
1.136 nicm 1504: struct options *oo = wp->window->options;
1.1 nicm 1505: struct grid_cell gc;
1.161 nicm 1506: u_int sx, sy, cy, endsx, endsy;
1507: int startrelpos, endrelpos;
1.1 nicm 1508:
1.161 nicm 1509: window_copy_synchronize_cursor(wp);
1.1 nicm 1510:
1511: /* Adjust the selection. */
1512: sx = data->selx;
1513: sy = data->sely;
1.161 nicm 1514: startrelpos = window_copy_adjust_selection(wp, &sx, &sy);
1515:
1516: /* Adjust the end of selection. */
1517: endsx = data->endselx;
1518: endsy = data->endsely;
1519: endrelpos = window_copy_adjust_selection(wp, &endsx, &endsy);
1520:
1521: /* Selection is outside of the current screen */
1522: if (startrelpos == endrelpos &&
1523: startrelpos != WINDOW_COPY_REL_POS_ON_SCREEN) {
1524: screen_hide_selection(s);
1525: return (0);
1526: }
1.1 nicm 1527:
1.161 nicm 1528: /* Set colours and selection. */
1529: style_apply(&gc, oo, "mode-style");
1.164 nicm 1530: gc.flags |= GRID_FLAG_NOPALETTE;
1.192 ! nicm 1531: screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag,
! 1532: data->modekeys, &gc);
1.42 nicm 1533:
1.96 nicm 1534: if (data->rectflag && may_redraw) {
1.42 nicm 1535: /*
1536: * Can't rely on the caller to redraw the right lines for
1537: * rectangle selection - find the highest line and the number
1538: * of lines, and redraw just past that in both directions
1539: */
1540: cy = data->cy;
1.182 nicm 1541: if (data->cursordrag == CURSORDRAG_ENDSEL) {
1542: if (sy < cy)
1543: window_copy_redraw_lines(wp, sy, cy - sy + 1);
1544: else
1545: window_copy_redraw_lines(wp, cy, sy - cy + 1);
1546: } else {
1547: if (endsy < cy)
1548: window_copy_redraw_lines(wp, endsy, cy - endsy + 1);
1549: else
1550: window_copy_redraw_lines(wp, cy, endsy - cy + 1);
1551: }
1.42 nicm 1552: }
1553:
1.1 nicm 1554: return (1);
1555: }
1556:
1.157 nicm 1557: static void *
1.89 nicm 1558: window_copy_get_selection(struct window_pane *wp, size_t *len)
1.1 nicm 1559: {
1560: struct window_copy_mode_data *data = wp->modedata;
1561: struct screen *s = &data->screen;
1562: char *buf;
1.42 nicm 1563: size_t off;
1.111 nicm 1564: u_int i, xx, yy, sx, sy, ex, ey, ey_last;
1.188 nicm 1565: u_int firstsx, lastex, restex, restsx, selx;
1.69 nicm 1566: int keys;
1.1 nicm 1567:
1.192 ! nicm 1568: if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE)
1.89 nicm 1569: return (NULL);
1.1 nicm 1570:
1571: buf = xmalloc(1);
1572: off = 0;
1573:
1574: *buf = '\0';
1575:
1576: /*
1577: * The selection extends from selx,sely to (adjusted) cx,cy on
1578: * the base screen.
1579: */
1580:
1581: /* Find start and end. */
1.161 nicm 1582: xx = data->endselx;
1583: yy = data->endsely;
1.2 nicm 1584: if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
1.1 nicm 1585: sx = xx; sy = yy;
1586: ex = data->selx; ey = data->sely;
1587: } else {
1588: sx = data->selx; sy = data->sely;
1589: ex = xx; ey = yy;
1590: }
1591:
1592: /* Trim ex to end of line. */
1.111 nicm 1593: ey_last = window_copy_find_length(wp, ey);
1594: if (ex > ey_last)
1595: ex = ey_last;
1.1 nicm 1596:
1.42 nicm 1597: /*
1598: * Deal with rectangle-copy if necessary; four situations: start of
1599: * first line (firstsx), end of last line (lastex), start (restsx) and
1600: * end (restex) of all other lines.
1601: */
1602: xx = screen_size_x(s);
1.69 nicm 1603:
1604: /*
1605: * Behave according to mode-keys. If it is emacs, copy like emacs,
1606: * keeping the top-left-most character, and dropping the
1607: * bottom-right-most, regardless of copy direction. If it is vi, also
1608: * keep bottom-right-most character.
1609: */
1.136 nicm 1610: keys = options_get_number(wp->window->options, "mode-keys");
1.42 nicm 1611: if (data->rectflag) {
1612: /*
1613: * Need to ignore the column with the cursor in it, which for
1614: * rectangular copy means knowing which side the cursor is on.
1615: */
1.188 nicm 1616: if (data->cursordrag == CURSORDRAG_ENDSEL)
1617: selx = data->selx;
1618: else
1619: selx = data->endselx;
1620: if (selx < data->cx) {
1.42 nicm 1621: /* Selection start is on the left. */
1.69 nicm 1622: if (keys == MODEKEY_EMACS) {
1623: lastex = data->cx;
1624: restex = data->cx;
1625: }
1626: else {
1627: lastex = data->cx + 1;
1628: restex = data->cx + 1;
1629: }
1.188 nicm 1630: firstsx = selx;
1631: restsx = selx;
1.42 nicm 1632: } else {
1633: /* Cursor is on the left. */
1.188 nicm 1634: lastex = selx + 1;
1635: restex = selx + 1;
1.64 nicm 1636: firstsx = data->cx;
1637: restsx = data->cx;
1.42 nicm 1638: }
1639: } else {
1.69 nicm 1640: if (keys == MODEKEY_EMACS)
1641: lastex = ex;
1.74 nicm 1642: else
1.69 nicm 1643: lastex = ex + 1;
1.42 nicm 1644: restex = xx;
1645: firstsx = sx;
1646: restsx = 0;
1647: }
1648:
1.1 nicm 1649: /* Copy the lines. */
1.110 nicm 1650: for (i = sy; i <= ey; i++) {
1651: window_copy_copy_line(wp, &buf, &off, i,
1652: (i == sy ? firstsx : restsx),
1653: (i == ey ? lastex : restex));
1.1 nicm 1654: }
1655:
1.26 nicm 1656: /* Don't bother if no data. */
1657: if (off == 0) {
1.81 nicm 1658: free(buf);
1.89 nicm 1659: return (NULL);
1.26 nicm 1660: }
1.111 nicm 1661: if (keys == MODEKEY_EMACS || lastex <= ey_last)
1662: off -= 1; /* remove final \n (unless at end in vi mode) */
1663: *len = off;
1.89 nicm 1664: return (buf);
1665: }
1666:
1.157 nicm 1667: static void
1.108 nicm 1668: window_copy_copy_buffer(struct window_pane *wp, const char *bufname, void *buf,
1669: size_t len)
1.89 nicm 1670: {
1.91 nicm 1671: struct screen_write_ctx ctx;
1.72 nicm 1672:
1.178 nicm 1673: if (options_get_number(global_options, "set-clipboard") != 0) {
1.91 nicm 1674: screen_write_start(&ctx, wp, NULL);
1675: screen_write_setselection(&ctx, buf, len);
1676: screen_write_stop(&ctx);
1.179 nicm 1677: notify_pane("pane-set-clipboard", wp);
1.91 nicm 1678: }
1.1 nicm 1679:
1.108 nicm 1680: if (paste_set(buf, len, bufname, NULL) != 0)
1.102 nicm 1681: free(buf);
1.89 nicm 1682: }
1683:
1.157 nicm 1684: static void
1.167 nicm 1685: window_copy_copy_pipe(struct window_pane *wp, struct session *s,
1.108 nicm 1686: const char *bufname, const char *arg)
1.89 nicm 1687: {
1.167 nicm 1688: void *buf;
1689: size_t len;
1690: struct job *job;
1691: char *expanded;
1.89 nicm 1692:
1693: buf = window_copy_get_selection(wp, &len);
1694: if (buf == NULL)
1695: return;
1.167 nicm 1696: expanded = format_single(NULL, arg, NULL, s, NULL, wp);
1.89 nicm 1697:
1.187 nicm 1698: job = job_run(expanded, s, NULL, NULL, NULL, NULL, NULL, JOB_NOWAIT);
1.90 nicm 1699: bufferevent_write(job->event, buf, len);
1.120 nicm 1700:
1701: free(expanded);
1.108 nicm 1702: window_copy_copy_buffer(wp, bufname, buf, len);
1.89 nicm 1703: }
1704:
1.157 nicm 1705: static void
1.108 nicm 1706: window_copy_copy_selection(struct window_pane *wp, const char *bufname)
1.89 nicm 1707: {
1.114 nicm 1708: void *buf;
1709: size_t len;
1.89 nicm 1710:
1711: buf = window_copy_get_selection(wp, &len);
1712: if (buf == NULL)
1713: return;
1714:
1.108 nicm 1715: window_copy_copy_buffer(wp, bufname, buf, len);
1.103 nicm 1716: }
1717:
1.157 nicm 1718: static void
1.108 nicm 1719: window_copy_append_selection(struct window_pane *wp, const char *bufname)
1.103 nicm 1720: {
1.108 nicm 1721: char *buf;
1722: struct paste_buffer *pb;
1.132 nicm 1723: const char *bufdata;
1724: size_t len, bufsize;
1.108 nicm 1725: struct screen_write_ctx ctx;
1.103 nicm 1726:
1727: buf = window_copy_get_selection(wp, &len);
1728: if (buf == NULL)
1729: return;
1730:
1.178 nicm 1731: if (options_get_number(global_options, "set-clipboard") != 0) {
1.103 nicm 1732: screen_write_start(&ctx, wp, NULL);
1733: screen_write_setselection(&ctx, buf, len);
1734: screen_write_stop(&ctx);
1.179 nicm 1735: notify_pane("pane-set-clipboard", wp);
1.103 nicm 1736: }
1737:
1.132 nicm 1738: if (bufname == NULL || *bufname == '\0')
1739: pb = paste_get_top(&bufname);
1740: else
1.108 nicm 1741: pb = paste_get_name(bufname);
1.103 nicm 1742: if (pb != NULL) {
1.132 nicm 1743: bufdata = paste_buffer_data(pb, &bufsize);
1744: buf = xrealloc(buf, len + bufsize);
1745: memmove(buf + bufsize, buf, len);
1746: memcpy(buf, bufdata, bufsize);
1747: len += bufsize;
1.103 nicm 1748: }
1.108 nicm 1749: if (paste_set(buf, len, bufname, NULL) != 0)
1.103 nicm 1750: free(buf);
1.1 nicm 1751: }
1752:
1.157 nicm 1753: static void
1.140 nicm 1754: window_copy_copy_line(struct window_pane *wp, char **buf, size_t *off, u_int sy,
1755: u_int sx, u_int ex)
1.1 nicm 1756: {
1.54 nicm 1757: struct window_copy_mode_data *data = wp->modedata;
1758: struct grid *gd = data->backing->grid;
1.140 nicm 1759: struct grid_cell gc;
1.54 nicm 1760: struct grid_line *gl;
1.86 nicm 1761: struct utf8_data ud;
1.54 nicm 1762: u_int i, xx, wrapped = 0;
1.115 nicm 1763: const char *s;
1.1 nicm 1764:
1765: if (sx > ex)
1766: return;
1767:
1.16 nicm 1768: /*
1769: * Work out if the line was wrapped at the screen edge and all of it is
1770: * on screen.
1771: */
1.190 nicm 1772: gl = grid_get_line(gd, sy);
1.35 nicm 1773: if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
1.16 nicm 1774: wrapped = 1;
1775:
1776: /* If the line was wrapped, don't strip spaces (use the full length). */
1777: if (wrapped)
1778: xx = gl->cellsize;
1779: else
1780: xx = window_copy_find_length(wp, sy);
1.1 nicm 1781: if (ex > xx)
1782: ex = xx;
1783: if (sx > xx)
1784: sx = xx;
1785:
1786: if (sx < ex) {
1787: for (i = sx; i < ex; i++) {
1.140 nicm 1788: grid_get_cell(gd, i, sy, &gc);
1789: if (gc.flags & GRID_FLAG_PADDING)
1.1 nicm 1790: continue;
1.140 nicm 1791: utf8_copy(&ud, &gc.data);
1792: if (ud.size == 1 && (gc.attr & GRID_ATTR_CHARSET)) {
1.115 nicm 1793: s = tty_acs_get(NULL, ud.data[0]);
1794: if (s != NULL && strlen(s) <= sizeof ud.data) {
1795: ud.size = strlen(s);
1.117 nicm 1796: memcpy(ud.data, s, ud.size);
1.115 nicm 1797: }
1798: }
1.86 nicm 1799:
1.116 nicm 1800: *buf = xrealloc(*buf, (*off) + ud.size);
1.86 nicm 1801: memcpy(*buf + *off, ud.data, ud.size);
1802: *off += ud.size;
1.1 nicm 1803: }
1804: }
1805:
1.16 nicm 1806: /* Only add a newline if the line wasn't wrapped. */
1.44 nicm 1807: if (!wrapped || ex != xx) {
1.116 nicm 1808: *buf = xrealloc(*buf, (*off) + 1);
1.16 nicm 1809: (*buf)[(*off)++] = '\n';
1810: }
1.1 nicm 1811: }
1812:
1.157 nicm 1813: static void
1.47 nicm 1814: window_copy_clear_selection(struct window_pane *wp)
1815: {
1816: struct window_copy_mode_data *data = wp->modedata;
1817: u_int px, py;
1818:
1819: screen_clear_selection(&data->screen);
1820:
1.161 nicm 1821: data->cursordrag = CURSORDRAG_NONE;
1822:
1.54 nicm 1823: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 1824: px = window_copy_find_length(wp, py);
1825: if (data->cx > px)
1826: window_copy_update_cursor(wp, px, data->cy);
1827: }
1828:
1.157 nicm 1829: static int
1.41 nicm 1830: window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set)
1.1 nicm 1831: {
1.54 nicm 1832: struct window_copy_mode_data *data = wp->modedata;
1.140 nicm 1833: struct grid_cell gc;
1834: const struct utf8_data *ud;
1835:
1836: grid_get_cell(data->backing->grid, px, py, &gc);
1.1 nicm 1837:
1.140 nicm 1838: ud = &gc.data;
1839: if (ud->size != 1 || (gc.flags & GRID_FLAG_PADDING))
1.1 nicm 1840: return (0);
1.140 nicm 1841: if (*ud->data == 0x00 || *ud->data == 0x7f)
1.1 nicm 1842: return (0);
1.140 nicm 1843: return (strchr(set, *ud->data) != NULL);
1.1 nicm 1844: }
1845:
1.157 nicm 1846: static u_int
1.1 nicm 1847: window_copy_find_length(struct window_pane *wp, u_int py)
1848: {
1.54 nicm 1849: struct window_copy_mode_data *data = wp->modedata;
1850: struct screen *s = data->backing;
1.140 nicm 1851: struct grid_cell gc;
1.54 nicm 1852: u_int px;
1.1 nicm 1853:
1.4 nicm 1854: /*
1855: * If the pane has been resized, its grid can contain old overlong
1856: * lines. grid_peek_cell does not allow accessing cells beyond the
1857: * width of the grid, and screen_write_copy treats them as spaces, so
1858: * ignore them here too.
1859: */
1.190 nicm 1860: px = grid_get_line(s->grid, py)->cellsize;
1.54 nicm 1861: if (px > screen_size_x(s))
1862: px = screen_size_x(s);
1.1 nicm 1863: while (px > 0) {
1.140 nicm 1864: grid_get_cell(s->grid, px - 1, py, &gc);
1865: if (gc.data.size != 1 || *gc.data.data != ' ')
1.1 nicm 1866: break;
1867: px--;
1868: }
1869: return (px);
1870: }
1871:
1.157 nicm 1872: static void
1.5 nicm 1873: window_copy_cursor_start_of_line(struct window_pane *wp)
1874: {
1875: struct window_copy_mode_data *data = wp->modedata;
1.58 nicm 1876: struct screen *back_s = data->backing;
1877: struct grid *gd = back_s->grid;
1878: u_int py;
1879:
1.192 ! nicm 1880: if (data->cx == 0 && data->lineflag == LINE_SEL_NONE) {
1.58 nicm 1881: py = screen_hsize(back_s) + data->cy - data->oy;
1.118 nicm 1882: while (py > 0 &&
1.190 nicm 1883: grid_get_line(gd, py - 1)->flags & GRID_LINE_WRAPPED) {
1.58 nicm 1884: window_copy_cursor_up(wp, 0);
1885: py = screen_hsize(back_s) + data->cy - data->oy;
1886: }
1887: }
1.18 nicm 1888: window_copy_update_cursor(wp, 0, data->cy);
1.96 nicm 1889: if (window_copy_update_selection(wp, 1))
1.5 nicm 1890: window_copy_redraw_lines(wp, data->cy, 1);
1.6 nicm 1891: }
1892:
1.157 nicm 1893: static void
1.6 nicm 1894: window_copy_cursor_back_to_indentation(struct window_pane *wp)
1895: {
1896: struct window_copy_mode_data *data = wp->modedata;
1897: u_int px, py, xx;
1.140 nicm 1898: struct grid_cell gc;
1.6 nicm 1899:
1900: px = 0;
1.54 nicm 1901: py = screen_hsize(data->backing) + data->cy - data->oy;
1.6 nicm 1902: xx = window_copy_find_length(wp, py);
1903:
1904: while (px < xx) {
1.140 nicm 1905: grid_get_cell(data->backing->grid, px, py, &gc);
1906: if (gc.data.size != 1 || *gc.data.data != ' ')
1.6 nicm 1907: break;
1908: px++;
1909: }
1910:
1.18 nicm 1911: window_copy_update_cursor(wp, px, data->cy);
1.96 nicm 1912: if (window_copy_update_selection(wp, 1))
1.18 nicm 1913: window_copy_redraw_lines(wp, data->cy, 1);
1.5 nicm 1914: }
1915:
1.157 nicm 1916: static void
1.5 nicm 1917: window_copy_cursor_end_of_line(struct window_pane *wp)
1918: {
1919: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 1920: struct screen *back_s = data->backing;
1921: struct grid *gd = back_s->grid;
1.190 nicm 1922: struct grid_line *gl;
1.5 nicm 1923: u_int px, py;
1924:
1.54 nicm 1925: py = screen_hsize(back_s) + data->cy - data->oy;
1.5 nicm 1926: px = window_copy_find_length(wp, py);
1927:
1.192 ! nicm 1928: if (data->cx == px && data->lineflag == LINE_SEL_NONE) {
! 1929: if (data->screen.sel != NULL && data->rectflag)
1.54 nicm 1930: px = screen_size_x(back_s);
1.190 nicm 1931: gl = grid_get_line(gd, py);
1932: if (gl->flags & GRID_LINE_WRAPPED) {
1933: while (py < gd->sy + gd->hsize) {
1934: gl = grid_get_line(gd, py);
1935: if (~gl->flags & GRID_LINE_WRAPPED)
1936: break;
1.49 nicm 1937: window_copy_cursor_down(wp, 0);
1.190 nicm 1938: py = screen_hsize(back_s) + data->cy - data->oy;
1.49 nicm 1939: }
1940: px = window_copy_find_length(wp, py);
1941: }
1942: }
1.18 nicm 1943: window_copy_update_cursor(wp, px, data->cy);
1.49 nicm 1944:
1.96 nicm 1945: if (window_copy_update_selection(wp, 1))
1.18 nicm 1946: window_copy_redraw_lines(wp, data->cy, 1);
1.95 nicm 1947: }
1948:
1.157 nicm 1949: static void
1.95 nicm 1950: window_copy_other_end(struct window_pane *wp)
1951: {
1952: struct window_copy_mode_data *data = wp->modedata;
1953: struct screen *s = &data->screen;
1.161 nicm 1954: u_int selx, sely, cy, yy, hsize;
1.95 nicm 1955:
1.192 ! nicm 1956: if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
1.95 nicm 1957: return;
1958:
1.192 ! nicm 1959: if (data->lineflag == LINE_SEL_LEFT_RIGHT)
! 1960: data->lineflag = LINE_SEL_RIGHT_LEFT;
! 1961: else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
! 1962: data->lineflag = LINE_SEL_LEFT_RIGHT;
1.118 nicm 1963:
1.161 nicm 1964: switch (data->cursordrag) {
1965: case CURSORDRAG_NONE:
1966: case CURSORDRAG_SEL:
1967: data->cursordrag = CURSORDRAG_ENDSEL;
1968: break;
1969: case CURSORDRAG_ENDSEL:
1970: data->cursordrag = CURSORDRAG_SEL;
1971: break;
1972: }
1973:
1974: selx = data->endselx;
1975: sely = data->endsely;
1976: if (data->cursordrag == CURSORDRAG_SEL) {
1977: selx = data->selx;
1978: sely = data->sely;
1979: }
1980:
1.95 nicm 1981: cy = data->cy;
1982: yy = screen_hsize(data->backing) + data->cy - data->oy;
1983:
1984: data->cx = selx;
1985:
1.122 nicm 1986: hsize = screen_hsize(data->backing);
1.161 nicm 1987: if (sely < hsize - data->oy) { /* above */
1.122 nicm 1988: data->oy = hsize - sely;
1.95 nicm 1989: data->cy = 0;
1.161 nicm 1990: } else if (sely > hsize - data->oy + screen_size_y(s)) { /* below */
1.122 nicm 1991: data->oy = hsize - sely + screen_size_y(s) - 1;
1.95 nicm 1992: data->cy = screen_size_y(s) - 1;
1993: } else
1994: data->cy = cy + sely - yy;
1995:
1.161 nicm 1996: window_copy_update_selection(wp, 1);
1.95 nicm 1997: window_copy_redraw_screen(wp);
1.5 nicm 1998: }
1999:
1.157 nicm 2000: static void
1.1 nicm 2001: window_copy_cursor_left(struct window_pane *wp)
2002: {
2003: struct window_copy_mode_data *data = wp->modedata;
1.168 nicm 2004: u_int py, cx;
2005: struct grid_cell gc;
1.1 nicm 2006:
1.145 nicm 2007: py = screen_hsize(data->backing) + data->cy - data->oy;
1.168 nicm 2008: cx = data->cx;
2009: while (cx > 0) {
2010: grid_get_cell(data->backing->grid, cx, py, &gc);
2011: if (~gc.flags & GRID_FLAG_PADDING)
2012: break;
2013: cx--;
2014: }
2015: if (cx == 0 && py > 0) {
1.28 nicm 2016: window_copy_cursor_up(wp, 0);
1.18 nicm 2017: window_copy_cursor_end_of_line(wp);
1.168 nicm 2018: } else if (cx > 0) {
2019: window_copy_update_cursor(wp, cx - 1, data->cy);
1.96 nicm 2020: if (window_copy_update_selection(wp, 1))
1.1 nicm 2021: window_copy_redraw_lines(wp, data->cy, 1);
2022: }
2023: }
2024:
1.157 nicm 2025: static void
1.1 nicm 2026: window_copy_cursor_right(struct window_pane *wp)
2027: {
2028: struct window_copy_mode_data *data = wp->modedata;
1.168 nicm 2029: u_int px, py, yy, cx, cy;
2030: struct grid_cell gc;
1.1 nicm 2031:
1.145 nicm 2032: py = screen_hsize(data->backing) + data->cy - data->oy;
2033: yy = screen_hsize(data->backing) + screen_size_y(data->backing) - 1;
1.192 ! nicm 2034: if (data->screen.sel != NULL && data->rectflag)
1.47 nicm 2035: px = screen_size_x(&data->screen);
1.168 nicm 2036: else
1.47 nicm 2037: px = window_copy_find_length(wp, py);
1.1 nicm 2038:
1.145 nicm 2039: if (data->cx >= px && py < yy) {
1.1 nicm 2040: window_copy_cursor_start_of_line(wp);
1.28 nicm 2041: window_copy_cursor_down(wp, 0);
1.145 nicm 2042: } else if (data->cx < px) {
1.168 nicm 2043: cx = data->cx + 1;
2044: cy = screen_hsize(data->backing) + data->cy - data->oy;
2045: while (cx < px) {
2046: grid_get_cell(data->backing->grid, cx, cy, &gc);
2047: if (~gc.flags & GRID_FLAG_PADDING)
2048: break;
2049: cx++;
2050: }
2051: window_copy_update_cursor(wp, cx, data->cy);
1.96 nicm 2052: if (window_copy_update_selection(wp, 1))
1.1 nicm 2053: window_copy_redraw_lines(wp, data->cy, 1);
2054: }
2055: }
2056:
1.157 nicm 2057: static void
1.28 nicm 2058: window_copy_cursor_up(struct window_pane *wp, int scroll_only)
1.1 nicm 2059: {
2060: struct window_copy_mode_data *data = wp->modedata;
1.36 nicm 2061: struct screen *s = &data->screen;
1.1 nicm 2062: u_int ox, oy, px, py;
2063:
1.54 nicm 2064: oy = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 2065: ox = window_copy_find_length(wp, oy);
1.77 nicm 2066: if (data->cx != ox) {
1.25 nicm 2067: data->lastcx = data->cx;
2068: data->lastsx = ox;
2069: }
1.1 nicm 2070:
1.192 ! nicm 2071: if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
1.118 nicm 2072: window_copy_other_end(wp);
2073:
1.25 nicm 2074: data->cx = data->lastcx;
1.28 nicm 2075: if (scroll_only || data->cy == 0) {
1.1 nicm 2076: window_copy_scroll_down(wp, 1);
1.36 nicm 2077: if (scroll_only) {
2078: if (data->cy == screen_size_y(s) - 1)
2079: window_copy_redraw_lines(wp, data->cy, 1);
2080: else
2081: window_copy_redraw_lines(wp, data->cy, 2);
2082: }
1.28 nicm 2083: } else {
1.18 nicm 2084: window_copy_update_cursor(wp, data->cx, data->cy - 1);
1.96 nicm 2085: if (window_copy_update_selection(wp, 1)) {
1.36 nicm 2086: if (data->cy == screen_size_y(s) - 1)
2087: window_copy_redraw_lines(wp, data->cy, 1);
2088: else
2089: window_copy_redraw_lines(wp, data->cy, 2);
2090: }
1.1 nicm 2091: }
2092:
1.192 ! nicm 2093: if (data->screen.sel != NULL || !data->rectflag) {
1.54 nicm 2094: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 2095: px = window_copy_find_length(wp, py);
1.49 nicm 2096: if ((data->cx >= data->lastsx && data->cx != px) ||
2097: data->cx > px)
1.47 nicm 2098: window_copy_cursor_end_of_line(wp);
2099: }
1.118 nicm 2100:
1.192 ! nicm 2101: if (data->lineflag == LINE_SEL_LEFT_RIGHT)
1.118 nicm 2102: window_copy_cursor_end_of_line(wp);
1.192 ! nicm 2103: else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
1.118 nicm 2104: window_copy_cursor_start_of_line(wp);
1.1 nicm 2105: }
2106:
1.157 nicm 2107: static void
1.28 nicm 2108: window_copy_cursor_down(struct window_pane *wp, int scroll_only)
1.1 nicm 2109: {
2110: struct window_copy_mode_data *data = wp->modedata;
2111: struct screen *s = &data->screen;
2112: u_int ox, oy, px, py;
2113:
1.54 nicm 2114: oy = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 2115: ox = window_copy_find_length(wp, oy);
1.77 nicm 2116: if (data->cx != ox) {
1.25 nicm 2117: data->lastcx = data->cx;
2118: data->lastsx = ox;
2119: }
1.1 nicm 2120:
1.192 ! nicm 2121: if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
1.118 nicm 2122: window_copy_other_end(wp);
2123:
1.25 nicm 2124: data->cx = data->lastcx;
1.28 nicm 2125: if (scroll_only || data->cy == screen_size_y(s) - 1) {
1.1 nicm 2126: window_copy_scroll_up(wp, 1);
1.31 nicm 2127: if (scroll_only && data->cy > 0)
1.28 nicm 2128: window_copy_redraw_lines(wp, data->cy - 1, 2);
2129: } else {
1.18 nicm 2130: window_copy_update_cursor(wp, data->cx, data->cy + 1);
1.96 nicm 2131: if (window_copy_update_selection(wp, 1))
1.1 nicm 2132: window_copy_redraw_lines(wp, data->cy - 1, 2);
2133: }
2134:
1.192 ! nicm 2135: if (data->screen.sel == NULL || !data->rectflag) {
1.54 nicm 2136: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 2137: px = window_copy_find_length(wp, py);
1.49 nicm 2138: if ((data->cx >= data->lastsx && data->cx != px) ||
2139: data->cx > px)
1.47 nicm 2140: window_copy_cursor_end_of_line(wp);
1.52 nicm 2141: }
1.118 nicm 2142:
1.192 ! nicm 2143: if (data->lineflag == LINE_SEL_LEFT_RIGHT)
1.118 nicm 2144: window_copy_cursor_end_of_line(wp);
1.192 ! nicm 2145: else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
1.118 nicm 2146: window_copy_cursor_start_of_line(wp);
1.52 nicm 2147: }
2148:
1.157 nicm 2149: static void
1.52 nicm 2150: window_copy_cursor_jump(struct window_pane *wp)
2151: {
2152: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 2153: struct screen *back_s = data->backing;
1.140 nicm 2154: struct grid_cell gc;
1.67 nicm 2155: u_int px, py, xx;
1.52 nicm 2156:
2157: px = data->cx + 1;
1.54 nicm 2158: py = screen_hsize(back_s) + data->cy - data->oy;
1.52 nicm 2159: xx = window_copy_find_length(wp, py);
2160:
2161: while (px < xx) {
1.140 nicm 2162: grid_get_cell(back_s->grid, px, py, &gc);
2163: if (!(gc.flags & GRID_FLAG_PADDING) &&
2164: gc.data.size == 1 && *gc.data.data == data->jumpchar) {
1.52 nicm 2165: window_copy_update_cursor(wp, px, data->cy);
1.96 nicm 2166: if (window_copy_update_selection(wp, 1))
1.52 nicm 2167: window_copy_redraw_lines(wp, data->cy, 1);
2168: return;
2169: }
2170: px++;
2171: }
2172: }
2173:
1.157 nicm 2174: static void
1.52 nicm 2175: window_copy_cursor_jump_back(struct window_pane *wp)
2176: {
2177: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 2178: struct screen *back_s = data->backing;
1.140 nicm 2179: struct grid_cell gc;
1.67 nicm 2180: u_int px, py;
1.52 nicm 2181:
2182: px = data->cx;
1.54 nicm 2183: py = screen_hsize(back_s) + data->cy - data->oy;
1.52 nicm 2184:
2185: if (px > 0)
2186: px--;
2187:
2188: for (;;) {
1.140 nicm 2189: grid_get_cell(back_s->grid, px, py, &gc);
2190: if (!(gc.flags & GRID_FLAG_PADDING) &&
2191: gc.data.size == 1 && *gc.data.data == data->jumpchar) {
1.52 nicm 2192: window_copy_update_cursor(wp, px, data->cy);
1.96 nicm 2193: if (window_copy_update_selection(wp, 1))
1.76 nicm 2194: window_copy_redraw_lines(wp, data->cy, 1);
2195: return;
2196: }
2197: if (px == 0)
2198: break;
2199: px--;
2200: }
2201: }
2202:
1.157 nicm 2203: static void
1.184 nicm 2204: window_copy_cursor_jump_to(struct window_pane *wp)
1.76 nicm 2205: {
2206: struct window_copy_mode_data *data = wp->modedata;
2207: struct screen *back_s = data->backing;
1.140 nicm 2208: struct grid_cell gc;
1.76 nicm 2209: u_int px, py, xx;
2210:
1.184 nicm 2211: px = data->cx + 2;
1.76 nicm 2212: py = screen_hsize(back_s) + data->cy - data->oy;
2213: xx = window_copy_find_length(wp, py);
2214:
2215: while (px < xx) {
1.140 nicm 2216: grid_get_cell(back_s->grid, px, py, &gc);
2217: if (!(gc.flags & GRID_FLAG_PADDING) &&
2218: gc.data.size == 1 && *gc.data.data == data->jumpchar) {
1.76 nicm 2219: window_copy_update_cursor(wp, px - 1, data->cy);
1.96 nicm 2220: if (window_copy_update_selection(wp, 1))
1.76 nicm 2221: window_copy_redraw_lines(wp, data->cy, 1);
2222: return;
2223: }
2224: px++;
2225: }
2226: }
2227:
1.157 nicm 2228: static void
1.184 nicm 2229: window_copy_cursor_jump_to_back(struct window_pane *wp)
1.76 nicm 2230: {
2231: struct window_copy_mode_data *data = wp->modedata;
2232: struct screen *back_s = data->backing;
1.140 nicm 2233: struct grid_cell gc;
1.76 nicm 2234: u_int px, py;
2235:
2236: px = data->cx;
2237: py = screen_hsize(back_s) + data->cy - data->oy;
2238:
2239: if (px > 0)
1.127 nicm 2240: px--;
2241:
1.184 nicm 2242: if (px > 0)
1.76 nicm 2243: px--;
2244:
2245: for (;;) {
1.140 nicm 2246: grid_get_cell(back_s->grid, px, py, &gc);
2247: if (!(gc.flags & GRID_FLAG_PADDING) &&
2248: gc.data.size == 1 && *gc.data.data == data->jumpchar) {
1.76 nicm 2249: window_copy_update_cursor(wp, px + 1, data->cy);
1.96 nicm 2250: if (window_copy_update_selection(wp, 1))
1.52 nicm 2251: window_copy_redraw_lines(wp, data->cy, 1);
2252: return;
2253: }
2254: if (px == 0)
2255: break;
2256: px--;
1.47 nicm 2257: }
1.1 nicm 2258: }
2259:
1.157 nicm 2260: static void
1.41 nicm 2261: window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
1.40 nicm 2262: {
2263: struct window_copy_mode_data *data = wp->modedata;
1.54 nicm 2264: struct screen *back_s = data->backing;
1.40 nicm 2265: u_int px, py, xx, yy;
1.48 nicm 2266: int expected = 0;
1.40 nicm 2267:
2268: px = data->cx;
1.54 nicm 2269: py = screen_hsize(back_s) + data->cy - data->oy;
1.40 nicm 2270: xx = window_copy_find_length(wp, py);
1.54 nicm 2271: yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
1.40 nicm 2272:
1.48 nicm 2273: /*
2274: * First skip past any nonword characters and then any word characters.
2275: *
2276: * expected is initially set to 0 for the former and then 1 for the
2277: * latter.
2278: */
2279: do {
2280: while (px > xx ||
2281: window_copy_in_set(wp, px, py, separators) == expected) {
2282: /* Move down if we're past the end of the line. */
2283: if (px > xx) {
2284: if (py == yy)
2285: return;
2286: window_copy_cursor_down(wp, 0);
2287: px = 0;
2288:
1.54 nicm 2289: py = screen_hsize(back_s) + data->cy - data->oy;
1.48 nicm 2290: xx = window_copy_find_length(wp, py);
2291: } else
2292: px++;
2293: }
2294: expected = !expected;
2295: } while (expected == 1);
1.40 nicm 2296:
2297: window_copy_update_cursor(wp, px, data->cy);
1.96 nicm 2298: if (window_copy_update_selection(wp, 1))
1.40 nicm 2299: window_copy_redraw_lines(wp, data->cy, 1);
2300: }
2301:
1.157 nicm 2302: static void
1.106 nicm 2303: window_copy_cursor_next_word_end(struct window_pane *wp,
2304: const char *separators)
1.1 nicm 2305: {
2306: struct window_copy_mode_data *data = wp->modedata;
1.136 nicm 2307: struct options *oo = wp->window->options;
1.54 nicm 2308: struct screen *back_s = data->backing;
1.39 nicm 2309: u_int px, py, xx, yy;
1.94 nicm 2310: int keys, expected = 1;
1.1 nicm 2311:
1.18 nicm 2312: px = data->cx;
1.54 nicm 2313: py = screen_hsize(back_s) + data->cy - data->oy;
1.1 nicm 2314: xx = window_copy_find_length(wp, py);
1.54 nicm 2315: yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
1.1 nicm 2316:
1.94 nicm 2317: keys = options_get_number(oo, "mode-keys");
2318: if (keys == MODEKEY_VI && !window_copy_in_set(wp, px, py, separators))
2319: px++;
2320:
1.48 nicm 2321: /*
2322: * First skip past any word characters, then any nonword characters.
2323: *
2324: * expected is initially set to 1 for the former and then 0 for the
2325: * latter.
2326: */
2327: do {
2328: while (px > xx ||
2329: window_copy_in_set(wp, px, py, separators) == expected) {
2330: /* Move down if we're past the end of the line. */
2331: if (px > xx) {
2332: if (py == yy)
2333: return;
2334: window_copy_cursor_down(wp, 0);
2335: px = 0;
2336:
1.54 nicm 2337: py = screen_hsize(back_s) + data->cy - data->oy;
1.48 nicm 2338: xx = window_copy_find_length(wp, py);
2339: } else
2340: px++;
2341: }
2342: expected = !expected;
2343: } while (expected == 0);
1.92 nicm 2344:
1.94 nicm 2345: if (keys == MODEKEY_VI && px != 0)
1.92 nicm 2346: px--;
1.18 nicm 2347:
2348: window_copy_update_cursor(wp, px, data->cy);
1.96 nicm 2349: if (window_copy_update_selection(wp, 1))
1.18 nicm 2350: window_copy_redraw_lines(wp, data->cy, 1);
1.1 nicm 2351: }
2352:
1.8 nicm 2353: /* Move to the previous place where a word begins. */
1.157 nicm 2354: static void
1.106 nicm 2355: window_copy_cursor_previous_word(struct window_pane *wp,
2356: const char *separators)
1.1 nicm 2357: {
2358: struct window_copy_mode_data *data = wp->modedata;
1.8 nicm 2359: u_int px, py;
1.1 nicm 2360:
1.18 nicm 2361: px = data->cx;
1.54 nicm 2362: py = screen_hsize(data->backing) + data->cy - data->oy;
1.1 nicm 2363:
1.8 nicm 2364: /* Move back to the previous word character. */
1.1 nicm 2365: for (;;) {
1.8 nicm 2366: if (px > 0) {
2367: px--;
1.41 nicm 2368: if (!window_copy_in_set(wp, px, py, separators))
1.1 nicm 2369: break;
1.8 nicm 2370: } else {
2371: if (data->cy == 0 &&
1.54 nicm 2372: (screen_hsize(data->backing) == 0 ||
2373: data->oy >= screen_hsize(data->backing) - 1))
1.8 nicm 2374: goto out;
1.28 nicm 2375: window_copy_cursor_up(wp, 0);
1.1 nicm 2376:
1.54 nicm 2377: py = screen_hsize(data->backing) + data->cy - data->oy;
1.8 nicm 2378: px = window_copy_find_length(wp, py);
1.1 nicm 2379: }
1.8 nicm 2380: }
1.1 nicm 2381:
1.8 nicm 2382: /* Move back to the beginning of this word. */
1.41 nicm 2383: while (px > 0 && !window_copy_in_set(wp, px - 1, py, separators))
1.1 nicm 2384: px--;
1.8 nicm 2385:
1.1 nicm 2386: out:
1.18 nicm 2387: window_copy_update_cursor(wp, px, data->cy);
1.96 nicm 2388: if (window_copy_update_selection(wp, 1))
1.18 nicm 2389: window_copy_redraw_lines(wp, data->cy, 1);
1.1 nicm 2390: }
2391:
1.157 nicm 2392: static void
1.1 nicm 2393: window_copy_scroll_up(struct window_pane *wp, u_int ny)
2394: {
2395: struct window_copy_mode_data *data = wp->modedata;
2396: struct screen *s = &data->screen;
2397: struct screen_write_ctx ctx;
2398:
2399: if (data->oy < ny)
2400: ny = data->oy;
2401: if (ny == 0)
2402: return;
2403: data->oy -= ny;
2404:
1.96 nicm 2405: window_copy_update_selection(wp, 0);
2406:
1.1 nicm 2407: screen_write_start(&ctx, wp, NULL);
2408: screen_write_cursormove(&ctx, 0, 0);
1.159 nicm 2409: screen_write_deleteline(&ctx, ny, 8);
1.1 nicm 2410: window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, ny);
2411: window_copy_write_line(wp, &ctx, 0);
1.31 nicm 2412: if (screen_size_y(s) > 1)
2413: window_copy_write_line(wp, &ctx, 1);
2414: if (screen_size_y(s) > 3)
2415: window_copy_write_line(wp, &ctx, screen_size_y(s) - 2);
1.192 ! nicm 2416: if (s->sel != NULL && screen_size_y(s) > ny)
1.1 nicm 2417: window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1);
2418: screen_write_cursormove(&ctx, data->cx, data->cy);
2419: screen_write_stop(&ctx);
2420: }
2421:
1.157 nicm 2422: static void
1.1 nicm 2423: window_copy_scroll_down(struct window_pane *wp, u_int ny)
2424: {
2425: struct window_copy_mode_data *data = wp->modedata;
2426: struct screen *s = &data->screen;
2427: struct screen_write_ctx ctx;
2428:
1.54 nicm 2429: if (ny > screen_hsize(data->backing))
1.1 nicm 2430: return;
2431:
1.54 nicm 2432: if (data->oy > screen_hsize(data->backing) - ny)
2433: ny = screen_hsize(data->backing) - data->oy;
1.1 nicm 2434: if (ny == 0)
2435: return;
2436: data->oy += ny;
2437:
1.96 nicm 2438: window_copy_update_selection(wp, 0);
2439:
1.1 nicm 2440: screen_write_start(&ctx, wp, NULL);
2441: screen_write_cursormove(&ctx, 0, 0);
1.159 nicm 2442: screen_write_insertline(&ctx, ny, 8);
1.1 nicm 2443: window_copy_write_lines(wp, &ctx, 0, ny);
1.192 ! nicm 2444: if (s->sel != NULL && screen_size_y(s) > ny)
1.1 nicm 2445: window_copy_write_line(wp, &ctx, ny);
1.96 nicm 2446: else if (ny == 1) /* nuke position */
1.1 nicm 2447: window_copy_write_line(wp, &ctx, 1);
2448: screen_write_cursormove(&ctx, data->cx, data->cy);
2449: screen_write_stop(&ctx);
1.135 nicm 2450: }
2451:
1.180 nicm 2452: void
2453: window_copy_add_formats(struct window_pane *wp, struct format_tree *ft)
1.135 nicm 2454: {
2455: struct window_copy_mode_data *data = wp->modedata;
2456:
2457: if (wp->mode != &window_copy_mode)
1.180 nicm 2458: return;
2459:
1.192 ! nicm 2460: format_add(ft, "selection_present", "%d", data->screen.sel != NULL);
1.180 nicm 2461: format_add(ft, "scroll_position", "%d", data->oy);
1.191 nicm 2462: format_add(ft, "rectangle_toggle", "%d", data->rectflag);
1.1 nicm 2463: }
1.42 nicm 2464:
1.157 nicm 2465: static void
1.42 nicm 2466: window_copy_rectangle_toggle(struct window_pane *wp)
2467: {
2468: struct window_copy_mode_data *data = wp->modedata;
1.47 nicm 2469: u_int px, py;
1.42 nicm 2470:
2471: data->rectflag = !data->rectflag;
1.47 nicm 2472:
1.54 nicm 2473: py = screen_hsize(data->backing) + data->cy - data->oy;
1.47 nicm 2474: px = window_copy_find_length(wp, py);
2475: if (data->cx > px)
2476: window_copy_update_cursor(wp, px, data->cy);
1.42 nicm 2477:
1.96 nicm 2478: window_copy_update_selection(wp, 1);
1.42 nicm 2479: window_copy_redraw_screen(wp);
1.156 nicm 2480: }
2481:
1.157 nicm 2482: static void
1.156 nicm 2483: window_copy_move_mouse(struct mouse_event *m)
2484: {
2485: struct window_pane *wp;
2486: u_int x, y;
2487:
2488: wp = cmd_mouse_pane(m, NULL, NULL);
2489: if (wp == NULL || wp->mode != &window_copy_mode)
2490: return;
2491:
1.183 nicm 2492: if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
1.156 nicm 2493: return;
2494:
2495: window_copy_update_cursor(wp, x, y);
1.126 nicm 2496: }
2497:
2498: void
1.141 nicm 2499: window_copy_start_drag(struct client *c, struct mouse_event *m)
1.126 nicm 2500: {
1.128 nicm 2501: struct window_pane *wp;
2502: u_int x, y;
1.126 nicm 2503:
1.155 nicm 2504: if (c == NULL)
2505: return;
2506:
1.126 nicm 2507: wp = cmd_mouse_pane(m, NULL, NULL);
1.129 nicm 2508: if (wp == NULL || wp->mode != &window_copy_mode)
1.126 nicm 2509: return;
2510:
2511: if (cmd_mouse_at(wp, m, &x, &y, 1) != 0)
2512: return;
2513:
2514: c->tty.mouse_drag_update = window_copy_drag_update;
1.155 nicm 2515: c->tty.mouse_drag_release = NULL; /* will fire MouseDragEnd key */
1.126 nicm 2516:
2517: window_copy_update_cursor(wp, x, y);
2518: window_copy_start_selection(wp);
2519: window_copy_redraw_screen(wp);
2520: }
2521:
1.157 nicm 2522: static void
1.141 nicm 2523: window_copy_drag_update(__unused struct client *c, struct mouse_event *m)
1.126 nicm 2524: {
2525: struct window_pane *wp;
2526: struct window_copy_mode_data *data;
2527: u_int x, y, old_cy;
2528:
2529: wp = cmd_mouse_pane(m, NULL, NULL);
1.129 nicm 2530: if (wp == NULL || wp->mode != &window_copy_mode)
1.126 nicm 2531: return;
2532: data = wp->modedata;
2533:
2534: if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
2535: return;
2536: old_cy = data->cy;
2537:
2538: window_copy_update_cursor(wp, x, y);
2539: if (window_copy_update_selection(wp, 1))
2540: window_copy_redraw_selection(wp, old_cy);
1.42 nicm 2541: }