4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
27 struct screen
*window_copy_init(struct window_pane
*);
28 void window_copy_free(struct window_pane
*);
29 void window_copy_resize(struct window_pane
*, u_int
, u_int
);
30 void window_copy_key(struct window_pane
*, struct session
*, int);
31 int window_copy_key_input(struct window_pane
*, int);
32 int window_copy_key_numeric_prefix(struct window_pane
*, int);
33 void window_copy_mouse(
34 struct window_pane
*, struct session
*, struct mouse_event
*);
36 void window_copy_redraw_lines(struct window_pane
*, u_int
, u_int
);
37 void window_copy_redraw_screen(struct window_pane
*);
38 void window_copy_write_line(
39 struct window_pane
*, struct screen_write_ctx
*, u_int
);
40 void window_copy_write_lines(
41 struct window_pane
*, struct screen_write_ctx
*, u_int
, u_int
);
43 void window_copy_scroll_to(struct window_pane
*, u_int
, u_int
);
44 int window_copy_search_compare(
45 struct grid
*, u_int
, u_int
, struct grid
*, u_int
, int);
46 int window_copy_search_lr(
47 struct grid
*, struct grid
*, u_int
*, u_int
, u_int
, u_int
, int);
48 int window_copy_search_rl(
49 struct grid
*, struct grid
*, u_int
*, u_int
, u_int
, u_int
, int);
50 void window_copy_search_up(struct window_pane
*, const char *);
51 void window_copy_search_down(struct window_pane
*, const char *);
52 void window_copy_goto_line(struct window_pane
*, const char *);
53 void window_copy_update_cursor(struct window_pane
*, u_int
, u_int
);
54 void window_copy_start_selection(struct window_pane
*);
55 int window_copy_update_selection(struct window_pane
*, int);
56 void *window_copy_get_selection(struct window_pane
*, size_t *);
57 void window_copy_copy_buffer(struct window_pane
*, int, void *, size_t);
58 void window_copy_copy_pipe(
59 struct window_pane
*, struct session
*, int, const char *);
60 void window_copy_copy_selection(struct window_pane
*, int);
61 void window_copy_clear_selection(struct window_pane
*);
62 void window_copy_copy_line(
63 struct window_pane
*, char **, size_t *, u_int
, u_int
, u_int
);
64 int window_copy_in_set(struct window_pane
*, u_int
, u_int
, const char *);
65 u_int
window_copy_find_length(struct window_pane
*, u_int
);
66 void window_copy_cursor_start_of_line(struct window_pane
*);
67 void window_copy_cursor_back_to_indentation(struct window_pane
*);
68 void window_copy_cursor_end_of_line(struct window_pane
*);
69 void window_copy_other_end(struct window_pane
*);
70 void window_copy_cursor_left(struct window_pane
*);
71 void window_copy_cursor_right(struct window_pane
*);
72 void window_copy_cursor_up(struct window_pane
*, int);
73 void window_copy_cursor_down(struct window_pane
*, int);
74 void window_copy_cursor_jump(struct window_pane
*);
75 void window_copy_cursor_jump_back(struct window_pane
*);
76 void window_copy_cursor_jump_to(struct window_pane
*);
77 void window_copy_cursor_jump_to_back(struct window_pane
*);
78 void window_copy_cursor_next_word(struct window_pane
*, const char *);
79 void window_copy_cursor_next_word_end(struct window_pane
*, const char *);
80 void window_copy_cursor_previous_word(struct window_pane
*, const char *);
81 void window_copy_scroll_up(struct window_pane
*, u_int
);
82 void window_copy_scroll_down(struct window_pane
*, u_int
);
83 void window_copy_rectangle_toggle(struct window_pane
*);
85 const struct window_mode window_copy_mode
= {
94 enum window_copy_input_type
{
96 WINDOW_COPY_NUMERICPREFIX
,
98 WINDOW_COPY_SEARCHDOWN
,
99 WINDOW_COPY_JUMPFORWARD
,
100 WINDOW_COPY_JUMPBACK
,
101 WINDOW_COPY_JUMPTOFORWARD
,
102 WINDOW_COPY_JUMPTOBACK
,
103 WINDOW_COPY_GOTOLINE
,
107 * Copy-mode's visible screen (the "screen" field) is filled from one of
108 * two sources: the original contents of the pane (used when we
109 * actually enter via the "copy-mode" command, to copy the contents of
110 * the current pane), or else a series of lines containing the output
111 * from an output-writing tmux command (such as any of the "show-*" or
112 * "list-*" commands).
114 * In either case, the full content of the copy-mode grid is pointed at
115 * by the "backing" field, and is copied into "screen" as needed (that
116 * is, when scrolling occurs). When copy-mode is backed by a pane,
117 * backing points directly at that pane's screen structure (&wp->base);
118 * when backed by a list of output-lines from a command, it points at
119 * a newly-allocated screen structure (which is deallocated when the
122 struct window_copy_mode_data
{
123 struct screen screen
;
125 struct screen
*backing
;
126 int backing_written
; /* backing display has started */
128 struct mode_key_data mdata
;
135 u_int rectflag
; /* are we in rectangle copy mode? */
140 u_int lastcx
; /* position in last line with content */
141 u_int lastsx
; /* size of last line with content */
143 enum window_copy_input_type inputtype
;
144 const char *inputprompt
;
149 enum window_copy_input_type searchtype
;
152 enum window_copy_input_type jumptype
;
157 window_copy_init(struct window_pane
*wp
)
159 struct window_copy_mode_data
*data
;
163 wp
->modedata
= data
= xmalloc(sizeof *data
);
171 data
->backing_written
= 0;
175 data
->inputtype
= WINDOW_COPY_OFF
;
176 data
->inputprompt
= NULL
;
177 data
->inputstr
= xstrdup("");
178 data
->numprefix
= -1;
180 data
->searchtype
= WINDOW_COPY_OFF
;
181 data
->searchstr
= NULL
;
184 bufferevent_disable(wp
->event
, EV_READ
|EV_WRITE
);
186 data
->jumptype
= WINDOW_COPY_OFF
;
187 data
->jumpchar
= '\0';
190 screen_init(s
, screen_size_x(&wp
->base
), screen_size_y(&wp
->base
), 0);
191 if (options_get_number(&wp
->window
->options
, "mode-mouse"))
192 s
->mode
|= MODE_MOUSE_STANDARD
;
194 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
195 if (keys
== MODEKEY_EMACS
)
196 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_copy
);
198 mode_key_init(&data
->mdata
, &mode_key_tree_vi_copy
);
200 data
->backing
= NULL
;
206 window_copy_init_from_pane(struct window_pane
*wp
)
208 struct window_copy_mode_data
*data
= wp
->modedata
;
209 struct screen
*s
= &data
->screen
;
210 struct screen_write_ctx ctx
;
213 if (wp
->mode
!= &window_copy_mode
)
214 fatalx("not in copy mode");
216 data
->backing
= &wp
->base
;
217 data
->cx
= data
->backing
->cx
;
218 data
->cy
= data
->backing
->cy
;
223 screen_write_start(&ctx
, NULL
, s
);
224 for (i
= 0; i
< screen_size_y(s
); i
++)
225 window_copy_write_line(wp
, &ctx
, i
);
226 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
227 screen_write_stop(&ctx
);
231 window_copy_init_for_output(struct window_pane
*wp
)
233 struct window_copy_mode_data
*data
= wp
->modedata
;
235 data
->backing
= xmalloc(sizeof *data
->backing
);
236 screen_init(data
->backing
, screen_size_x(&wp
->base
),
237 screen_size_y(&wp
->base
), UINT_MAX
);
238 data
->backing
->mode
&= ~MODE_WRAP
;
242 window_copy_free(struct window_pane
*wp
)
244 struct window_copy_mode_data
*data
= wp
->modedata
;
247 bufferevent_enable(wp
->event
, EV_READ
|EV_WRITE
);
249 free(data
->searchstr
);
250 free(data
->inputstr
);
252 if (data
->backing
!= &wp
->base
) {
253 screen_free(data
->backing
);
256 screen_free(&data
->screen
);
262 window_copy_add(struct window_pane
*wp
, const char *fmt
, ...)
267 window_copy_vadd(wp
, fmt
, ap
);
272 window_copy_vadd(struct window_pane
*wp
, const char *fmt
, va_list ap
)
274 struct window_copy_mode_data
*data
= wp
->modedata
;
275 struct screen
*backing
= data
->backing
;
276 struct screen_write_ctx back_ctx
, ctx
;
281 if (backing
== &wp
->base
)
284 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
285 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
287 old_hsize
= screen_hsize(data
->backing
);
288 screen_write_start(&back_ctx
, NULL
, backing
);
289 if (data
->backing_written
) {
291 * On the second or later line, do a CRLF before writing
292 * (so it's on a new line).
294 screen_write_carriagereturn(&back_ctx
);
295 screen_write_linefeed(&back_ctx
, 0);
297 data
->backing_written
= 1;
298 screen_write_vnputs(&back_ctx
, 0, &gc
, utf8flag
, fmt
, ap
);
299 screen_write_stop(&back_ctx
);
301 data
->oy
+= screen_hsize(data
->backing
) - old_hsize
;
303 screen_write_start(&ctx
, wp
, &data
->screen
);
306 * If the history has changed, draw the top line.
307 * (If there's any history at all, it has changed.)
309 if (screen_hsize(data
->backing
))
310 window_copy_redraw_lines(wp
, 0, 1);
312 /* Write the line, if it's visible. */
313 if (backing
->cy
+ data
->oy
< screen_size_y(backing
))
314 window_copy_redraw_lines(wp
, backing
->cy
, 1);
316 screen_write_stop(&ctx
);
320 window_copy_pageup(struct window_pane
*wp
)
322 struct window_copy_mode_data
*data
= wp
->modedata
;
323 struct screen
*s
= &data
->screen
;
327 if (screen_size_y(s
) > 2)
328 n
= screen_size_y(s
) - 2;
329 if (data
->oy
+ n
> screen_hsize(data
->backing
))
330 data
->oy
= screen_hsize(data
->backing
);
333 window_copy_update_selection(wp
, 1);
334 window_copy_redraw_screen(wp
);
338 window_copy_resize(struct window_pane
*wp
, u_int sx
, u_int sy
)
340 struct window_copy_mode_data
*data
= wp
->modedata
;
341 struct screen
*s
= &data
->screen
;
342 struct screen_write_ctx ctx
;
344 screen_resize(s
, sx
, sy
, 0);
345 if (data
->backing
!= &wp
->base
)
346 screen_resize(data
->backing
, sx
, sy
, 0);
348 if (data
->cy
> sy
- 1)
352 if (data
->oy
> screen_hsize(data
->backing
))
353 data
->oy
= screen_hsize(data
->backing
);
355 window_copy_clear_selection(wp
);
357 screen_write_start(&ctx
, NULL
, s
);
358 window_copy_write_lines(wp
, &ctx
, 0, screen_size_y(s
) - 1);
359 screen_write_stop(&ctx
);
361 window_copy_redraw_screen(wp
);
365 window_copy_key(struct window_pane
*wp
, struct session
*sess
, int key
)
367 const char *word_separators
;
368 struct window_copy_mode_data
*data
= wp
->modedata
;
369 struct screen
*s
= &data
->screen
;
372 enum mode_key_cmd cmd
;
375 np
= data
->numprefix
;
379 if (data
->inputtype
== WINDOW_COPY_JUMPFORWARD
||
380 data
->inputtype
== WINDOW_COPY_JUMPBACK
||
381 data
->inputtype
== WINDOW_COPY_JUMPTOFORWARD
||
382 data
->inputtype
== WINDOW_COPY_JUMPTOBACK
) {
383 /* Ignore keys with modifiers. */
384 if ((key
& KEYC_MASK_MOD
) == 0) {
385 data
->jumpchar
= key
;
386 if (data
->inputtype
== WINDOW_COPY_JUMPFORWARD
) {
387 for (; np
!= 0; np
--)
388 window_copy_cursor_jump(wp
);
389 } else if (data
->inputtype
== WINDOW_COPY_JUMPBACK
) {
390 for (; np
!= 0; np
--)
391 window_copy_cursor_jump_back(wp
);
392 } else if (data
->inputtype
== WINDOW_COPY_JUMPTOFORWARD
) {
393 for (; np
!= 0; np
--)
394 window_copy_cursor_jump_to(wp
);
395 } else if (data
->inputtype
== WINDOW_COPY_JUMPTOBACK
) {
396 for (; np
!= 0; np
--)
397 window_copy_cursor_jump_to_back(wp
);
400 data
->jumptype
= data
->inputtype
;
401 data
->inputtype
= WINDOW_COPY_OFF
;
402 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
404 } else if (data
->inputtype
== WINDOW_COPY_NUMERICPREFIX
) {
405 if (window_copy_key_numeric_prefix(wp
, key
) == 0)
407 data
->inputtype
= WINDOW_COPY_OFF
;
408 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
409 } else if (data
->inputtype
!= WINDOW_COPY_OFF
) {
410 if (window_copy_key_input(wp
, key
) != 0)
415 cmd
= mode_key_lookup(&data
->mdata
, key
, &arg
);
417 case MODEKEYCOPY_CANCEL
:
418 window_pane_reset_mode(wp
);
420 case MODEKEYCOPY_OTHEREND
:
421 for (; np
!= 0; np
--)
422 window_copy_other_end(wp
);
424 case MODEKEYCOPY_LEFT
:
425 for (; np
!= 0; np
--)
426 window_copy_cursor_left(wp
);
428 case MODEKEYCOPY_RIGHT
:
429 for (; np
!= 0; np
--)
430 window_copy_cursor_right(wp
);
433 for (; np
!= 0; np
--)
434 window_copy_cursor_up(wp
, 0);
436 case MODEKEYCOPY_DOWN
:
437 for (; np
!= 0; np
--)
438 window_copy_cursor_down(wp
, 0);
440 case MODEKEYCOPY_SCROLLUP
:
441 for (; np
!= 0; np
--)
442 window_copy_cursor_up(wp
, 1);
444 case MODEKEYCOPY_SCROLLDOWN
:
445 for (; np
!= 0; np
--)
446 window_copy_cursor_down(wp
, 1);
448 case MODEKEYCOPY_PREVIOUSPAGE
:
449 for (; np
!= 0; np
--)
450 window_copy_pageup(wp
);
452 case MODEKEYCOPY_NEXTPAGE
:
454 if (screen_size_y(s
) > 2)
455 n
= screen_size_y(s
) - 2;
456 for (; np
!= 0; np
--) {
462 window_copy_update_selection(wp
, 1);
463 window_copy_redraw_screen(wp
);
465 case MODEKEYCOPY_HALFPAGEUP
:
466 n
= screen_size_y(s
) / 2;
467 for (; np
!= 0; np
--) {
468 if (data
->oy
+ n
> screen_hsize(data
->backing
))
469 data
->oy
= screen_hsize(data
->backing
);
473 window_copy_update_selection(wp
, 1);
474 window_copy_redraw_screen(wp
);
476 case MODEKEYCOPY_HALFPAGEDOWN
:
477 n
= screen_size_y(s
) / 2;
478 for (; np
!= 0; np
--) {
484 window_copy_update_selection(wp
, 1);
485 window_copy_redraw_screen(wp
);
487 case MODEKEYCOPY_TOPLINE
:
490 window_copy_update_selection(wp
, 1);
491 window_copy_redraw_screen(wp
);
493 case MODEKEYCOPY_MIDDLELINE
:
495 data
->cy
= (screen_size_y(s
) - 1) / 2;
496 window_copy_update_selection(wp
, 1);
497 window_copy_redraw_screen(wp
);
499 case MODEKEYCOPY_BOTTOMLINE
:
501 data
->cy
= screen_size_y(s
) - 1;
502 window_copy_update_selection(wp
, 1);
503 window_copy_redraw_screen(wp
);
505 case MODEKEYCOPY_HISTORYTOP
:
508 data
->oy
= screen_hsize(data
->backing
);
509 window_copy_update_selection(wp
, 1);
510 window_copy_redraw_screen(wp
);
512 case MODEKEYCOPY_HISTORYBOTTOM
:
514 data
->cy
= screen_size_y(s
) - 1;
516 window_copy_update_selection(wp
, 1);
517 window_copy_redraw_screen(wp
);
519 case MODEKEYCOPY_STARTSELECTION
:
520 window_copy_start_selection(wp
);
521 window_copy_redraw_screen(wp
);
523 case MODEKEYCOPY_COPYLINE
:
524 case MODEKEYCOPY_SELECTLINE
:
525 window_copy_cursor_start_of_line(wp
);
527 case MODEKEYCOPY_COPYENDOFLINE
:
528 window_copy_start_selection(wp
);
530 window_copy_cursor_down(wp
, 0);
531 window_copy_cursor_end_of_line(wp
);
532 window_copy_redraw_screen(wp
);
534 /* If a copy command then copy the selection and exit. */
536 (cmd
== MODEKEYCOPY_COPYLINE
||
537 cmd
== MODEKEYCOPY_COPYENDOFLINE
)) {
538 window_copy_copy_selection(wp
, -1);
539 window_pane_reset_mode(wp
);
543 case MODEKEYCOPY_CLEARSELECTION
:
544 window_copy_clear_selection(wp
);
545 window_copy_redraw_screen(wp
);
547 case MODEKEYCOPY_COPYPIPE
:
549 window_copy_copy_pipe(wp
, sess
, data
->numprefix
, arg
);
550 window_pane_reset_mode(wp
);
554 case MODEKEYCOPY_COPYSELECTION
:
556 window_copy_copy_selection(wp
, data
->numprefix
);
557 window_pane_reset_mode(wp
);
561 case MODEKEYCOPY_STARTOFLINE
:
562 window_copy_cursor_start_of_line(wp
);
564 case MODEKEYCOPY_BACKTOINDENTATION
:
565 window_copy_cursor_back_to_indentation(wp
);
567 case MODEKEYCOPY_ENDOFLINE
:
568 window_copy_cursor_end_of_line(wp
);
570 case MODEKEYCOPY_NEXTSPACE
:
571 for (; np
!= 0; np
--)
572 window_copy_cursor_next_word(wp
, " ");
574 case MODEKEYCOPY_NEXTSPACEEND
:
575 for (; np
!= 0; np
--)
576 window_copy_cursor_next_word_end(wp
, " ");
578 case MODEKEYCOPY_NEXTWORD
:
580 options_get_string(&sess
->options
, "word-separators");
581 for (; np
!= 0; np
--)
582 window_copy_cursor_next_word(wp
, word_separators
);
584 case MODEKEYCOPY_NEXTWORDEND
:
586 options_get_string(&sess
->options
, "word-separators");
587 for (; np
!= 0; np
--)
588 window_copy_cursor_next_word_end(wp
, word_separators
);
590 case MODEKEYCOPY_PREVIOUSSPACE
:
591 for (; np
!= 0; np
--)
592 window_copy_cursor_previous_word(wp
, " ");
594 case MODEKEYCOPY_PREVIOUSWORD
:
596 options_get_string(&sess
->options
, "word-separators");
597 for (; np
!= 0; np
--)
598 window_copy_cursor_previous_word(wp
, word_separators
);
600 case MODEKEYCOPY_JUMP
:
601 data
->inputtype
= WINDOW_COPY_JUMPFORWARD
;
602 data
->inputprompt
= "Jump Forward";
603 *data
->inputstr
= '\0';
604 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
605 return; /* skip numprefix reset */
606 case MODEKEYCOPY_JUMPAGAIN
:
607 if (data
->jumptype
== WINDOW_COPY_JUMPFORWARD
) {
608 for (; np
!= 0; np
--)
609 window_copy_cursor_jump(wp
);
610 } else if (data
->jumptype
== WINDOW_COPY_JUMPBACK
) {
611 for (; np
!= 0; np
--)
612 window_copy_cursor_jump_back(wp
);
613 } else if (data
->jumptype
== WINDOW_COPY_JUMPTOFORWARD
) {
614 for (; np
!= 0; np
--)
615 window_copy_cursor_jump_to(wp
);
616 } else if (data
->jumptype
== WINDOW_COPY_JUMPTOBACK
) {
617 for (; np
!= 0; np
--)
618 window_copy_cursor_jump_to_back(wp
);
621 case MODEKEYCOPY_JUMPREVERSE
:
622 if (data
->jumptype
== WINDOW_COPY_JUMPFORWARD
) {
623 for (; np
!= 0; np
--)
624 window_copy_cursor_jump_back(wp
);
625 } else if (data
->jumptype
== WINDOW_COPY_JUMPBACK
) {
626 for (; np
!= 0; np
--)
627 window_copy_cursor_jump(wp
);
628 } else if (data
->jumptype
== WINDOW_COPY_JUMPTOFORWARD
) {
629 for (; np
!= 0; np
--)
630 window_copy_cursor_jump_to_back(wp
);
631 } else if (data
->jumptype
== WINDOW_COPY_JUMPTOBACK
) {
632 for (; np
!= 0; np
--)
633 window_copy_cursor_jump_to(wp
);
636 case MODEKEYCOPY_JUMPBACK
:
637 data
->inputtype
= WINDOW_COPY_JUMPBACK
;
638 data
->inputprompt
= "Jump Back";
639 *data
->inputstr
= '\0';
640 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
641 return; /* skip numprefix reset */
642 case MODEKEYCOPY_JUMPTO
:
643 data
->inputtype
= WINDOW_COPY_JUMPTOFORWARD
;
644 data
->inputprompt
= "Jump To";
645 *data
->inputstr
= '\0';
646 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
647 return; /* skip numprefix reset */
648 case MODEKEYCOPY_JUMPTOBACK
:
649 data
->inputtype
= WINDOW_COPY_JUMPTOBACK
;
650 data
->inputprompt
= "Jump To Back";
651 *data
->inputstr
= '\0';
652 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
653 return; /* skip numprefix reset */
654 case MODEKEYCOPY_SEARCHUP
:
655 data
->inputtype
= WINDOW_COPY_SEARCHUP
;
656 data
->inputprompt
= "Search Up";
658 case MODEKEYCOPY_SEARCHDOWN
:
659 data
->inputtype
= WINDOW_COPY_SEARCHDOWN
;
660 data
->inputprompt
= "Search Down";
662 case MODEKEYCOPY_SEARCHAGAIN
:
663 case MODEKEYCOPY_SEARCHREVERSE
:
664 switch (data
->searchtype
) {
665 case WINDOW_COPY_OFF
:
666 case WINDOW_COPY_GOTOLINE
:
667 case WINDOW_COPY_JUMPFORWARD
:
668 case WINDOW_COPY_JUMPBACK
:
669 case WINDOW_COPY_JUMPTOFORWARD
:
670 case WINDOW_COPY_JUMPTOBACK
:
671 case WINDOW_COPY_NUMERICPREFIX
:
673 case WINDOW_COPY_SEARCHUP
:
674 if (cmd
== MODEKEYCOPY_SEARCHAGAIN
) {
675 for (; np
!= 0; np
--) {
676 window_copy_search_up(
677 wp
, data
->searchstr
);
680 for (; np
!= 0; np
--) {
681 window_copy_search_down(
682 wp
, data
->searchstr
);
686 case WINDOW_COPY_SEARCHDOWN
:
687 if (cmd
== MODEKEYCOPY_SEARCHAGAIN
) {
688 for (; np
!= 0; np
--) {
689 window_copy_search_down(
690 wp
, data
->searchstr
);
693 for (; np
!= 0; np
--) {
694 window_copy_search_up(
695 wp
, data
->searchstr
);
701 case MODEKEYCOPY_GOTOLINE
:
702 data
->inputtype
= WINDOW_COPY_GOTOLINE
;
703 data
->inputprompt
= "Goto Line";
704 *data
->inputstr
= '\0';
706 case MODEKEYCOPY_STARTNUMBERPREFIX
:
707 key
&= KEYC_MASK_KEY
;
708 if (key
>= '0' && key
<= '9') {
709 data
->inputtype
= WINDOW_COPY_NUMERICPREFIX
;
711 window_copy_key_numeric_prefix(wp
, key
);
715 case MODEKEYCOPY_RECTANGLETOGGLE
:
716 window_copy_rectangle_toggle(wp
);
722 data
->numprefix
= -1;
726 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
727 if (keys
== MODEKEY_EMACS
)
728 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_edit
);
730 mode_key_init(&data
->mdata
, &mode_key_tree_vi_edit
);
732 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
736 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
737 if (keys
== MODEKEY_EMACS
)
738 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_copy
);
740 mode_key_init(&data
->mdata
, &mode_key_tree_vi_copy
);
742 data
->inputtype
= WINDOW_COPY_OFF
;
743 data
->inputprompt
= NULL
;
745 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
749 window_copy_key_input(struct window_pane
*wp
, int key
)
751 struct window_copy_mode_data
*data
= wp
->modedata
;
752 struct screen
*s
= &data
->screen
;
756 switch (mode_key_lookup(&data
->mdata
, key
, NULL
)) {
757 case MODEKEYEDIT_CANCEL
:
758 data
->numprefix
= -1;
760 case MODEKEYEDIT_BACKSPACE
:
761 inputlen
= strlen(data
->inputstr
);
763 data
->inputstr
[inputlen
- 1] = '\0';
765 case MODEKEYEDIT_DELETELINE
:
766 *data
->inputstr
= '\0';
768 case MODEKEYEDIT_ENTER
:
769 np
= data
->numprefix
;
773 switch (data
->inputtype
) {
774 case WINDOW_COPY_OFF
:
775 case WINDOW_COPY_JUMPFORWARD
:
776 case WINDOW_COPY_JUMPBACK
:
777 case WINDOW_COPY_JUMPTOFORWARD
:
778 case WINDOW_COPY_JUMPTOBACK
:
779 case WINDOW_COPY_NUMERICPREFIX
:
781 case WINDOW_COPY_SEARCHUP
:
782 for (; np
!= 0; np
--)
783 window_copy_search_up(wp
, data
->inputstr
);
784 data
->searchtype
= data
->inputtype
;
785 data
->searchstr
= xstrdup(data
->inputstr
);
787 case WINDOW_COPY_SEARCHDOWN
:
788 for (; np
!= 0; np
--)
789 window_copy_search_down(wp
, data
->inputstr
);
790 data
->searchtype
= data
->inputtype
;
791 data
->searchstr
= xstrdup(data
->inputstr
);
793 case WINDOW_COPY_GOTOLINE
:
794 window_copy_goto_line(wp
, data
->inputstr
);
795 *data
->inputstr
= '\0';
798 data
->numprefix
= -1;
801 if (key
< 32 || key
> 126)
803 inputlen
= strlen(data
->inputstr
) + 2;
805 data
->inputstr
= xrealloc(data
->inputstr
, 1, inputlen
);
806 data
->inputstr
[inputlen
- 2] = key
;
807 data
->inputstr
[inputlen
- 1] = '\0';
813 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
818 window_copy_key_numeric_prefix(struct window_pane
*wp
, int key
)
820 struct window_copy_mode_data
*data
= wp
->modedata
;
821 struct screen
*s
= &data
->screen
;
823 key
&= KEYC_MASK_KEY
;
824 if (key
< '0' || key
> '9')
827 if (data
->numprefix
>= 100) /* no more than three digits */
829 data
->numprefix
= data
->numprefix
* 10 + key
- '0';
831 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
837 struct window_pane
*wp
, struct session
*sess
, struct mouse_event
*m
)
839 struct window_copy_mode_data
*data
= wp
->modedata
;
840 struct screen
*s
= &data
->screen
;
843 if (m
->x
>= screen_size_x(s
))
845 if (m
->y
>= screen_size_y(s
))
848 /* If mouse wheel (buttons 4 and 5), scroll. */
849 if (m
->event
== MOUSE_EVENT_WHEEL
) {
850 if (m
->wheel
== MOUSE_WHEEL_UP
) {
851 for (i
= 0; i
< 5; i
++)
852 window_copy_cursor_up(wp
, 1);
853 } else if (m
->wheel
== MOUSE_WHEEL_DOWN
) {
854 for (i
= 0; i
< 5; i
++)
855 window_copy_cursor_down(wp
, 1);
863 * If already reading motion, move the cursor while buttons are still
864 * pressed, or stop the selection on their release.
866 if (s
->mode
& MODE_MOUSE_BUTTON
) {
867 if (~m
->event
& MOUSE_EVENT_UP
) {
868 window_copy_update_cursor(wp
, m
->x
, m
->y
);
869 if (window_copy_update_selection(wp
, 1))
870 window_copy_redraw_screen(wp
);
876 /* Otherwise if other buttons pressed, start selection and motion. */
877 if (~m
->event
& MOUSE_EVENT_UP
) {
878 s
->mode
&= ~MODE_MOUSE_STANDARD
;
879 s
->mode
|= MODE_MOUSE_BUTTON
;
881 window_copy_update_cursor(wp
, m
->x
, m
->y
);
882 window_copy_start_selection(wp
);
883 window_copy_redraw_screen(wp
);
889 s
->mode
&= ~MODE_MOUSE_BUTTON
;
890 s
->mode
|= MODE_MOUSE_STANDARD
;
892 window_copy_copy_selection(wp
, -1);
893 window_pane_reset_mode(wp
);
898 window_copy_scroll_to(struct window_pane
*wp
, u_int px
, u_int py
)
900 struct window_copy_mode_data
*data
= wp
->modedata
;
901 struct grid
*gd
= data
->backing
->grid
;
910 } else if (py
> gd
->hsize
+ gd
->sy
- gap
) {
912 data
->cy
= py
- gd
->hsize
;
914 offset
= py
+ gap
- gd
->sy
;
915 data
->cy
= py
- offset
;
917 data
->oy
= gd
->hsize
- offset
;
919 window_copy_update_selection(wp
, 1);
920 window_copy_redraw_screen(wp
);
924 window_copy_search_compare(
925 struct grid
*gd
, u_int px
, u_int py
, struct grid
*sgd
, u_int spx
, int cis
)
927 const struct grid_cell
*gc
, *sgc
;
928 struct utf8_data ud
, sud
;
930 gc
= grid_peek_cell(gd
, px
, py
);
931 grid_cell_get(gc
, &ud
);
932 sgc
= grid_peek_cell(sgd
, spx
, 0);
933 grid_cell_get(sgc
, &sud
);
935 if (ud
.size
!= sud
.size
|| ud
.width
!= sud
.width
)
938 if (cis
&& ud
.size
== 1)
939 return (tolower(ud
.data
[0]) == sud
.data
[0]);
941 return (memcmp(ud
.data
, sud
.data
, ud
.size
) == 0);
945 window_copy_search_lr(struct grid
*gd
,
946 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
, int cis
)
951 for (ax
= first
; ax
< last
; ax
++) {
952 if (ax
+ sgd
->sx
>= gd
->sx
)
954 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
956 matched
= window_copy_search_compare(gd
, px
, py
, sgd
,
970 window_copy_search_rl(struct grid
*gd
,
971 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
, int cis
)
976 for (ax
= last
+ 1; ax
> first
; ax
--) {
977 if (gd
->sx
- (ax
- 1) < sgd
->sx
)
979 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
981 matched
= window_copy_search_compare(gd
, px
, py
, sgd
,
995 window_copy_search_up(struct window_pane
*wp
, const char *searchstr
)
997 struct window_copy_mode_data
*data
= wp
->modedata
;
998 struct screen
*s
= data
->backing
, ss
;
999 struct screen_write_ctx ctx
;
1000 struct grid
*gd
= s
->grid
, *sgd
;
1001 struct grid_cell gc
;
1003 u_int i
, last
, fx
, fy
, px
;
1004 int utf8flag
, n
, wrapped
, wrapflag
, cis
;
1007 if (*searchstr
== '\0')
1009 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
1010 wrapflag
= options_get_number(&wp
->window
->options
, "wrap-search");
1011 searchlen
= screen_write_strlen(utf8flag
, "%s", searchstr
);
1013 screen_init(&ss
, searchlen
, 1, 0);
1014 screen_write_start(&ctx
, NULL
, &ss
);
1015 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1016 screen_write_nputs(&ctx
, -1, &gc
, utf8flag
, "%s", searchstr
);
1017 screen_write_stop(&ctx
);
1020 fy
= gd
->hsize
- data
->oy
+ data
->cy
;
1032 for (ptr
= searchstr
; *ptr
!= '\0'; ptr
++) {
1033 if (*ptr
!= tolower((u_char
)*ptr
)) {
1041 for (i
= fy
+ 1; i
> 0; i
--) {
1042 last
= screen_size_x(s
);
1045 n
= window_copy_search_rl(gd
, sgd
, &px
, i
- 1, 0, last
, cis
);
1047 window_copy_scroll_to(wp
, px
, i
- 1);
1051 if (wrapflag
&& !n
&& !wrapped
) {
1053 fy
= gd
->hsize
+ gd
->sy
- 1;
1062 window_copy_search_down(struct window_pane
*wp
, const char *searchstr
)
1064 struct window_copy_mode_data
*data
= wp
->modedata
;
1065 struct screen
*s
= data
->backing
, ss
;
1066 struct screen_write_ctx ctx
;
1067 struct grid
*gd
= s
->grid
, *sgd
;
1068 struct grid_cell gc
;
1070 u_int i
, first
, fx
, fy
, px
;
1071 int utf8flag
, n
, wrapped
, wrapflag
, cis
;
1074 if (*searchstr
== '\0')
1076 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
1077 wrapflag
= options_get_number(&wp
->window
->options
, "wrap-search");
1078 searchlen
= screen_write_strlen(utf8flag
, "%s", searchstr
);
1080 screen_init(&ss
, searchlen
, 1, 0);
1081 screen_write_start(&ctx
, NULL
, &ss
);
1082 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1083 screen_write_nputs(&ctx
, -1, &gc
, utf8flag
, "%s", searchstr
);
1084 screen_write_stop(&ctx
);
1087 fy
= gd
->hsize
- data
->oy
+ data
->cy
;
1089 if (fx
== gd
->sx
- 1) {
1090 if (fy
== gd
->hsize
+ gd
->sy
)
1099 for (ptr
= searchstr
; *ptr
!= '\0'; ptr
++) {
1100 if (*ptr
!= tolower((u_char
)*ptr
)) {
1108 for (i
= fy
+ 1; i
< gd
->hsize
+ gd
->sy
+ 1; i
++) {
1112 n
= window_copy_search_lr(gd
, sgd
, &px
, i
- 1, first
, gd
->sx
,
1115 window_copy_scroll_to(wp
, px
, i
- 1);
1119 if (wrapflag
&& !n
&& !wrapped
) {
1130 window_copy_goto_line(struct window_pane
*wp
, const char *linestr
)
1132 struct window_copy_mode_data
*data
= wp
->modedata
;
1136 lineno
= strtonum(linestr
, 0, screen_hsize(data
->backing
), &errstr
);
1141 window_copy_update_selection(wp
, 1);
1142 window_copy_redraw_screen(wp
);
1146 window_copy_write_line(
1147 struct window_pane
*wp
, struct screen_write_ctx
*ctx
, u_int py
)
1149 struct window_copy_mode_data
*data
= wp
->modedata
;
1150 struct screen
*s
= &data
->screen
;
1151 struct options
*oo
= &wp
->window
->options
;
1152 struct grid_cell gc
;
1154 size_t last
, xoff
= 0, size
= 0;
1156 window_mode_attrs(&gc
, oo
);
1158 last
= screen_size_y(s
) - 1;
1160 size
= xsnprintf(hdr
, sizeof hdr
,
1161 "[%u/%u]", data
->oy
, screen_hsize(data
->backing
));
1162 if (size
> screen_size_x(s
))
1163 size
= screen_size_x(s
);
1164 screen_write_cursormove(ctx
, screen_size_x(s
) - size
, 0);
1165 screen_write_puts(ctx
, &gc
, "%s", hdr
);
1166 } else if (py
== last
&& data
->inputtype
!= WINDOW_COPY_OFF
) {
1167 if (data
->inputtype
== WINDOW_COPY_NUMERICPREFIX
) {
1168 xoff
= size
= xsnprintf(hdr
, sizeof hdr
,
1169 "Repeat: %u", data
->numprefix
);
1171 xoff
= size
= xsnprintf(hdr
, sizeof hdr
,
1172 "%s: %s", data
->inputprompt
, data
->inputstr
);
1174 screen_write_cursormove(ctx
, 0, last
);
1175 screen_write_puts(ctx
, &gc
, "%s", hdr
);
1179 screen_write_cursormove(ctx
, xoff
, py
);
1180 screen_write_copy(ctx
, data
->backing
, xoff
,
1181 (screen_hsize(data
->backing
) - data
->oy
) + py
,
1182 screen_size_x(s
) - size
, 1);
1184 if (py
== data
->cy
&& data
->cx
== screen_size_x(s
)) {
1185 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1186 screen_write_cursormove(ctx
, screen_size_x(s
) - 1, py
);
1187 screen_write_putc(ctx
, &gc
, '$');
1192 window_copy_write_lines(
1193 struct window_pane
*wp
, struct screen_write_ctx
*ctx
, u_int py
, u_int ny
)
1197 for (yy
= py
; yy
< py
+ ny
; yy
++)
1198 window_copy_write_line(wp
, ctx
, py
);
1202 window_copy_redraw_lines(struct window_pane
*wp
, u_int py
, u_int ny
)
1204 struct window_copy_mode_data
*data
= wp
->modedata
;
1205 struct screen_write_ctx ctx
;
1208 screen_write_start(&ctx
, wp
, NULL
);
1209 for (i
= py
; i
< py
+ ny
; i
++)
1210 window_copy_write_line(wp
, &ctx
, i
);
1211 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1212 screen_write_stop(&ctx
);
1216 window_copy_redraw_screen(struct window_pane
*wp
)
1218 struct window_copy_mode_data
*data
= wp
->modedata
;
1220 window_copy_redraw_lines(wp
, 0, screen_size_y(&data
->screen
));
1224 window_copy_update_cursor(struct window_pane
*wp
, u_int cx
, u_int cy
)
1226 struct window_copy_mode_data
*data
= wp
->modedata
;
1227 struct screen
*s
= &data
->screen
;
1228 struct screen_write_ctx ctx
;
1229 u_int old_cx
, old_cy
;
1231 old_cx
= data
->cx
; old_cy
= data
->cy
;
1232 data
->cx
= cx
; data
->cy
= cy
;
1233 if (old_cx
== screen_size_x(s
))
1234 window_copy_redraw_lines(wp
, old_cy
, 1);
1235 if (data
->cx
== screen_size_x(s
))
1236 window_copy_redraw_lines(wp
, data
->cy
, 1);
1238 screen_write_start(&ctx
, wp
, NULL
);
1239 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1240 screen_write_stop(&ctx
);
1245 window_copy_start_selection(struct window_pane
*wp
)
1247 struct window_copy_mode_data
*data
= wp
->modedata
;
1248 struct screen
*s
= &data
->screen
;
1250 data
->selx
= data
->cx
;
1251 data
->sely
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1254 window_copy_update_selection(wp
, 1);
1258 window_copy_update_selection(struct window_pane
*wp
, int may_redraw
)
1260 struct window_copy_mode_data
*data
= wp
->modedata
;
1261 struct screen
*s
= &data
->screen
;
1262 struct options
*oo
= &wp
->window
->options
;
1263 struct grid_cell gc
;
1264 u_int sx
, sy
, ty
, cy
;
1270 window_mode_attrs(&gc
, oo
);
1272 /* Find top of screen. */
1273 ty
= screen_hsize(data
->backing
) - data
->oy
;
1275 /* Adjust the selection. */
1278 if (sy
< ty
) { /* above screen */
1279 if (!data
->rectflag
)
1282 } else if (sy
> ty
+ screen_size_y(s
) - 1) { /* below screen */
1283 if (!data
->rectflag
)
1284 sx
= screen_size_x(s
) - 1;
1285 sy
= screen_size_y(s
) - 1;
1288 sy
= screen_hsize(s
) + sy
;
1290 screen_set_selection(s
,
1291 sx
, sy
, data
->cx
, screen_hsize(s
) + data
->cy
, data
->rectflag
, &gc
);
1293 if (data
->rectflag
&& may_redraw
) {
1295 * Can't rely on the caller to redraw the right lines for
1296 * rectangle selection - find the highest line and the number
1297 * of lines, and redraw just past that in both directions
1301 window_copy_redraw_lines(wp
, sy
, cy
- sy
+ 1);
1303 window_copy_redraw_lines(wp
, cy
, sy
- cy
+ 1);
1310 window_copy_get_selection(struct window_pane
*wp
, size_t *len
)
1312 struct window_copy_mode_data
*data
= wp
->modedata
;
1313 struct screen
*s
= &data
->screen
;
1316 u_int i
, xx
, yy
, sx
, sy
, ex
, ey
;
1317 u_int firstsx
, lastex
, restex
, restsx
;
1329 * The selection extends from selx,sely to (adjusted) cx,cy on
1333 /* Find start and end. */
1335 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1336 if (yy
< data
->sely
|| (yy
== data
->sely
&& xx
< data
->selx
)) {
1338 ex
= data
->selx
; ey
= data
->sely
;
1340 sx
= data
->selx
; sy
= data
->sely
;
1344 /* Trim ex to end of line. */
1345 xx
= window_copy_find_length(wp
, ey
);
1350 * Deal with rectangle-copy if necessary; four situations: start of
1351 * first line (firstsx), end of last line (lastex), start (restsx) and
1352 * end (restex) of all other lines.
1354 xx
= screen_size_x(s
);
1357 * Behave according to mode-keys. If it is emacs, copy like emacs,
1358 * keeping the top-left-most character, and dropping the
1359 * bottom-right-most, regardless of copy direction. If it is vi, also
1360 * keep bottom-right-most character.
1362 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
1363 if (data
->rectflag
) {
1365 * Need to ignore the column with the cursor in it, which for
1366 * rectangular copy means knowing which side the cursor is on.
1368 if (data
->selx
< data
->cx
) {
1369 /* Selection start is on the left. */
1370 if (keys
== MODEKEY_EMACS
) {
1375 lastex
= data
->cx
+ 1;
1376 restex
= data
->cx
+ 1;
1378 firstsx
= data
->selx
;
1379 restsx
= data
->selx
;
1381 /* Cursor is on the left. */
1382 lastex
= data
->selx
+ 1;
1383 restex
= data
->selx
+ 1;
1388 if (keys
== MODEKEY_EMACS
)
1397 /* Copy the lines. */
1399 window_copy_copy_line(wp
, &buf
, &off
, sy
, firstsx
, lastex
);
1401 window_copy_copy_line(wp
, &buf
, &off
, sy
, firstsx
, restex
);
1403 for (i
= sy
+ 1; i
< ey
; i
++) {
1404 window_copy_copy_line(
1405 wp
, &buf
, &off
, i
, restsx
, restex
);
1408 window_copy_copy_line(wp
, &buf
, &off
, ey
, restsx
, lastex
);
1411 /* Don't bother if no data. */
1416 *len
= off
- 1; /* remove final \n */
1421 window_copy_copy_buffer(struct window_pane
*wp
, int idx
, void *buf
, size_t len
)
1424 struct screen_write_ctx ctx
;
1426 if (options_get_number(&global_options
, "set-clipboard")) {
1427 screen_write_start(&ctx
, wp
, NULL
);
1428 screen_write_setselection(&ctx
, buf
, len
);
1429 screen_write_stop(&ctx
);
1433 limit
= options_get_number(&global_options
, "buffer-limit");
1434 paste_add(&global_buffers
, buf
, len
, limit
);
1436 paste_replace(&global_buffers
, idx
, buf
, len
);
1440 window_copy_copy_pipe(
1441 struct window_pane
*wp
, struct session
*sess
, int idx
, const char *arg
)
1448 buf
= window_copy_get_selection(wp
, &len
);
1452 job
= job_run(arg
, sess
, NULL
, NULL
, NULL
);
1453 bufferevent_write(job
->event
, buf
, len
);
1455 window_copy_copy_buffer(wp
, idx
, buf
, len
);
1459 window_copy_copy_selection(struct window_pane
*wp
, int idx
)
1464 buf
= window_copy_get_selection(wp
, &len
);
1468 window_copy_copy_buffer(wp
, idx
, buf
, len
);
1472 window_copy_copy_line(struct window_pane
*wp
,
1473 char **buf
, size_t *off
, u_int sy
, u_int sx
, u_int ex
)
1475 struct window_copy_mode_data
*data
= wp
->modedata
;
1476 struct grid
*gd
= data
->backing
->grid
;
1477 const struct grid_cell
*gc
;
1478 struct grid_line
*gl
;
1479 struct utf8_data ud
;
1480 u_int i
, xx
, wrapped
= 0;
1486 * Work out if the line was wrapped at the screen edge and all of it is
1489 gl
= &gd
->linedata
[sy
];
1490 if (gl
->flags
& GRID_LINE_WRAPPED
&& gl
->cellsize
<= gd
->sx
)
1493 /* If the line was wrapped, don't strip spaces (use the full length). */
1497 xx
= window_copy_find_length(wp
, sy
);
1504 for (i
= sx
; i
< ex
; i
++) {
1505 gc
= grid_peek_cell(gd
, i
, sy
);
1506 if (gc
->flags
& GRID_FLAG_PADDING
)
1508 grid_cell_get(gc
, &ud
);
1510 *buf
= xrealloc(*buf
, 1, (*off
) + ud
.size
);
1511 memcpy(*buf
+ *off
, ud
.data
, ud
.size
);
1516 /* Only add a newline if the line wasn't wrapped. */
1517 if (!wrapped
|| ex
!= xx
) {
1518 *buf
= xrealloc(*buf
, 1, (*off
) + 1);
1519 (*buf
)[(*off
)++] = '\n';
1524 window_copy_clear_selection(struct window_pane
*wp
)
1526 struct window_copy_mode_data
*data
= wp
->modedata
;
1529 screen_clear_selection(&data
->screen
);
1531 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1532 px
= window_copy_find_length(wp
, py
);
1534 window_copy_update_cursor(wp
, px
, data
->cy
);
1538 window_copy_in_set(struct window_pane
*wp
, u_int px
, u_int py
, const char *set
)
1540 struct window_copy_mode_data
*data
= wp
->modedata
;
1541 const struct grid_cell
*gc
;
1542 struct utf8_data ud
;
1544 gc
= grid_peek_cell(data
->backing
->grid
, px
, py
);
1545 grid_cell_get(gc
, &ud
);
1546 if (ud
.size
!= 1 || gc
->flags
& GRID_FLAG_PADDING
)
1548 if (*ud
.data
== 0x00 || *ud
.data
== 0x7f)
1550 return (strchr(set
, *ud
.data
) != NULL
);
1554 window_copy_find_length(struct window_pane
*wp
, u_int py
)
1556 struct window_copy_mode_data
*data
= wp
->modedata
;
1557 struct screen
*s
= data
->backing
;
1558 const struct grid_cell
*gc
;
1559 struct utf8_data ud
;
1563 * If the pane has been resized, its grid can contain old overlong
1564 * lines. grid_peek_cell does not allow accessing cells beyond the
1565 * width of the grid, and screen_write_copy treats them as spaces, so
1566 * ignore them here too.
1568 px
= s
->grid
->linedata
[py
].cellsize
;
1569 if (px
> screen_size_x(s
))
1570 px
= screen_size_x(s
);
1572 gc
= grid_peek_cell(s
->grid
, px
- 1, py
);
1573 grid_cell_get(gc
, &ud
);
1574 if (ud
.size
!= 1 || *ud
.data
!= ' ')
1582 window_copy_cursor_start_of_line(struct window_pane
*wp
)
1584 struct window_copy_mode_data
*data
= wp
->modedata
;
1585 struct screen
*back_s
= data
->backing
;
1586 struct grid
*gd
= back_s
->grid
;
1589 if (data
->cx
== 0) {
1590 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1591 while (py
> 0 && gd
->linedata
[py
-1].flags
& GRID_LINE_WRAPPED
) {
1592 window_copy_cursor_up(wp
, 0);
1593 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1596 window_copy_update_cursor(wp
, 0, data
->cy
);
1597 if (window_copy_update_selection(wp
, 1))
1598 window_copy_redraw_lines(wp
, data
->cy
, 1);
1602 window_copy_cursor_back_to_indentation(struct window_pane
*wp
)
1604 struct window_copy_mode_data
*data
= wp
->modedata
;
1606 const struct grid_cell
*gc
;
1607 struct utf8_data ud
;
1610 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1611 xx
= window_copy_find_length(wp
, py
);
1614 gc
= grid_peek_cell(data
->backing
->grid
, px
, py
);
1615 grid_cell_get(gc
, &ud
);
1616 if (ud
.size
!= 1 || *ud
.data
!= ' ')
1621 window_copy_update_cursor(wp
, px
, data
->cy
);
1622 if (window_copy_update_selection(wp
, 1))
1623 window_copy_redraw_lines(wp
, data
->cy
, 1);
1627 window_copy_cursor_end_of_line(struct window_pane
*wp
)
1629 struct window_copy_mode_data
*data
= wp
->modedata
;
1630 struct screen
*back_s
= data
->backing
;
1631 struct grid
*gd
= back_s
->grid
;
1634 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1635 px
= window_copy_find_length(wp
, py
);
1637 if (data
->cx
== px
) {
1638 if (data
->screen
.sel
.flag
&& data
->rectflag
)
1639 px
= screen_size_x(back_s
);
1640 if (gd
->linedata
[py
].flags
& GRID_LINE_WRAPPED
) {
1641 while (py
< gd
->sy
+ gd
->hsize
&&
1642 gd
->linedata
[py
].flags
& GRID_LINE_WRAPPED
) {
1643 window_copy_cursor_down(wp
, 0);
1644 py
= screen_hsize(back_s
)
1645 + data
->cy
- data
->oy
;
1647 px
= window_copy_find_length(wp
, py
);
1650 window_copy_update_cursor(wp
, px
, data
->cy
);
1652 if (window_copy_update_selection(wp
, 1))
1653 window_copy_redraw_lines(wp
, data
->cy
, 1);
1657 window_copy_other_end(struct window_pane
*wp
)
1659 struct window_copy_mode_data
*data
= wp
->modedata
;
1660 struct screen
*s
= &data
->screen
;
1661 u_int selx
, sely
, cx
, cy
, yy
;
1670 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1676 if (sely
< screen_hsize(data
->backing
) - data
->oy
) {
1677 data
->oy
= screen_hsize(data
->backing
) - sely
;
1679 } else if (sely
> screen_hsize(data
->backing
) - data
->oy
+ screen_size_y(s
)) {
1680 data
->oy
= screen_hsize(data
->backing
) - sely
+ screen_size_y(s
) - 1;
1681 data
->cy
= screen_size_y(s
) - 1;
1684 data
->cy
= cy
+ sely
- yy
;
1686 window_copy_redraw_screen(wp
);
1690 window_copy_cursor_left(struct window_pane
*wp
)
1692 struct window_copy_mode_data
*data
= wp
->modedata
;
1694 if (data
->cx
== 0) {
1695 window_copy_cursor_up(wp
, 0);
1696 window_copy_cursor_end_of_line(wp
);
1698 window_copy_update_cursor(wp
, data
->cx
- 1, data
->cy
);
1699 if (window_copy_update_selection(wp
, 1))
1700 window_copy_redraw_lines(wp
, data
->cy
, 1);
1705 window_copy_cursor_right(struct window_pane
*wp
)
1707 struct window_copy_mode_data
*data
= wp
->modedata
;
1710 if (data
->screen
.sel
.flag
&& data
->rectflag
)
1711 px
= screen_size_x(&data
->screen
);
1713 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1714 px
= window_copy_find_length(wp
, py
);
1717 if (data
->cx
>= px
) {
1718 window_copy_cursor_start_of_line(wp
);
1719 window_copy_cursor_down(wp
, 0);
1721 window_copy_update_cursor(wp
, data
->cx
+ 1, data
->cy
);
1722 if (window_copy_update_selection(wp
, 1))
1723 window_copy_redraw_lines(wp
, data
->cy
, 1);
1728 window_copy_cursor_up(struct window_pane
*wp
, int scroll_only
)
1730 struct window_copy_mode_data
*data
= wp
->modedata
;
1731 struct screen
*s
= &data
->screen
;
1732 u_int ox
, oy
, px
, py
;
1734 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1735 ox
= window_copy_find_length(wp
, oy
);
1736 if (data
->cx
!= ox
) {
1737 data
->lastcx
= data
->cx
;
1741 data
->cx
= data
->lastcx
;
1742 if (scroll_only
|| data
->cy
== 0) {
1743 window_copy_scroll_down(wp
, 1);
1745 if (data
->cy
== screen_size_y(s
) - 1)
1746 window_copy_redraw_lines(wp
, data
->cy
, 1);
1748 window_copy_redraw_lines(wp
, data
->cy
, 2);
1751 window_copy_update_cursor(wp
, data
->cx
, data
->cy
- 1);
1752 if (window_copy_update_selection(wp
, 1)) {
1753 if (data
->cy
== screen_size_y(s
) - 1)
1754 window_copy_redraw_lines(wp
, data
->cy
, 1);
1756 window_copy_redraw_lines(wp
, data
->cy
, 2);
1760 if (!data
->screen
.sel
.flag
|| !data
->rectflag
) {
1761 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1762 px
= window_copy_find_length(wp
, py
);
1763 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
1765 window_copy_cursor_end_of_line(wp
);
1770 window_copy_cursor_down(struct window_pane
*wp
, int scroll_only
)
1772 struct window_copy_mode_data
*data
= wp
->modedata
;
1773 struct screen
*s
= &data
->screen
;
1774 u_int ox
, oy
, px
, py
;
1776 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1777 ox
= window_copy_find_length(wp
, oy
);
1778 if (data
->cx
!= ox
) {
1779 data
->lastcx
= data
->cx
;
1783 data
->cx
= data
->lastcx
;
1784 if (scroll_only
|| data
->cy
== screen_size_y(s
) - 1) {
1785 window_copy_scroll_up(wp
, 1);
1786 if (scroll_only
&& data
->cy
> 0)
1787 window_copy_redraw_lines(wp
, data
->cy
- 1, 2);
1789 window_copy_update_cursor(wp
, data
->cx
, data
->cy
+ 1);
1790 if (window_copy_update_selection(wp
, 1))
1791 window_copy_redraw_lines(wp
, data
->cy
- 1, 2);
1794 if (!data
->screen
.sel
.flag
|| !data
->rectflag
) {
1795 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1796 px
= window_copy_find_length(wp
, py
);
1797 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
1799 window_copy_cursor_end_of_line(wp
);
1804 window_copy_cursor_jump(struct window_pane
*wp
)
1806 struct window_copy_mode_data
*data
= wp
->modedata
;
1807 struct screen
*back_s
= data
->backing
;
1808 const struct grid_cell
*gc
;
1809 struct utf8_data ud
;
1813 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1814 xx
= window_copy_find_length(wp
, py
);
1817 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1818 grid_cell_get(gc
, &ud
);
1819 if (!(gc
->flags
& GRID_FLAG_PADDING
) &&
1820 ud
.size
== 1 && *ud
.data
== data
->jumpchar
) {
1821 window_copy_update_cursor(wp
, px
, data
->cy
);
1822 if (window_copy_update_selection(wp
, 1))
1823 window_copy_redraw_lines(wp
, data
->cy
, 1);
1831 window_copy_cursor_jump_back(struct window_pane
*wp
)
1833 struct window_copy_mode_data
*data
= wp
->modedata
;
1834 struct screen
*back_s
= data
->backing
;
1835 const struct grid_cell
*gc
;
1836 struct utf8_data ud
;
1840 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1846 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1847 grid_cell_get(gc
, &ud
);
1848 if (!(gc
->flags
& GRID_FLAG_PADDING
) &&
1849 ud
.size
== 1 && *ud
.data
== data
->jumpchar
) {
1850 window_copy_update_cursor(wp
, px
, data
->cy
);
1851 if (window_copy_update_selection(wp
, 1))
1852 window_copy_redraw_lines(wp
, data
->cy
, 1);
1862 window_copy_cursor_jump_to(struct window_pane
*wp
)
1864 struct window_copy_mode_data
*data
= wp
->modedata
;
1865 struct screen
*back_s
= data
->backing
;
1866 const struct grid_cell
*gc
;
1867 struct utf8_data ud
;
1871 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1872 xx
= window_copy_find_length(wp
, py
);
1875 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1876 grid_cell_get(gc
, &ud
);
1877 if (!(gc
->flags
& GRID_FLAG_PADDING
) &&
1878 ud
.size
== 1 && *ud
.data
== data
->jumpchar
) {
1879 window_copy_update_cursor(wp
, px
- 1, data
->cy
);
1880 if (window_copy_update_selection(wp
, 1))
1881 window_copy_redraw_lines(wp
, data
->cy
, 1);
1889 window_copy_cursor_jump_to_back(struct window_pane
*wp
)
1891 struct window_copy_mode_data
*data
= wp
->modedata
;
1892 struct screen
*back_s
= data
->backing
;
1893 const struct grid_cell
*gc
;
1894 struct utf8_data ud
;
1898 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1904 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1905 grid_cell_get(gc
, &ud
);
1906 if (!(gc
->flags
& GRID_FLAG_PADDING
) &&
1907 ud
.size
== 1 && *ud
.data
== data
->jumpchar
) {
1908 window_copy_update_cursor(wp
, px
+ 1, data
->cy
);
1909 if (window_copy_update_selection(wp
, 1))
1910 window_copy_redraw_lines(wp
, data
->cy
, 1);
1920 window_copy_cursor_next_word(struct window_pane
*wp
, const char *separators
)
1922 struct window_copy_mode_data
*data
= wp
->modedata
;
1923 struct screen
*back_s
= data
->backing
;
1924 u_int px
, py
, xx
, yy
;
1928 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1929 xx
= window_copy_find_length(wp
, py
);
1930 yy
= screen_hsize(back_s
) + screen_size_y(back_s
) - 1;
1933 * First skip past any nonword characters and then any word characters.
1935 * expected is initially set to 0 for the former and then 1 for the
1940 window_copy_in_set(wp
, px
, py
, separators
) == expected
) {
1941 /* Move down if we're past the end of the line. */
1945 window_copy_cursor_down(wp
, 0);
1948 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1949 xx
= window_copy_find_length(wp
, py
);
1953 expected
= !expected
;
1954 } while (expected
== 1);
1956 window_copy_update_cursor(wp
, px
, data
->cy
);
1957 if (window_copy_update_selection(wp
, 1))
1958 window_copy_redraw_lines(wp
, data
->cy
, 1);
1962 window_copy_cursor_next_word_end(struct window_pane
*wp
, const char *separators
)
1964 struct window_copy_mode_data
*data
= wp
->modedata
;
1965 struct options
*oo
= &wp
->window
->options
;
1966 struct screen
*back_s
= data
->backing
;
1967 u_int px
, py
, xx
, yy
;
1968 int keys
, expected
= 1;
1971 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1972 xx
= window_copy_find_length(wp
, py
);
1973 yy
= screen_hsize(back_s
) + screen_size_y(back_s
) - 1;
1975 keys
= options_get_number(oo
, "mode-keys");
1976 if (keys
== MODEKEY_VI
&& !window_copy_in_set(wp
, px
, py
, separators
))
1980 * First skip past any word characters, then any nonword characters.
1982 * expected is initially set to 1 for the former and then 0 for the
1987 window_copy_in_set(wp
, px
, py
, separators
) == expected
) {
1988 /* Move down if we're past the end of the line. */
1992 window_copy_cursor_down(wp
, 0);
1995 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1996 xx
= window_copy_find_length(wp
, py
);
2000 expected
= !expected
;
2001 } while (expected
== 0);
2003 if (keys
== MODEKEY_VI
&& px
!= 0)
2006 window_copy_update_cursor(wp
, px
, data
->cy
);
2007 if (window_copy_update_selection(wp
, 1))
2008 window_copy_redraw_lines(wp
, data
->cy
, 1);
2011 /* Move to the previous place where a word begins. */
2013 window_copy_cursor_previous_word(struct window_pane
*wp
, const char *separators
)
2015 struct window_copy_mode_data
*data
= wp
->modedata
;
2019 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2021 /* Move back to the previous word character. */
2025 if (!window_copy_in_set(wp
, px
, py
, separators
))
2028 if (data
->cy
== 0 &&
2029 (screen_hsize(data
->backing
) == 0 ||
2030 data
->oy
>= screen_hsize(data
->backing
) - 1))
2032 window_copy_cursor_up(wp
, 0);
2034 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2035 px
= window_copy_find_length(wp
, py
);
2039 /* Move back to the beginning of this word. */
2040 while (px
> 0 && !window_copy_in_set(wp
, px
- 1, py
, separators
))
2044 window_copy_update_cursor(wp
, px
, data
->cy
);
2045 if (window_copy_update_selection(wp
, 1))
2046 window_copy_redraw_lines(wp
, data
->cy
, 1);
2050 window_copy_scroll_up(struct window_pane
*wp
, u_int ny
)
2052 struct window_copy_mode_data
*data
= wp
->modedata
;
2053 struct screen
*s
= &data
->screen
;
2054 struct screen_write_ctx ctx
;
2062 window_copy_update_selection(wp
, 0);
2064 screen_write_start(&ctx
, wp
, NULL
);
2065 screen_write_cursormove(&ctx
, 0, 0);
2066 screen_write_deleteline(&ctx
, ny
);
2067 window_copy_write_lines(wp
, &ctx
, screen_size_y(s
) - ny
, ny
);
2068 window_copy_write_line(wp
, &ctx
, 0);
2069 if (screen_size_y(s
) > 1)
2070 window_copy_write_line(wp
, &ctx
, 1);
2071 if (screen_size_y(s
) > 3)
2072 window_copy_write_line(wp
, &ctx
, screen_size_y(s
) - 2);
2073 if (s
->sel
.flag
&& screen_size_y(s
) > ny
)
2074 window_copy_write_line(wp
, &ctx
, screen_size_y(s
) - ny
- 1);
2075 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
2076 screen_write_stop(&ctx
);
2080 window_copy_scroll_down(struct window_pane
*wp
, u_int ny
)
2082 struct window_copy_mode_data
*data
= wp
->modedata
;
2083 struct screen
*s
= &data
->screen
;
2084 struct screen_write_ctx ctx
;
2086 if (ny
> screen_hsize(data
->backing
))
2089 if (data
->oy
> screen_hsize(data
->backing
) - ny
)
2090 ny
= screen_hsize(data
->backing
) - data
->oy
;
2095 window_copy_update_selection(wp
, 0);
2097 screen_write_start(&ctx
, wp
, NULL
);
2098 screen_write_cursormove(&ctx
, 0, 0);
2099 screen_write_insertline(&ctx
, ny
);
2100 window_copy_write_lines(wp
, &ctx
, 0, ny
);
2101 if (s
->sel
.flag
&& screen_size_y(s
) > ny
)
2102 window_copy_write_line(wp
, &ctx
, ny
);
2103 else if (ny
== 1) /* nuke position */
2104 window_copy_write_line(wp
, &ctx
, 1);
2105 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
2106 screen_write_stop(&ctx
);
2110 window_copy_rectangle_toggle(struct window_pane
*wp
)
2112 struct window_copy_mode_data
*data
= wp
->modedata
;
2115 data
->rectflag
= !data
->rectflag
;
2117 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2118 px
= window_copy_find_length(wp
, py
);
2120 window_copy_update_cursor(wp
, px
, data
->cy
);
2122 window_copy_update_selection(wp
, 1);
2123 window_copy_redraw_screen(wp
);