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