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
;
755 struct paste_buffer
*pb
;
758 switch (mode_key_lookup(&data
->mdata
, key
, NULL
)) {
759 case MODEKEYEDIT_CANCEL
:
760 data
->numprefix
= -1;
762 case MODEKEYEDIT_BACKSPACE
:
763 inputlen
= strlen(data
->inputstr
);
765 data
->inputstr
[inputlen
- 1] = '\0';
767 case MODEKEYEDIT_DELETELINE
:
768 *data
->inputstr
= '\0';
770 case MODEKEYEDIT_PASTE
:
771 if ((pb
= paste_get_top(&global_buffers
)) == NULL
)
773 for (n
= 0; n
< pb
->size
; n
++) {
774 ch
= (u_char
) pb
->data
[n
];
775 if (ch
< 32 || ch
== 127)
778 inputlen
= strlen(data
->inputstr
);
780 data
->inputstr
= xrealloc(data
->inputstr
, 1, inputlen
+ n
+ 1);
781 memcpy(data
->inputstr
+ inputlen
, pb
->data
, n
);
782 data
->inputstr
[inputlen
+ n
] = '\0';
784 case MODEKEYEDIT_ENTER
:
785 np
= data
->numprefix
;
789 switch (data
->inputtype
) {
790 case WINDOW_COPY_OFF
:
791 case WINDOW_COPY_JUMPFORWARD
:
792 case WINDOW_COPY_JUMPBACK
:
793 case WINDOW_COPY_JUMPTOFORWARD
:
794 case WINDOW_COPY_JUMPTOBACK
:
795 case WINDOW_COPY_NUMERICPREFIX
:
797 case WINDOW_COPY_SEARCHUP
:
798 for (; np
!= 0; np
--)
799 window_copy_search_up(wp
, data
->inputstr
);
800 data
->searchtype
= data
->inputtype
;
801 data
->searchstr
= xstrdup(data
->inputstr
);
803 case WINDOW_COPY_SEARCHDOWN
:
804 for (; np
!= 0; np
--)
805 window_copy_search_down(wp
, data
->inputstr
);
806 data
->searchtype
= data
->inputtype
;
807 data
->searchstr
= xstrdup(data
->inputstr
);
809 case WINDOW_COPY_GOTOLINE
:
810 window_copy_goto_line(wp
, data
->inputstr
);
811 *data
->inputstr
= '\0';
814 data
->numprefix
= -1;
817 if (key
< 32 || key
> 126)
819 inputlen
= strlen(data
->inputstr
) + 2;
821 data
->inputstr
= xrealloc(data
->inputstr
, 1, inputlen
);
822 data
->inputstr
[inputlen
- 2] = key
;
823 data
->inputstr
[inputlen
- 1] = '\0';
829 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
834 window_copy_key_numeric_prefix(struct window_pane
*wp
, int key
)
836 struct window_copy_mode_data
*data
= wp
->modedata
;
837 struct screen
*s
= &data
->screen
;
839 key
&= KEYC_MASK_KEY
;
840 if (key
< '0' || key
> '9')
843 if (data
->numprefix
>= 100) /* no more than three digits */
845 data
->numprefix
= data
->numprefix
* 10 + key
- '0';
847 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
853 struct window_pane
*wp
, struct session
*sess
, struct mouse_event
*m
)
855 struct window_copy_mode_data
*data
= wp
->modedata
;
856 struct screen
*s
= &data
->screen
;
859 if (m
->x
>= screen_size_x(s
))
861 if (m
->y
>= screen_size_y(s
))
864 /* If mouse wheel (buttons 4 and 5), scroll. */
865 if (m
->event
== MOUSE_EVENT_WHEEL
) {
866 if (m
->wheel
== MOUSE_WHEEL_UP
) {
867 for (i
= 0; i
< 5; i
++)
868 window_copy_cursor_up(wp
, 1);
869 } else if (m
->wheel
== MOUSE_WHEEL_DOWN
) {
870 for (i
= 0; i
< 5; i
++)
871 window_copy_cursor_down(wp
, 1);
873 * We reached the bottom, leave copy mode,
874 * but only if no selection is in progress.
876 if (data
->oy
== 0 && !s
->sel
.flag
)
883 * If already reading motion, move the cursor while buttons are still
884 * pressed, or stop the selection on their release.
886 if (s
->mode
& MODE_MOUSE_BUTTON
) {
887 if (~m
->event
& MOUSE_EVENT_UP
) {
888 window_copy_update_cursor(wp
, m
->x
, m
->y
);
889 if (window_copy_update_selection(wp
, 1))
890 window_copy_redraw_screen(wp
);
896 /* Otherwise if other buttons pressed, start selection and motion. */
897 if (~m
->event
& MOUSE_EVENT_UP
) {
898 s
->mode
&= ~MODE_MOUSE_STANDARD
;
899 s
->mode
|= MODE_MOUSE_BUTTON
;
901 window_copy_update_cursor(wp
, m
->x
, m
->y
);
902 window_copy_start_selection(wp
);
903 window_copy_redraw_screen(wp
);
909 s
->mode
&= ~MODE_MOUSE_BUTTON
;
910 s
->mode
|= MODE_MOUSE_STANDARD
;
912 window_copy_copy_selection(wp
, -1);
913 window_pane_reset_mode(wp
);
918 window_copy_scroll_to(struct window_pane
*wp
, u_int px
, u_int py
)
920 struct window_copy_mode_data
*data
= wp
->modedata
;
921 struct grid
*gd
= data
->backing
->grid
;
930 } else if (py
> gd
->hsize
+ gd
->sy
- gap
) {
932 data
->cy
= py
- gd
->hsize
;
934 offset
= py
+ gap
- gd
->sy
;
935 data
->cy
= py
- offset
;
937 data
->oy
= gd
->hsize
- offset
;
939 window_copy_update_selection(wp
, 1);
940 window_copy_redraw_screen(wp
);
944 window_copy_search_compare(
945 struct grid
*gd
, u_int px
, u_int py
, struct grid
*sgd
, u_int spx
, int cis
)
947 const struct grid_cell
*gc
, *sgc
;
948 struct utf8_data ud
, sud
;
950 gc
= grid_peek_cell(gd
, px
, py
);
951 grid_cell_get(gc
, &ud
);
952 sgc
= grid_peek_cell(sgd
, spx
, 0);
953 grid_cell_get(sgc
, &sud
);
955 if (ud
.size
!= sud
.size
|| ud
.width
!= sud
.width
)
958 if (cis
&& ud
.size
== 1)
959 return (tolower(ud
.data
[0]) == sud
.data
[0]);
961 return (memcmp(ud
.data
, sud
.data
, ud
.size
) == 0);
965 window_copy_search_lr(struct grid
*gd
,
966 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
, int cis
)
971 for (ax
= first
; ax
< last
; ax
++) {
972 if (ax
+ sgd
->sx
>= gd
->sx
)
974 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
976 matched
= window_copy_search_compare(gd
, px
, py
, sgd
,
990 window_copy_search_rl(struct grid
*gd
,
991 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
, int cis
)
996 for (ax
= last
+ 1; ax
> first
; ax
--) {
997 if (gd
->sx
- (ax
- 1) < sgd
->sx
)
999 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
1001 matched
= window_copy_search_compare(gd
, px
, py
, sgd
,
1006 if (bx
== sgd
->sx
) {
1015 window_copy_search_up(struct window_pane
*wp
, const char *searchstr
)
1017 struct window_copy_mode_data
*data
= wp
->modedata
;
1018 struct screen
*s
= data
->backing
, ss
;
1019 struct screen_write_ctx ctx
;
1020 struct grid
*gd
= s
->grid
, *sgd
;
1021 struct grid_cell gc
;
1023 u_int i
, last
, fx
, fy
, px
;
1024 int utf8flag
, n
, wrapped
, wrapflag
, cis
;
1027 if (*searchstr
== '\0')
1029 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
1030 wrapflag
= options_get_number(&wp
->window
->options
, "wrap-search");
1031 searchlen
= screen_write_strlen(utf8flag
, "%s", searchstr
);
1033 screen_init(&ss
, searchlen
, 1, 0);
1034 screen_write_start(&ctx
, NULL
, &ss
);
1035 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1036 screen_write_nputs(&ctx
, -1, &gc
, utf8flag
, "%s", searchstr
);
1037 screen_write_stop(&ctx
);
1040 fy
= gd
->hsize
- data
->oy
+ data
->cy
;
1052 for (ptr
= searchstr
; *ptr
!= '\0'; ptr
++) {
1053 if (*ptr
!= tolower((u_char
)*ptr
)) {
1061 for (i
= fy
+ 1; i
> 0; i
--) {
1062 last
= screen_size_x(s
);
1065 n
= window_copy_search_rl(gd
, sgd
, &px
, i
- 1, 0, last
, cis
);
1067 window_copy_scroll_to(wp
, px
, i
- 1);
1071 if (wrapflag
&& !n
&& !wrapped
) {
1073 fy
= gd
->hsize
+ gd
->sy
- 1;
1082 window_copy_search_down(struct window_pane
*wp
, const char *searchstr
)
1084 struct window_copy_mode_data
*data
= wp
->modedata
;
1085 struct screen
*s
= data
->backing
, ss
;
1086 struct screen_write_ctx ctx
;
1087 struct grid
*gd
= s
->grid
, *sgd
;
1088 struct grid_cell gc
;
1090 u_int i
, first
, fx
, fy
, px
;
1091 int utf8flag
, n
, wrapped
, wrapflag
, cis
;
1094 if (*searchstr
== '\0')
1096 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
1097 wrapflag
= options_get_number(&wp
->window
->options
, "wrap-search");
1098 searchlen
= screen_write_strlen(utf8flag
, "%s", searchstr
);
1100 screen_init(&ss
, searchlen
, 1, 0);
1101 screen_write_start(&ctx
, NULL
, &ss
);
1102 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1103 screen_write_nputs(&ctx
, -1, &gc
, utf8flag
, "%s", searchstr
);
1104 screen_write_stop(&ctx
);
1107 fy
= gd
->hsize
- data
->oy
+ data
->cy
;
1109 if (fx
== gd
->sx
- 1) {
1110 if (fy
== gd
->hsize
+ gd
->sy
)
1119 for (ptr
= searchstr
; *ptr
!= '\0'; ptr
++) {
1120 if (*ptr
!= tolower((u_char
)*ptr
)) {
1128 for (i
= fy
+ 1; i
< gd
->hsize
+ gd
->sy
+ 1; i
++) {
1132 n
= window_copy_search_lr(gd
, sgd
, &px
, i
- 1, first
, gd
->sx
,
1135 window_copy_scroll_to(wp
, px
, i
- 1);
1139 if (wrapflag
&& !n
&& !wrapped
) {
1150 window_copy_goto_line(struct window_pane
*wp
, const char *linestr
)
1152 struct window_copy_mode_data
*data
= wp
->modedata
;
1156 lineno
= strtonum(linestr
, 0, screen_hsize(data
->backing
), &errstr
);
1161 window_copy_update_selection(wp
, 1);
1162 window_copy_redraw_screen(wp
);
1166 window_copy_write_line(
1167 struct window_pane
*wp
, struct screen_write_ctx
*ctx
, u_int py
)
1169 struct window_copy_mode_data
*data
= wp
->modedata
;
1170 struct screen
*s
= &data
->screen
;
1171 struct options
*oo
= &wp
->window
->options
;
1172 struct grid_cell gc
;
1174 size_t last
, xoff
= 0, size
= 0, limit
;
1176 style_apply(&gc
, oo
, "mode-style");
1178 last
= screen_size_y(s
) - 1;
1180 size
= xsnprintf(hdr
, sizeof hdr
,
1181 "[%u/%u]", data
->oy
, screen_hsize(data
->backing
));
1182 if (size
> screen_size_x(s
))
1183 size
= screen_size_x(s
);
1184 screen_write_cursormove(ctx
, screen_size_x(s
) - size
, 0);
1185 screen_write_puts(ctx
, &gc
, "%s", hdr
);
1186 } else if (py
== last
&& data
->inputtype
!= WINDOW_COPY_OFF
) {
1188 if (limit
> screen_size_x(s
))
1189 limit
= screen_size_x(s
);
1190 if (data
->inputtype
== WINDOW_COPY_NUMERICPREFIX
) {
1191 xoff
= size
= xsnprintf(hdr
, limit
,
1192 "Repeat: %u", data
->numprefix
);
1194 xoff
= size
= xsnprintf(hdr
, limit
,
1195 "%s: %s", data
->inputprompt
, data
->inputstr
);
1197 screen_write_cursormove(ctx
, 0, last
);
1198 screen_write_puts(ctx
, &gc
, "%s", hdr
);
1202 screen_write_cursormove(ctx
, xoff
, py
);
1203 screen_write_copy(ctx
, data
->backing
, xoff
,
1204 (screen_hsize(data
->backing
) - data
->oy
) + py
,
1205 screen_size_x(s
) - size
, 1);
1207 if (py
== data
->cy
&& data
->cx
== screen_size_x(s
)) {
1208 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1209 screen_write_cursormove(ctx
, screen_size_x(s
) - 1, py
);
1210 screen_write_putc(ctx
, &gc
, '$');
1215 window_copy_write_lines(
1216 struct window_pane
*wp
, struct screen_write_ctx
*ctx
, u_int py
, u_int ny
)
1220 for (yy
= py
; yy
< py
+ ny
; yy
++)
1221 window_copy_write_line(wp
, ctx
, py
);
1225 window_copy_redraw_lines(struct window_pane
*wp
, u_int py
, u_int ny
)
1227 struct window_copy_mode_data
*data
= wp
->modedata
;
1228 struct screen_write_ctx ctx
;
1231 screen_write_start(&ctx
, wp
, NULL
);
1232 for (i
= py
; i
< py
+ ny
; i
++)
1233 window_copy_write_line(wp
, &ctx
, i
);
1234 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1235 screen_write_stop(&ctx
);
1239 window_copy_redraw_screen(struct window_pane
*wp
)
1241 struct window_copy_mode_data
*data
= wp
->modedata
;
1243 window_copy_redraw_lines(wp
, 0, screen_size_y(&data
->screen
));
1247 window_copy_update_cursor(struct window_pane
*wp
, u_int cx
, u_int cy
)
1249 struct window_copy_mode_data
*data
= wp
->modedata
;
1250 struct screen
*s
= &data
->screen
;
1251 struct screen_write_ctx ctx
;
1252 u_int old_cx
, old_cy
;
1254 old_cx
= data
->cx
; old_cy
= data
->cy
;
1255 data
->cx
= cx
; data
->cy
= cy
;
1256 if (old_cx
== screen_size_x(s
))
1257 window_copy_redraw_lines(wp
, old_cy
, 1);
1258 if (data
->cx
== screen_size_x(s
))
1259 window_copy_redraw_lines(wp
, data
->cy
, 1);
1261 screen_write_start(&ctx
, wp
, NULL
);
1262 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1263 screen_write_stop(&ctx
);
1268 window_copy_start_selection(struct window_pane
*wp
)
1270 struct window_copy_mode_data
*data
= wp
->modedata
;
1271 struct screen
*s
= &data
->screen
;
1273 data
->selx
= data
->cx
;
1274 data
->sely
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1277 window_copy_update_selection(wp
, 1);
1281 window_copy_update_selection(struct window_pane
*wp
, int may_redraw
)
1283 struct window_copy_mode_data
*data
= wp
->modedata
;
1284 struct screen
*s
= &data
->screen
;
1285 struct options
*oo
= &wp
->window
->options
;
1286 struct grid_cell gc
;
1287 u_int sx
, sy
, ty
, cy
;
1293 style_apply(&gc
, oo
, "mode-style");
1295 /* Find top of screen. */
1296 ty
= screen_hsize(data
->backing
) - data
->oy
;
1298 /* Adjust the selection. */
1301 if (sy
< ty
) { /* above screen */
1302 if (!data
->rectflag
)
1305 } else if (sy
> ty
+ screen_size_y(s
) - 1) { /* below screen */
1306 if (!data
->rectflag
)
1307 sx
= screen_size_x(s
) - 1;
1308 sy
= screen_size_y(s
) - 1;
1311 sy
= screen_hsize(s
) + sy
;
1313 screen_set_selection(s
,
1314 sx
, sy
, data
->cx
, screen_hsize(s
) + data
->cy
, data
->rectflag
, &gc
);
1316 if (data
->rectflag
&& may_redraw
) {
1318 * Can't rely on the caller to redraw the right lines for
1319 * rectangle selection - find the highest line and the number
1320 * of lines, and redraw just past that in both directions
1324 window_copy_redraw_lines(wp
, sy
, cy
- sy
+ 1);
1326 window_copy_redraw_lines(wp
, cy
, sy
- cy
+ 1);
1333 window_copy_get_selection(struct window_pane
*wp
, size_t *len
)
1335 struct window_copy_mode_data
*data
= wp
->modedata
;
1336 struct screen
*s
= &data
->screen
;
1339 u_int i
, xx
, yy
, sx
, sy
, ex
, ey
;
1340 u_int firstsx
, lastex
, restex
, restsx
;
1352 * The selection extends from selx,sely to (adjusted) cx,cy on
1356 /* Find start and end. */
1358 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1359 if (yy
< data
->sely
|| (yy
== data
->sely
&& xx
< data
->selx
)) {
1361 ex
= data
->selx
; ey
= data
->sely
;
1363 sx
= data
->selx
; sy
= data
->sely
;
1367 /* Trim ex to end of line. */
1368 xx
= window_copy_find_length(wp
, ey
);
1373 * Deal with rectangle-copy if necessary; four situations: start of
1374 * first line (firstsx), end of last line (lastex), start (restsx) and
1375 * end (restex) of all other lines.
1377 xx
= screen_size_x(s
);
1380 * Behave according to mode-keys. If it is emacs, copy like emacs,
1381 * keeping the top-left-most character, and dropping the
1382 * bottom-right-most, regardless of copy direction. If it is vi, also
1383 * keep bottom-right-most character.
1385 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
1386 if (data
->rectflag
) {
1388 * Need to ignore the column with the cursor in it, which for
1389 * rectangular copy means knowing which side the cursor is on.
1391 if (data
->selx
< data
->cx
) {
1392 /* Selection start is on the left. */
1393 if (keys
== MODEKEY_EMACS
) {
1398 lastex
= data
->cx
+ 1;
1399 restex
= data
->cx
+ 1;
1401 firstsx
= data
->selx
;
1402 restsx
= data
->selx
;
1404 /* Cursor is on the left. */
1405 lastex
= data
->selx
+ 1;
1406 restex
= data
->selx
+ 1;
1411 if (keys
== MODEKEY_EMACS
)
1420 /* Copy the lines. */
1422 window_copy_copy_line(wp
, &buf
, &off
, sy
, firstsx
, lastex
);
1424 window_copy_copy_line(wp
, &buf
, &off
, sy
, firstsx
, restex
);
1426 for (i
= sy
+ 1; i
< ey
; i
++) {
1427 window_copy_copy_line(
1428 wp
, &buf
, &off
, i
, restsx
, restex
);
1431 window_copy_copy_line(wp
, &buf
, &off
, ey
, restsx
, lastex
);
1434 /* Don't bother if no data. */
1439 *len
= off
- 1; /* remove final \n */
1444 window_copy_copy_buffer(struct window_pane
*wp
, int idx
, void *buf
, size_t len
)
1447 struct screen_write_ctx ctx
;
1449 if (options_get_number(&global_options
, "set-clipboard")) {
1450 screen_write_start(&ctx
, wp
, NULL
);
1451 screen_write_setselection(&ctx
, buf
, len
);
1452 screen_write_stop(&ctx
);
1456 limit
= options_get_number(&global_options
, "buffer-limit");
1457 paste_add(&global_buffers
, buf
, len
, limit
);
1458 } else if (paste_replace(&global_buffers
, idx
, buf
, len
) != 0)
1463 window_copy_copy_pipe(
1464 struct window_pane
*wp
, struct session
*sess
, int idx
, const char *arg
)
1471 buf
= window_copy_get_selection(wp
, &len
);
1475 job
= job_run(arg
, sess
, NULL
, NULL
, NULL
);
1476 bufferevent_write(job
->event
, buf
, len
);
1478 window_copy_copy_buffer(wp
, idx
, buf
, len
);
1482 window_copy_copy_selection(struct window_pane
*wp
, int idx
)
1487 buf
= window_copy_get_selection(wp
, &len
);
1491 window_copy_copy_buffer(wp
, idx
, buf
, len
);
1495 window_copy_copy_line(struct window_pane
*wp
,
1496 char **buf
, size_t *off
, u_int sy
, u_int sx
, u_int ex
)
1498 struct window_copy_mode_data
*data
= wp
->modedata
;
1499 struct grid
*gd
= data
->backing
->grid
;
1500 const struct grid_cell
*gc
;
1501 struct grid_line
*gl
;
1502 struct utf8_data ud
;
1503 u_int i
, xx
, wrapped
= 0;
1509 * Work out if the line was wrapped at the screen edge and all of it is
1512 gl
= &gd
->linedata
[sy
];
1513 if (gl
->flags
& GRID_LINE_WRAPPED
&& gl
->cellsize
<= gd
->sx
)
1516 /* If the line was wrapped, don't strip spaces (use the full length). */
1520 xx
= window_copy_find_length(wp
, sy
);
1527 for (i
= sx
; i
< ex
; i
++) {
1528 gc
= grid_peek_cell(gd
, i
, sy
);
1529 if (gc
->flags
& GRID_FLAG_PADDING
)
1531 grid_cell_get(gc
, &ud
);
1533 *buf
= xrealloc(*buf
, 1, (*off
) + ud
.size
);
1534 memcpy(*buf
+ *off
, ud
.data
, ud
.size
);
1539 /* Only add a newline if the line wasn't wrapped. */
1540 if (!wrapped
|| ex
!= xx
) {
1541 *buf
= xrealloc(*buf
, 1, (*off
) + 1);
1542 (*buf
)[(*off
)++] = '\n';
1547 window_copy_clear_selection(struct window_pane
*wp
)
1549 struct window_copy_mode_data
*data
= wp
->modedata
;
1552 screen_clear_selection(&data
->screen
);
1554 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1555 px
= window_copy_find_length(wp
, py
);
1557 window_copy_update_cursor(wp
, px
, data
->cy
);
1561 window_copy_in_set(struct window_pane
*wp
, u_int px
, u_int py
, const char *set
)
1563 struct window_copy_mode_data
*data
= wp
->modedata
;
1564 const struct grid_cell
*gc
;
1565 struct utf8_data ud
;
1567 gc
= grid_peek_cell(data
->backing
->grid
, px
, py
);
1568 grid_cell_get(gc
, &ud
);
1569 if (ud
.size
!= 1 || gc
->flags
& GRID_FLAG_PADDING
)
1571 if (*ud
.data
== 0x00 || *ud
.data
== 0x7f)
1573 return (strchr(set
, *ud
.data
) != NULL
);
1577 window_copy_find_length(struct window_pane
*wp
, u_int py
)
1579 struct window_copy_mode_data
*data
= wp
->modedata
;
1580 struct screen
*s
= data
->backing
;
1581 const struct grid_cell
*gc
;
1582 struct utf8_data ud
;
1586 * If the pane has been resized, its grid can contain old overlong
1587 * lines. grid_peek_cell does not allow accessing cells beyond the
1588 * width of the grid, and screen_write_copy treats them as spaces, so
1589 * ignore them here too.
1591 px
= s
->grid
->linedata
[py
].cellsize
;
1592 if (px
> screen_size_x(s
))
1593 px
= screen_size_x(s
);
1595 gc
= grid_peek_cell(s
->grid
, px
- 1, py
);
1596 grid_cell_get(gc
, &ud
);
1597 if (ud
.size
!= 1 || *ud
.data
!= ' ')
1605 window_copy_cursor_start_of_line(struct window_pane
*wp
)
1607 struct window_copy_mode_data
*data
= wp
->modedata
;
1608 struct screen
*back_s
= data
->backing
;
1609 struct grid
*gd
= back_s
->grid
;
1612 if (data
->cx
== 0) {
1613 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1614 while (py
> 0 && gd
->linedata
[py
-1].flags
& GRID_LINE_WRAPPED
) {
1615 window_copy_cursor_up(wp
, 0);
1616 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1619 window_copy_update_cursor(wp
, 0, data
->cy
);
1620 if (window_copy_update_selection(wp
, 1))
1621 window_copy_redraw_lines(wp
, data
->cy
, 1);
1625 window_copy_cursor_back_to_indentation(struct window_pane
*wp
)
1627 struct window_copy_mode_data
*data
= wp
->modedata
;
1629 const struct grid_cell
*gc
;
1630 struct utf8_data ud
;
1633 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1634 xx
= window_copy_find_length(wp
, py
);
1637 gc
= grid_peek_cell(data
->backing
->grid
, px
, py
);
1638 grid_cell_get(gc
, &ud
);
1639 if (ud
.size
!= 1 || *ud
.data
!= ' ')
1644 window_copy_update_cursor(wp
, px
, data
->cy
);
1645 if (window_copy_update_selection(wp
, 1))
1646 window_copy_redraw_lines(wp
, data
->cy
, 1);
1650 window_copy_cursor_end_of_line(struct window_pane
*wp
)
1652 struct window_copy_mode_data
*data
= wp
->modedata
;
1653 struct screen
*back_s
= data
->backing
;
1654 struct grid
*gd
= back_s
->grid
;
1657 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1658 px
= window_copy_find_length(wp
, py
);
1660 if (data
->cx
== px
) {
1661 if (data
->screen
.sel
.flag
&& data
->rectflag
)
1662 px
= screen_size_x(back_s
);
1663 if (gd
->linedata
[py
].flags
& GRID_LINE_WRAPPED
) {
1664 while (py
< gd
->sy
+ gd
->hsize
&&
1665 gd
->linedata
[py
].flags
& GRID_LINE_WRAPPED
) {
1666 window_copy_cursor_down(wp
, 0);
1667 py
= screen_hsize(back_s
)
1668 + data
->cy
- data
->oy
;
1670 px
= window_copy_find_length(wp
, py
);
1673 window_copy_update_cursor(wp
, px
, data
->cy
);
1675 if (window_copy_update_selection(wp
, 1))
1676 window_copy_redraw_lines(wp
, data
->cy
, 1);
1680 window_copy_other_end(struct window_pane
*wp
)
1682 struct window_copy_mode_data
*data
= wp
->modedata
;
1683 struct screen
*s
= &data
->screen
;
1684 u_int selx
, sely
, cx
, cy
, yy
;
1693 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1699 if (sely
< screen_hsize(data
->backing
) - data
->oy
) {
1700 data
->oy
= screen_hsize(data
->backing
) - sely
;
1702 } else if (sely
> screen_hsize(data
->backing
) - data
->oy
+ screen_size_y(s
)) {
1703 data
->oy
= screen_hsize(data
->backing
) - sely
+ screen_size_y(s
) - 1;
1704 data
->cy
= screen_size_y(s
) - 1;
1707 data
->cy
= cy
+ sely
- yy
;
1709 window_copy_redraw_screen(wp
);
1713 window_copy_cursor_left(struct window_pane
*wp
)
1715 struct window_copy_mode_data
*data
= wp
->modedata
;
1717 if (data
->cx
== 0) {
1718 window_copy_cursor_up(wp
, 0);
1719 window_copy_cursor_end_of_line(wp
);
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_right(struct window_pane
*wp
)
1730 struct window_copy_mode_data
*data
= wp
->modedata
;
1733 if (data
->screen
.sel
.flag
&& data
->rectflag
)
1734 px
= screen_size_x(&data
->screen
);
1736 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1737 px
= window_copy_find_length(wp
, py
);
1740 if (data
->cx
>= px
) {
1741 window_copy_cursor_start_of_line(wp
);
1742 window_copy_cursor_down(wp
, 0);
1744 window_copy_update_cursor(wp
, data
->cx
+ 1, data
->cy
);
1745 if (window_copy_update_selection(wp
, 1))
1746 window_copy_redraw_lines(wp
, data
->cy
, 1);
1751 window_copy_cursor_up(struct window_pane
*wp
, int scroll_only
)
1753 struct window_copy_mode_data
*data
= wp
->modedata
;
1754 struct screen
*s
= &data
->screen
;
1755 u_int ox
, oy
, px
, py
;
1757 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1758 ox
= window_copy_find_length(wp
, oy
);
1759 if (data
->cx
!= ox
) {
1760 data
->lastcx
= data
->cx
;
1764 data
->cx
= data
->lastcx
;
1765 if (scroll_only
|| data
->cy
== 0) {
1766 window_copy_scroll_down(wp
, 1);
1768 if (data
->cy
== screen_size_y(s
) - 1)
1769 window_copy_redraw_lines(wp
, data
->cy
, 1);
1771 window_copy_redraw_lines(wp
, data
->cy
, 2);
1774 window_copy_update_cursor(wp
, data
->cx
, data
->cy
- 1);
1775 if (window_copy_update_selection(wp
, 1)) {
1776 if (data
->cy
== screen_size_y(s
) - 1)
1777 window_copy_redraw_lines(wp
, data
->cy
, 1);
1779 window_copy_redraw_lines(wp
, data
->cy
, 2);
1783 if (!data
->screen
.sel
.flag
|| !data
->rectflag
) {
1784 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1785 px
= window_copy_find_length(wp
, py
);
1786 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
1788 window_copy_cursor_end_of_line(wp
);
1793 window_copy_cursor_down(struct window_pane
*wp
, int scroll_only
)
1795 struct window_copy_mode_data
*data
= wp
->modedata
;
1796 struct screen
*s
= &data
->screen
;
1797 u_int ox
, oy
, px
, py
;
1799 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1800 ox
= window_copy_find_length(wp
, oy
);
1801 if (data
->cx
!= ox
) {
1802 data
->lastcx
= data
->cx
;
1806 data
->cx
= data
->lastcx
;
1807 if (scroll_only
|| data
->cy
== screen_size_y(s
) - 1) {
1808 window_copy_scroll_up(wp
, 1);
1809 if (scroll_only
&& data
->cy
> 0)
1810 window_copy_redraw_lines(wp
, data
->cy
- 1, 2);
1812 window_copy_update_cursor(wp
, data
->cx
, data
->cy
+ 1);
1813 if (window_copy_update_selection(wp
, 1))
1814 window_copy_redraw_lines(wp
, data
->cy
- 1, 2);
1817 if (!data
->screen
.sel
.flag
|| !data
->rectflag
) {
1818 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1819 px
= window_copy_find_length(wp
, py
);
1820 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
1822 window_copy_cursor_end_of_line(wp
);
1827 window_copy_cursor_jump(struct window_pane
*wp
)
1829 struct window_copy_mode_data
*data
= wp
->modedata
;
1830 struct screen
*back_s
= data
->backing
;
1831 const struct grid_cell
*gc
;
1832 struct utf8_data ud
;
1836 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1837 xx
= window_copy_find_length(wp
, py
);
1840 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1841 grid_cell_get(gc
, &ud
);
1842 if (!(gc
->flags
& GRID_FLAG_PADDING
) &&
1843 ud
.size
== 1 && *ud
.data
== data
->jumpchar
) {
1844 window_copy_update_cursor(wp
, px
, data
->cy
);
1845 if (window_copy_update_selection(wp
, 1))
1846 window_copy_redraw_lines(wp
, data
->cy
, 1);
1854 window_copy_cursor_jump_back(struct window_pane
*wp
)
1856 struct window_copy_mode_data
*data
= wp
->modedata
;
1857 struct screen
*back_s
= data
->backing
;
1858 const struct grid_cell
*gc
;
1859 struct utf8_data ud
;
1863 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1869 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1870 grid_cell_get(gc
, &ud
);
1871 if (!(gc
->flags
& GRID_FLAG_PADDING
) &&
1872 ud
.size
== 1 && *ud
.data
== data
->jumpchar
) {
1873 window_copy_update_cursor(wp
, px
, data
->cy
);
1874 if (window_copy_update_selection(wp
, 1))
1875 window_copy_redraw_lines(wp
, data
->cy
, 1);
1885 window_copy_cursor_jump_to(struct window_pane
*wp
)
1887 struct window_copy_mode_data
*data
= wp
->modedata
;
1888 struct screen
*back_s
= data
->backing
;
1889 const struct grid_cell
*gc
;
1890 struct utf8_data ud
;
1894 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1895 xx
= window_copy_find_length(wp
, py
);
1898 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1899 grid_cell_get(gc
, &ud
);
1900 if (!(gc
->flags
& GRID_FLAG_PADDING
) &&
1901 ud
.size
== 1 && *ud
.data
== data
->jumpchar
) {
1902 window_copy_update_cursor(wp
, px
- 1, data
->cy
);
1903 if (window_copy_update_selection(wp
, 1))
1904 window_copy_redraw_lines(wp
, data
->cy
, 1);
1912 window_copy_cursor_jump_to_back(struct window_pane
*wp
)
1914 struct window_copy_mode_data
*data
= wp
->modedata
;
1915 struct screen
*back_s
= data
->backing
;
1916 const struct grid_cell
*gc
;
1917 struct utf8_data ud
;
1921 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1927 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1928 grid_cell_get(gc
, &ud
);
1929 if (!(gc
->flags
& GRID_FLAG_PADDING
) &&
1930 ud
.size
== 1 && *ud
.data
== data
->jumpchar
) {
1931 window_copy_update_cursor(wp
, px
+ 1, data
->cy
);
1932 if (window_copy_update_selection(wp
, 1))
1933 window_copy_redraw_lines(wp
, data
->cy
, 1);
1943 window_copy_cursor_next_word(struct window_pane
*wp
, const char *separators
)
1945 struct window_copy_mode_data
*data
= wp
->modedata
;
1946 struct screen
*back_s
= data
->backing
;
1947 u_int px
, py
, xx
, yy
;
1951 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1952 xx
= window_copy_find_length(wp
, py
);
1953 yy
= screen_hsize(back_s
) + screen_size_y(back_s
) - 1;
1956 * First skip past any nonword characters and then any word characters.
1958 * expected is initially set to 0 for the former and then 1 for the
1963 window_copy_in_set(wp
, px
, py
, separators
) == expected
) {
1964 /* Move down if we're past the end of the line. */
1968 window_copy_cursor_down(wp
, 0);
1971 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1972 xx
= window_copy_find_length(wp
, py
);
1976 expected
= !expected
;
1977 } while (expected
== 1);
1979 window_copy_update_cursor(wp
, px
, data
->cy
);
1980 if (window_copy_update_selection(wp
, 1))
1981 window_copy_redraw_lines(wp
, data
->cy
, 1);
1985 window_copy_cursor_next_word_end(struct window_pane
*wp
, const char *separators
)
1987 struct window_copy_mode_data
*data
= wp
->modedata
;
1988 struct options
*oo
= &wp
->window
->options
;
1989 struct screen
*back_s
= data
->backing
;
1990 u_int px
, py
, xx
, yy
;
1991 int keys
, expected
= 1;
1994 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1995 xx
= window_copy_find_length(wp
, py
);
1996 yy
= screen_hsize(back_s
) + screen_size_y(back_s
) - 1;
1998 keys
= options_get_number(oo
, "mode-keys");
1999 if (keys
== MODEKEY_VI
&& !window_copy_in_set(wp
, px
, py
, separators
))
2003 * First skip past any word characters, then any nonword characters.
2005 * expected is initially set to 1 for the former and then 0 for the
2010 window_copy_in_set(wp
, px
, py
, separators
) == expected
) {
2011 /* Move down if we're past the end of the line. */
2015 window_copy_cursor_down(wp
, 0);
2018 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
2019 xx
= window_copy_find_length(wp
, py
);
2023 expected
= !expected
;
2024 } while (expected
== 0);
2026 if (keys
== MODEKEY_VI
&& px
!= 0)
2029 window_copy_update_cursor(wp
, px
, data
->cy
);
2030 if (window_copy_update_selection(wp
, 1))
2031 window_copy_redraw_lines(wp
, data
->cy
, 1);
2034 /* Move to the previous place where a word begins. */
2036 window_copy_cursor_previous_word(struct window_pane
*wp
, const char *separators
)
2038 struct window_copy_mode_data
*data
= wp
->modedata
;
2042 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2044 /* Move back to the previous word character. */
2048 if (!window_copy_in_set(wp
, px
, py
, separators
))
2051 if (data
->cy
== 0 &&
2052 (screen_hsize(data
->backing
) == 0 ||
2053 data
->oy
>= screen_hsize(data
->backing
) - 1))
2055 window_copy_cursor_up(wp
, 0);
2057 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2058 px
= window_copy_find_length(wp
, py
);
2062 /* Move back to the beginning of this word. */
2063 while (px
> 0 && !window_copy_in_set(wp
, px
- 1, py
, separators
))
2067 window_copy_update_cursor(wp
, px
, data
->cy
);
2068 if (window_copy_update_selection(wp
, 1))
2069 window_copy_redraw_lines(wp
, data
->cy
, 1);
2073 window_copy_scroll_up(struct window_pane
*wp
, u_int ny
)
2075 struct window_copy_mode_data
*data
= wp
->modedata
;
2076 struct screen
*s
= &data
->screen
;
2077 struct screen_write_ctx ctx
;
2085 window_copy_update_selection(wp
, 0);
2087 screen_write_start(&ctx
, wp
, NULL
);
2088 screen_write_cursormove(&ctx
, 0, 0);
2089 screen_write_deleteline(&ctx
, ny
);
2090 window_copy_write_lines(wp
, &ctx
, screen_size_y(s
) - ny
, ny
);
2091 window_copy_write_line(wp
, &ctx
, 0);
2092 if (screen_size_y(s
) > 1)
2093 window_copy_write_line(wp
, &ctx
, 1);
2094 if (screen_size_y(s
) > 3)
2095 window_copy_write_line(wp
, &ctx
, screen_size_y(s
) - 2);
2096 if (s
->sel
.flag
&& screen_size_y(s
) > ny
)
2097 window_copy_write_line(wp
, &ctx
, screen_size_y(s
) - ny
- 1);
2098 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
2099 screen_write_stop(&ctx
);
2103 window_copy_scroll_down(struct window_pane
*wp
, u_int ny
)
2105 struct window_copy_mode_data
*data
= wp
->modedata
;
2106 struct screen
*s
= &data
->screen
;
2107 struct screen_write_ctx ctx
;
2109 if (ny
> screen_hsize(data
->backing
))
2112 if (data
->oy
> screen_hsize(data
->backing
) - ny
)
2113 ny
= screen_hsize(data
->backing
) - data
->oy
;
2118 window_copy_update_selection(wp
, 0);
2120 screen_write_start(&ctx
, wp
, NULL
);
2121 screen_write_cursormove(&ctx
, 0, 0);
2122 screen_write_insertline(&ctx
, ny
);
2123 window_copy_write_lines(wp
, &ctx
, 0, ny
);
2124 if (s
->sel
.flag
&& screen_size_y(s
) > ny
)
2125 window_copy_write_line(wp
, &ctx
, ny
);
2126 else if (ny
== 1) /* nuke position */
2127 window_copy_write_line(wp
, &ctx
, 1);
2128 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
2129 screen_write_stop(&ctx
);
2133 window_copy_rectangle_toggle(struct window_pane
*wp
)
2135 struct window_copy_mode_data
*data
= wp
->modedata
;
2138 data
->rectflag
= !data
->rectflag
;
2140 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2141 px
= window_copy_find_length(wp
, py
);
2143 window_copy_update_cursor(wp
, px
, data
->cy
);
2145 window_copy_update_selection(wp
, 1);
2146 window_copy_redraw_screen(wp
);