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