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