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>
26 struct screen
*window_copy_init(struct window_pane
*);
27 void window_copy_free(struct window_pane
*);
28 void window_copy_resize(struct window_pane
*, u_int
, u_int
);
29 void window_copy_key(struct window_pane
*, struct session
*, int);
30 int window_copy_key_input(struct window_pane
*, int);
31 int window_copy_key_numeric_prefix(struct window_pane
*, int);
32 void window_copy_mouse(
33 struct window_pane
*, struct session
*, struct mouse_event
*);
35 void window_copy_redraw_lines(struct window_pane
*, u_int
, u_int
);
36 void window_copy_redraw_screen(struct window_pane
*);
37 void window_copy_write_line(
38 struct window_pane
*, struct screen_write_ctx
*, u_int
);
39 void window_copy_write_lines(
40 struct window_pane
*, struct screen_write_ctx
*, u_int
, u_int
);
42 void window_copy_scroll_to(struct window_pane
*, u_int
, u_int
);
43 int window_copy_search_compare(
44 struct grid
*, u_int
, u_int
, struct grid
*, u_int
);
45 int window_copy_search_lr(
46 struct grid
*, struct grid
*, u_int
*, u_int
, u_int
, u_int
);
47 int window_copy_search_rl(
48 struct grid
*, struct grid
*, u_int
*, u_int
, u_int
, u_int
);
49 void window_copy_search_up(struct window_pane
*, const char *);
50 void window_copy_search_down(struct window_pane
*, const char *);
51 void window_copy_goto_line(struct window_pane
*, const char *);
52 void window_copy_update_cursor(struct window_pane
*, u_int
, u_int
);
53 void window_copy_start_selection(struct window_pane
*);
54 int window_copy_update_selection(struct window_pane
*);
55 void window_copy_copy_selection(struct window_pane
*);
56 void window_copy_clear_selection(struct window_pane
*);
57 void window_copy_copy_line(
58 struct window_pane
*, char **, size_t *, u_int
, u_int
, u_int
);
59 int window_copy_in_set(struct window_pane
*, u_int
, u_int
, const char *);
60 u_int
window_copy_find_length(struct window_pane
*, u_int
);
61 void window_copy_cursor_start_of_line(struct window_pane
*);
62 void window_copy_cursor_back_to_indentation(struct window_pane
*);
63 void window_copy_cursor_end_of_line(struct window_pane
*);
64 void window_copy_cursor_left(struct window_pane
*);
65 void window_copy_cursor_right(struct window_pane
*);
66 void window_copy_cursor_up(struct window_pane
*, int);
67 void window_copy_cursor_down(struct window_pane
*, int);
68 void window_copy_cursor_jump(struct window_pane
*);
69 void window_copy_cursor_jump_back(struct window_pane
*);
70 void window_copy_cursor_next_word(struct window_pane
*, const char *);
71 void window_copy_cursor_next_word_end(struct window_pane
*, const char *);
72 void window_copy_cursor_previous_word(struct window_pane
*, const char *);
73 void window_copy_scroll_up(struct window_pane
*, u_int
);
74 void window_copy_scroll_down(struct window_pane
*, u_int
);
75 void window_copy_rectangle_toggle(struct window_pane
*);
77 const struct window_mode window_copy_mode
= {
86 enum window_copy_input_type
{
88 WINDOW_COPY_NUMERICPREFIX
,
90 WINDOW_COPY_SEARCHDOWN
,
91 WINDOW_COPY_JUMPFORWARD
,
97 * Copy-mode's visible screen (the "screen" field) is filled from one of
98 * two sources: the original contents of the pane (used when we
99 * actually enter via the "copy-mode" command, to copy the contents of
100 * the current pane), or else a series of lines containing the output
101 * from an output-writing tmux command (such as any of the "show-*" or
102 * "list-*" commands).
104 * In either case, the full content of the copy-mode grid is pointed at
105 * by the "backing" field, and is copied into "screen" as needed (that
106 * is, when scrolling occurs). When copy-mode is backed by a pane,
107 * backing points directly at that pane's screen structure (&wp->base);
108 * when backed by a list of output-lines from a command, it points at
109 * a newly-allocated screen structure (which is deallocated when the
112 struct window_copy_mode_data
{
113 struct screen screen
;
115 struct screen
*backing
;
116 int backing_written
; /* backing display has started */
118 struct mode_key_data mdata
;
125 u_int rectflag
; /* are we in rectangle copy mode? */
130 u_int lastcx
; /* position in last line with content */
131 u_int lastsx
; /* size of last line with content */
133 enum window_copy_input_type inputtype
;
134 const char *inputprompt
;
139 enum window_copy_input_type searchtype
;
142 enum window_copy_input_type jumptype
;
147 window_copy_init(struct window_pane
*wp
)
149 struct window_copy_mode_data
*data
;
153 wp
->modedata
= data
= xmalloc(sizeof *data
);
161 data
->backing_written
= 0;
165 data
->inputtype
= WINDOW_COPY_OFF
;
166 data
->inputprompt
= NULL
;
167 data
->inputstr
= xstrdup("");
170 data
->searchtype
= WINDOW_COPY_OFF
;
171 data
->searchstr
= NULL
;
173 wp
->flags
|= PANE_FREEZE
;
175 bufferevent_disable(wp
->event
, EV_READ
|EV_WRITE
);
177 data
->jumptype
= WINDOW_COPY_OFF
;
178 data
->jumpchar
= '\0';
181 screen_init(s
, screen_size_x(&wp
->base
), screen_size_y(&wp
->base
), 0);
182 if (options_get_number(&wp
->window
->options
, "mode-mouse"))
183 s
->mode
|= MODE_MOUSE_STANDARD
;
185 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
186 if (keys
== MODEKEY_EMACS
)
187 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_copy
);
189 mode_key_init(&data
->mdata
, &mode_key_tree_vi_copy
);
191 data
->backing
= NULL
;
197 window_copy_init_from_pane(struct window_pane
*wp
)
199 struct window_copy_mode_data
*data
= wp
->modedata
;
200 struct screen
*s
= &data
->screen
;
201 struct screen_write_ctx ctx
;
204 if (wp
->mode
!= &window_copy_mode
)
205 fatalx("not in copy mode");
207 data
->backing
= &wp
->base
;
208 data
->cx
= data
->backing
->cx
;
209 data
->cy
= data
->backing
->cy
;
214 screen_write_start(&ctx
, NULL
, s
);
215 for (i
= 0; i
< screen_size_y(s
); i
++)
216 window_copy_write_line(wp
, &ctx
, i
);
217 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
218 screen_write_stop(&ctx
);
222 window_copy_init_for_output(struct window_pane
*wp
)
224 struct window_copy_mode_data
*data
= wp
->modedata
;
226 data
->backing
= xmalloc(sizeof *data
->backing
);
227 screen_init(data
->backing
, screen_size_x(&wp
->base
),
228 screen_size_y(&wp
->base
), UINT_MAX
);
229 data
->backing
->mode
&= ~MODE_WRAP
;
233 window_copy_free(struct window_pane
*wp
)
235 struct window_copy_mode_data
*data
= wp
->modedata
;
237 wp
->flags
&= ~PANE_FREEZE
;
239 bufferevent_enable(wp
->event
, EV_READ
|EV_WRITE
);
241 if (data
->searchstr
!= NULL
)
242 xfree(data
->searchstr
);
243 xfree(data
->inputstr
);
245 if (data
->backing
!= &wp
->base
) {
246 screen_free(data
->backing
);
247 xfree(data
->backing
);
249 screen_free(&data
->screen
);
255 window_copy_add(struct window_pane
*wp
, const char *fmt
, ...)
260 window_copy_vadd(wp
, fmt
, ap
);
265 window_copy_vadd(struct window_pane
*wp
, const char *fmt
, va_list ap
)
267 struct window_copy_mode_data
*data
= wp
->modedata
;
268 struct screen
*backing
= data
->backing
;
269 struct screen_write_ctx back_ctx
, ctx
;
274 if (backing
== &wp
->base
)
277 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
278 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
280 old_hsize
= screen_hsize(data
->backing
);
281 screen_write_start(&back_ctx
, NULL
, backing
);
282 if (data
->backing_written
) {
284 * On the second or later line, do a CRLF before writing
285 * (so it's on a new line).
287 screen_write_carriagereturn(&back_ctx
);
288 screen_write_linefeed(&back_ctx
, 0);
290 data
->backing_written
= 1;
291 screen_write_vnputs(&back_ctx
, 0, &gc
, utf8flag
, fmt
, ap
);
292 screen_write_stop(&back_ctx
);
294 data
->oy
+= screen_hsize(data
->backing
) - old_hsize
;
296 screen_write_start(&ctx
, wp
, &data
->screen
);
299 * If the history has changed, draw the top line.
300 * (If there's any history at all, it has changed.)
302 if (screen_hsize(data
->backing
))
303 window_copy_redraw_lines(wp
, 0, 1);
305 /* Write the line, if it's visible. */
306 if (backing
->cy
+ data
->oy
< screen_size_y(backing
))
307 window_copy_redraw_lines(wp
, backing
->cy
, 1);
309 screen_write_stop(&ctx
);
313 window_copy_pageup(struct window_pane
*wp
)
315 struct window_copy_mode_data
*data
= wp
->modedata
;
316 struct screen
*s
= &data
->screen
;
320 if (screen_size_y(s
) > 2)
321 n
= screen_size_y(s
) - 2;
322 if (data
->oy
+ n
> screen_hsize(data
->backing
))
323 data
->oy
= screen_hsize(data
->backing
);
326 window_copy_update_selection(wp
);
327 window_copy_redraw_screen(wp
);
331 window_copy_resize(struct window_pane
*wp
, u_int sx
, u_int sy
)
333 struct window_copy_mode_data
*data
= wp
->modedata
;
334 struct screen
*s
= &data
->screen
;
335 struct screen_write_ctx ctx
;
337 screen_resize(s
, sx
, sy
);
338 if (data
->backing
!= &wp
->base
)
339 screen_resize(data
->backing
, sx
, sy
);
341 if (data
->cy
> sy
- 1)
345 if (data
->oy
> screen_hsize(data
->backing
))
346 data
->oy
= screen_hsize(data
->backing
);
348 window_copy_clear_selection(wp
);
350 screen_write_start(&ctx
, NULL
, s
);
351 window_copy_write_lines(wp
, &ctx
, 0, screen_size_y(s
) - 1);
352 screen_write_stop(&ctx
);
354 window_copy_redraw_screen(wp
);
358 window_copy_key(struct window_pane
*wp
, struct session
*sess
, int key
)
360 const char *word_separators
;
361 struct window_copy_mode_data
*data
= wp
->modedata
;
362 struct screen
*s
= &data
->screen
;
365 enum mode_key_cmd cmd
;
367 np
= data
->numprefix
;
371 if (data
->inputtype
== WINDOW_COPY_JUMPFORWARD
||
372 data
->inputtype
== WINDOW_COPY_JUMPBACK
) {
373 /* Ignore keys with modifiers. */
374 if ((key
& KEYC_MASK_MOD
) == 0) {
375 data
->jumpchar
= key
;
376 if (data
->inputtype
== WINDOW_COPY_JUMPFORWARD
) {
377 for (; np
!= 0; np
--)
378 window_copy_cursor_jump(wp
);
380 for (; np
!= 0; np
--)
381 window_copy_cursor_jump_back(wp
);
384 data
->jumptype
= data
->inputtype
;
385 data
->inputtype
= WINDOW_COPY_OFF
;
386 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
388 } else if (data
->inputtype
== WINDOW_COPY_NUMERICPREFIX
) {
389 if (window_copy_key_numeric_prefix(wp
, key
) == 0)
391 data
->inputtype
= WINDOW_COPY_OFF
;
392 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
393 } else if (data
->inputtype
!= WINDOW_COPY_OFF
) {
394 if (window_copy_key_input(wp
, key
) != 0)
399 cmd
= mode_key_lookup(&data
->mdata
, key
);
401 case MODEKEYCOPY_CANCEL
:
402 window_pane_reset_mode(wp
);
404 case MODEKEYCOPY_LEFT
:
405 for (; np
!= 0; np
--)
406 window_copy_cursor_left(wp
);
408 case MODEKEYCOPY_RIGHT
:
409 for (; np
!= 0; np
--)
410 window_copy_cursor_right(wp
);
413 for (; np
!= 0; np
--)
414 window_copy_cursor_up(wp
, 0);
416 case MODEKEYCOPY_DOWN
:
417 for (; np
!= 0; np
--)
418 window_copy_cursor_down(wp
, 0);
420 case MODEKEYCOPY_SCROLLUP
:
421 for (; np
!= 0; np
--)
422 window_copy_cursor_up(wp
, 1);
424 case MODEKEYCOPY_SCROLLDOWN
:
425 for (; np
!= 0; np
--)
426 window_copy_cursor_down(wp
, 1);
428 case MODEKEYCOPY_PREVIOUSPAGE
:
429 for (; np
!= 0; np
--)
430 window_copy_pageup(wp
);
432 case MODEKEYCOPY_NEXTPAGE
:
434 if (screen_size_y(s
) > 2)
435 n
= screen_size_y(s
) - 2;
436 for (; np
!= 0; np
--) {
442 window_copy_update_selection(wp
);
443 window_copy_redraw_screen(wp
);
445 case MODEKEYCOPY_HALFPAGEUP
:
446 n
= screen_size_y(s
) / 2;
447 for (; np
!= 0; np
--) {
448 if (data
->oy
+ n
> screen_hsize(data
->backing
))
449 data
->oy
= screen_hsize(data
->backing
);
453 window_copy_update_selection(wp
);
454 window_copy_redraw_screen(wp
);
456 case MODEKEYCOPY_HALFPAGEDOWN
:
457 n
= screen_size_y(s
) / 2;
458 for (; np
!= 0; np
--) {
464 window_copy_update_selection(wp
);
465 window_copy_redraw_screen(wp
);
467 case MODEKEYCOPY_TOPLINE
:
470 window_copy_update_selection(wp
);
471 window_copy_redraw_screen(wp
);
473 case MODEKEYCOPY_MIDDLELINE
:
475 data
->cy
= (screen_size_y(s
) - 1) / 2;
476 window_copy_update_selection(wp
);
477 window_copy_redraw_screen(wp
);
479 case MODEKEYCOPY_BOTTOMLINE
:
481 data
->cy
= screen_size_y(s
) - 1;
482 window_copy_update_selection(wp
);
483 window_copy_redraw_screen(wp
);
485 case MODEKEYCOPY_HISTORYTOP
:
488 data
->oy
= screen_hsize(data
->backing
);
489 window_copy_update_selection(wp
);
490 window_copy_redraw_screen(wp
);
492 case MODEKEYCOPY_HISTORYBOTTOM
:
494 data
->cy
= screen_size_y(s
) - 1;
496 window_copy_update_selection(wp
);
497 window_copy_redraw_screen(wp
);
499 case MODEKEYCOPY_STARTSELECTION
:
500 window_copy_start_selection(wp
);
501 window_copy_redraw_screen(wp
);
503 case MODEKEYCOPY_COPYLINE
:
504 case MODEKEYCOPY_SELECTLINE
:
505 window_copy_cursor_start_of_line(wp
);
507 case MODEKEYCOPY_COPYENDOFLINE
:
508 window_copy_start_selection(wp
);
510 window_copy_cursor_down(wp
, 0);
511 window_copy_cursor_end_of_line(wp
);
512 window_copy_redraw_screen(wp
);
514 /* If a copy command then copy the selection and exit. */
516 (cmd
== MODEKEYCOPY_COPYLINE
||
517 cmd
== MODEKEYCOPY_COPYENDOFLINE
)) {
518 window_copy_copy_selection(wp
);
519 window_pane_reset_mode(wp
);
523 case MODEKEYCOPY_CLEARSELECTION
:
524 window_copy_clear_selection(wp
);
525 window_copy_redraw_screen(wp
);
527 case MODEKEYCOPY_COPYSELECTION
:
529 window_copy_copy_selection(wp
);
530 window_pane_reset_mode(wp
);
534 case MODEKEYCOPY_STARTOFLINE
:
535 window_copy_cursor_start_of_line(wp
);
537 case MODEKEYCOPY_BACKTOINDENTATION
:
538 window_copy_cursor_back_to_indentation(wp
);
540 case MODEKEYCOPY_ENDOFLINE
:
541 window_copy_cursor_end_of_line(wp
);
543 case MODEKEYCOPY_NEXTSPACE
:
544 for (; np
!= 0; np
--)
545 window_copy_cursor_next_word(wp
, " ");
547 case MODEKEYCOPY_NEXTSPACEEND
:
548 for (; np
!= 0; np
--)
549 window_copy_cursor_next_word_end(wp
, " ");
551 case MODEKEYCOPY_NEXTWORD
:
553 options_get_string(&wp
->window
->options
, "word-separators");
554 for (; np
!= 0; np
--)
555 window_copy_cursor_next_word(wp
, word_separators
);
557 case MODEKEYCOPY_NEXTWORDEND
:
559 options_get_string(&wp
->window
->options
, "word-separators");
560 for (; np
!= 0; np
--)
561 window_copy_cursor_next_word_end(wp
, word_separators
);
563 case MODEKEYCOPY_PREVIOUSSPACE
:
564 for (; np
!= 0; np
--)
565 window_copy_cursor_previous_word(wp
, " ");
567 case MODEKEYCOPY_PREVIOUSWORD
:
569 options_get_string(&wp
->window
->options
, "word-separators");
570 for (; np
!= 0; np
--)
571 window_copy_cursor_previous_word(wp
, word_separators
);
573 case MODEKEYCOPY_JUMP
:
574 data
->inputtype
= WINDOW_COPY_JUMPFORWARD
;
575 data
->inputprompt
= "Jump Forward";
576 *data
->inputstr
= '\0';
577 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
578 return; /* skip numprefix reset */
579 case MODEKEYCOPY_JUMPAGAIN
:
580 if (data
->jumptype
== WINDOW_COPY_JUMPFORWARD
) {
581 for (; np
!= 0; np
--)
582 window_copy_cursor_jump(wp
);
583 } else if (data
->jumptype
== WINDOW_COPY_JUMPBACK
) {
584 for (; np
!= 0; np
--)
585 window_copy_cursor_jump_back(wp
);
588 case MODEKEYCOPY_JUMPREVERSE
:
589 if (data
->jumptype
== WINDOW_COPY_JUMPFORWARD
) {
590 for (; np
!= 0; np
--)
591 window_copy_cursor_jump_back(wp
);
592 } else if (data
->jumptype
== WINDOW_COPY_JUMPBACK
) {
593 for (; np
!= 0; np
--)
594 window_copy_cursor_jump(wp
);
597 case MODEKEYCOPY_JUMPBACK
:
598 data
->inputtype
= WINDOW_COPY_JUMPBACK
;
599 data
->inputprompt
= "Jump Back";
600 *data
->inputstr
= '\0';
601 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
602 return; /* skip numprefix reset */
603 case MODEKEYCOPY_SEARCHUP
:
604 data
->inputtype
= WINDOW_COPY_SEARCHUP
;
605 data
->inputprompt
= "Search Up";
607 case MODEKEYCOPY_SEARCHDOWN
:
608 data
->inputtype
= WINDOW_COPY_SEARCHDOWN
;
609 data
->inputprompt
= "Search Down";
611 case MODEKEYCOPY_SEARCHAGAIN
:
612 case MODEKEYCOPY_SEARCHREVERSE
:
613 switch (data
->searchtype
) {
614 case WINDOW_COPY_OFF
:
615 case WINDOW_COPY_GOTOLINE
:
616 case WINDOW_COPY_JUMPFORWARD
:
617 case WINDOW_COPY_JUMPBACK
:
618 case WINDOW_COPY_NUMERICPREFIX
:
620 case WINDOW_COPY_SEARCHUP
:
621 if (cmd
== MODEKEYCOPY_SEARCHAGAIN
) {
622 for (; np
!= 0; np
--) {
623 window_copy_search_up(
624 wp
, data
->searchstr
);
627 for (; np
!= 0; np
--) {
628 window_copy_search_down(
629 wp
, data
->searchstr
);
633 case WINDOW_COPY_SEARCHDOWN
:
634 if (cmd
== MODEKEYCOPY_SEARCHAGAIN
) {
635 for (; np
!= 0; np
--) {
636 window_copy_search_down(
637 wp
, data
->searchstr
);
640 for (; np
!= 0; np
--) {
641 window_copy_search_up(
642 wp
, data
->searchstr
);
648 case MODEKEYCOPY_GOTOLINE
:
649 data
->inputtype
= WINDOW_COPY_GOTOLINE
;
650 data
->inputprompt
= "Goto Line";
651 *data
->inputstr
= '\0';
653 case MODEKEYCOPY_STARTNUMBERPREFIX
:
654 key
&= KEYC_MASK_KEY
;
655 if (key
>= '0' && key
<= '9') {
656 data
->inputtype
= WINDOW_COPY_NUMERICPREFIX
;
658 window_copy_key_numeric_prefix(wp
, key
);
662 case MODEKEYCOPY_RECTANGLETOGGLE
:
663 window_copy_rectangle_toggle(wp
);
673 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
674 if (keys
== MODEKEY_EMACS
)
675 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_edit
);
677 mode_key_init(&data
->mdata
, &mode_key_tree_vi_edit
);
679 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
683 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
684 if (keys
== MODEKEY_EMACS
)
685 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_copy
);
687 mode_key_init(&data
->mdata
, &mode_key_tree_vi_copy
);
689 data
->inputtype
= WINDOW_COPY_OFF
;
690 data
->inputprompt
= NULL
;
692 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
696 window_copy_key_input(struct window_pane
*wp
, int key
)
698 struct window_copy_mode_data
*data
= wp
->modedata
;
699 struct screen
*s
= &data
->screen
;
703 switch (mode_key_lookup(&data
->mdata
, key
)) {
704 case MODEKEYEDIT_CANCEL
:
707 case MODEKEYEDIT_BACKSPACE
:
708 inputlen
= strlen(data
->inputstr
);
710 data
->inputstr
[inputlen
- 1] = '\0';
712 case MODEKEYEDIT_DELETELINE
:
713 *data
->inputstr
= '\0';
715 case MODEKEYEDIT_ENTER
:
716 np
= data
->numprefix
;
720 switch (data
->inputtype
) {
721 case WINDOW_COPY_OFF
:
722 case WINDOW_COPY_JUMPFORWARD
:
723 case WINDOW_COPY_JUMPBACK
:
724 case WINDOW_COPY_NUMERICPREFIX
:
726 case WINDOW_COPY_SEARCHUP
:
727 for (; np
!= 0; np
--)
728 window_copy_search_up(wp
, data
->inputstr
);
729 data
->searchtype
= data
->inputtype
;
730 data
->searchstr
= xstrdup(data
->inputstr
);
732 case WINDOW_COPY_SEARCHDOWN
:
733 for (; np
!= 0; np
--)
734 window_copy_search_down(wp
, data
->inputstr
);
735 data
->searchtype
= data
->inputtype
;
736 data
->searchstr
= xstrdup(data
->inputstr
);
738 case WINDOW_COPY_GOTOLINE
:
739 window_copy_goto_line(wp
, data
->inputstr
);
740 *data
->inputstr
= '\0';
746 if (key
< 32 || key
> 126)
748 inputlen
= strlen(data
->inputstr
) + 2;
750 data
->inputstr
= xrealloc(data
->inputstr
, 1, inputlen
);
751 data
->inputstr
[inputlen
- 2] = key
;
752 data
->inputstr
[inputlen
- 1] = '\0';
758 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
763 window_copy_key_numeric_prefix(struct window_pane
*wp
, int key
)
765 struct window_copy_mode_data
*data
= wp
->modedata
;
766 struct screen
*s
= &data
->screen
;
768 key
&= KEYC_MASK_KEY
;
769 if (key
< '0' || key
> '9')
772 if (data
->numprefix
>= 100) /* no more than three digits */
774 data
->numprefix
= data
->numprefix
* 10 + key
- '0';
776 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
783 struct window_pane
*wp
, struct session
*sess
, struct mouse_event
*m
)
785 struct window_copy_mode_data
*data
= wp
->modedata
;
786 struct screen
*s
= &data
->screen
;
789 if (m
->x
>= screen_size_x(s
))
791 if (m
->y
>= screen_size_y(s
))
794 /* If mouse wheel (buttons 4 and 5), scroll. */
795 if ((m
->b
& MOUSE_45
)) {
796 if ((m
->b
& MOUSE_BUTTON
) == MOUSE_1
) {
797 for (i
= 0; i
< 5; i
++)
798 window_copy_cursor_up(wp
, 0);
799 } else if ((m
->b
& MOUSE_BUTTON
) == MOUSE_2
) {
801 for (i
= 0; i
< 5; i
++)
802 window_copy_cursor_down(wp
, 0);
803 if (old_cy
== data
->cy
)
810 * If already reading motion, move the cursor while buttons are still
811 * pressed, or stop the selection on their release.
813 if (s
->mode
& MODE_MOUSE_BUTTON
) {
814 if ((m
->b
& MOUSE_BUTTON
) != MOUSE_UP
) {
815 window_copy_update_cursor(wp
, m
->x
, m
->y
);
816 if (window_copy_update_selection(wp
))
817 window_copy_redraw_screen(wp
);
823 /* Otherwise if other buttons pressed, start selection and motion. */
824 if ((m
->b
& MOUSE_BUTTON
) != MOUSE_UP
) {
825 s
->mode
&= ~MODE_MOUSE_STANDARD
;
826 s
->mode
|= MODE_MOUSE_BUTTON
;
828 window_copy_update_cursor(wp
, m
->x
, m
->y
);
829 window_copy_start_selection(wp
);
830 window_copy_redraw_screen(wp
);
836 s
->mode
&= ~MODE_MOUSE_BUTTON
;
837 s
->mode
|= MODE_MOUSE_STANDARD
;
839 window_copy_copy_selection(wp
);
840 window_pane_reset_mode(wp
);
845 window_copy_scroll_to(struct window_pane
*wp
, u_int px
, u_int py
)
847 struct window_copy_mode_data
*data
= wp
->modedata
;
848 struct grid
*gd
= data
->backing
->grid
;
857 } else if (py
> gd
->hsize
+ gd
->sy
- gap
) {
859 data
->cy
= py
- gd
->hsize
;
861 offset
= py
+ gap
- gd
->sy
;
862 data
->cy
= py
- offset
;
864 data
->oy
= gd
->hsize
- offset
;
866 window_copy_update_selection(wp
);
867 window_copy_redraw_screen(wp
);
871 window_copy_search_compare(
872 struct grid
*gd
, u_int px
, u_int py
, struct grid
*sgd
, u_int spx
)
874 const struct grid_cell
*gc
, *sgc
;
875 const struct grid_utf8
*gu
, *sgu
;
877 gc
= grid_peek_cell(gd
, px
, py
);
878 sgc
= grid_peek_cell(sgd
, spx
, 0);
880 if ((gc
->flags
& GRID_FLAG_UTF8
) != (sgc
->flags
& GRID_FLAG_UTF8
))
883 if (gc
->flags
& GRID_FLAG_UTF8
) {
884 gu
= grid_peek_utf8(gd
, px
, py
);
885 sgu
= grid_peek_utf8(sgd
, spx
, 0);
886 if (grid_utf8_compare(gu
, sgu
))
889 if (gc
->data
== sgc
->data
)
896 window_copy_search_lr(struct grid
*gd
,
897 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
)
901 for (ax
= first
; ax
< last
; ax
++) {
902 if (ax
+ sgd
->sx
>= gd
->sx
)
904 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
906 if (!window_copy_search_compare(gd
, px
, py
, sgd
, bx
))
918 window_copy_search_rl(struct grid
*gd
,
919 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
)
923 for (ax
= last
+ 1; ax
> first
; ax
--) {
924 if (gd
->sx
- (ax
- 1) < sgd
->sx
)
926 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
928 if (!window_copy_search_compare(gd
, px
, py
, sgd
, bx
))
940 window_copy_search_up(struct window_pane
*wp
, const char *searchstr
)
942 struct window_copy_mode_data
*data
= wp
->modedata
;
943 struct screen
*s
= data
->backing
, ss
;
944 struct screen_write_ctx ctx
;
945 struct grid
*gd
= s
->grid
, *sgd
;
948 u_int i
, last
, fx
, fy
, px
;
949 int utf8flag
, n
, wrapped
;
951 if (*searchstr
== '\0')
953 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
954 searchlen
= screen_write_strlen(utf8flag
, "%s", searchstr
);
956 screen_init(&ss
, searchlen
, 1, 0);
957 screen_write_start(&ctx
, NULL
, &ss
);
958 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
959 screen_write_nputs(&ctx
, -1, &gc
, utf8flag
, "%s", searchstr
);
960 screen_write_stop(&ctx
);
963 fy
= gd
->hsize
- data
->oy
+ data
->cy
;
976 for (i
= fy
+ 1; i
> 0; i
--) {
977 last
= screen_size_x(s
);
980 n
= window_copy_search_rl(gd
, sgd
, &px
, i
- 1, 0, last
);
982 window_copy_scroll_to(wp
, px
, i
- 1);
986 if (!n
&& !wrapped
) {
988 fy
= gd
->hsize
+ gd
->sy
- 1;
997 window_copy_search_down(struct window_pane
*wp
, const char *searchstr
)
999 struct window_copy_mode_data
*data
= wp
->modedata
;
1000 struct screen
*s
= data
->backing
, ss
;
1001 struct screen_write_ctx ctx
;
1002 struct grid
*gd
= s
->grid
, *sgd
;
1003 struct grid_cell gc
;
1005 u_int i
, first
, fx
, fy
, px
;
1006 int utf8flag
, n
, wrapped
;
1008 if (*searchstr
== '\0')
1010 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
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
;
1022 if (fx
== gd
->sx
- 1) {
1023 if (fy
== gd
->hsize
+ gd
->sy
)
1033 for (i
= fy
+ 1; i
< gd
->hsize
+ gd
->sy
; i
++) {
1037 n
= window_copy_search_lr(gd
, sgd
, &px
, i
- 1, first
, gd
->sx
);
1039 window_copy_scroll_to(wp
, px
, i
- 1);
1043 if (!n
&& !wrapped
) {
1054 window_copy_goto_line(struct window_pane
*wp
, const char *linestr
)
1056 struct window_copy_mode_data
*data
= wp
->modedata
;
1060 lineno
= strtonum(linestr
, 0, screen_hsize(data
->backing
), &errstr
);
1065 window_copy_update_selection(wp
);
1066 window_copy_redraw_screen(wp
);
1070 window_copy_write_line(
1071 struct window_pane
*wp
, struct screen_write_ctx
*ctx
, u_int py
)
1073 struct window_copy_mode_data
*data
= wp
->modedata
;
1074 struct screen
*s
= &data
->screen
;
1075 struct options
*oo
= &wp
->window
->options
;
1076 struct grid_cell gc
;
1078 size_t last
, xoff
= 0, size
= 0;
1080 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1081 colour_set_fg(&gc
, options_get_number(oo
, "mode-fg"));
1082 colour_set_bg(&gc
, options_get_number(oo
, "mode-bg"));
1083 gc
.attr
|= options_get_number(oo
, "mode-attr");
1085 last
= screen_size_y(s
) - 1;
1087 size
= xsnprintf(hdr
, sizeof hdr
,
1088 "[%u/%u]", data
->oy
, screen_hsize(data
->backing
));
1089 if (size
> screen_size_x(s
))
1090 size
= screen_size_x(s
);
1091 screen_write_cursormove(ctx
, screen_size_x(s
) - size
, 0);
1092 screen_write_puts(ctx
, &gc
, "%s", hdr
);
1093 } else if (py
== last
&& data
->inputtype
!= WINDOW_COPY_OFF
) {
1094 if (data
->inputtype
== WINDOW_COPY_NUMERICPREFIX
) {
1095 xoff
= size
= xsnprintf(hdr
, sizeof hdr
,
1096 "Repeat: %u", data
->numprefix
);
1098 xoff
= size
= xsnprintf(hdr
, sizeof hdr
,
1099 "%s: %s", data
->inputprompt
, data
->inputstr
);
1101 screen_write_cursormove(ctx
, 0, last
);
1102 screen_write_puts(ctx
, &gc
, "%s", hdr
);
1106 screen_write_cursormove(ctx
, xoff
, py
);
1107 screen_write_copy(ctx
, data
->backing
, xoff
,
1108 (screen_hsize(data
->backing
) - data
->oy
) + py
,
1109 screen_size_x(s
) - size
, 1);
1111 if (py
== data
->cy
&& data
->cx
== screen_size_x(s
)) {
1112 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1113 screen_write_cursormove(ctx
, screen_size_x(s
) - 1, py
);
1114 screen_write_putc(ctx
, &gc
, '$');
1119 window_copy_write_lines(
1120 struct window_pane
*wp
, struct screen_write_ctx
*ctx
, u_int py
, u_int ny
)
1124 for (yy
= py
; yy
< py
+ ny
; yy
++)
1125 window_copy_write_line(wp
, ctx
, py
);
1129 window_copy_redraw_lines(struct window_pane
*wp
, u_int py
, u_int ny
)
1131 struct window_copy_mode_data
*data
= wp
->modedata
;
1132 struct screen_write_ctx ctx
;
1135 screen_write_start(&ctx
, wp
, NULL
);
1136 for (i
= py
; i
< py
+ ny
; i
++)
1137 window_copy_write_line(wp
, &ctx
, i
);
1138 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1139 screen_write_stop(&ctx
);
1143 window_copy_redraw_screen(struct window_pane
*wp
)
1145 struct window_copy_mode_data
*data
= wp
->modedata
;
1147 window_copy_redraw_lines(wp
, 0, screen_size_y(&data
->screen
));
1151 window_copy_update_cursor(struct window_pane
*wp
, u_int cx
, u_int cy
)
1153 struct window_copy_mode_data
*data
= wp
->modedata
;
1154 struct screen
*s
= &data
->screen
;
1155 struct screen_write_ctx ctx
;
1156 u_int old_cx
, old_cy
;
1158 old_cx
= data
->cx
; old_cy
= data
->cy
;
1159 data
->cx
= cx
; data
->cy
= cy
;
1160 if (old_cx
== screen_size_x(s
))
1161 window_copy_redraw_lines(wp
, old_cy
, 1);
1162 if (data
->cx
== screen_size_x(s
))
1163 window_copy_redraw_lines(wp
, data
->cy
, 1);
1165 screen_write_start(&ctx
, wp
, NULL
);
1166 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1167 screen_write_stop(&ctx
);
1172 window_copy_start_selection(struct window_pane
*wp
)
1174 struct window_copy_mode_data
*data
= wp
->modedata
;
1175 struct screen
*s
= &data
->screen
;
1177 data
->selx
= data
->cx
;
1178 data
->sely
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1181 window_copy_update_selection(wp
);
1185 window_copy_update_selection(struct window_pane
*wp
)
1187 struct window_copy_mode_data
*data
= wp
->modedata
;
1188 struct screen
*s
= &data
->screen
;
1189 struct options
*oo
= &wp
->window
->options
;
1190 struct grid_cell gc
;
1191 u_int sx
, sy
, ty
, cy
;
1197 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1198 colour_set_fg(&gc
, options_get_number(oo
, "mode-fg"));
1199 colour_set_bg(&gc
, options_get_number(oo
, "mode-bg"));
1200 gc
.attr
|= options_get_number(oo
, "mode-attr");
1202 /* Find top of screen. */
1203 ty
= screen_hsize(data
->backing
) - data
->oy
;
1205 /* Adjust the selection. */
1208 if (sy
< ty
) { /* above screen */
1209 if (!data
->rectflag
)
1212 } else if (sy
> ty
+ screen_size_y(s
) - 1) { /* below screen */
1213 if (!data
->rectflag
)
1214 sx
= screen_size_x(s
) - 1;
1215 sy
= screen_size_y(s
) - 1;
1218 sy
= screen_hsize(s
) + sy
;
1220 screen_set_selection(s
,
1221 sx
, sy
, data
->cx
, screen_hsize(s
) + data
->cy
, data
->rectflag
, &gc
);
1223 if (data
->rectflag
) {
1225 * Can't rely on the caller to redraw the right lines for
1226 * rectangle selection - find the highest line and the number
1227 * of lines, and redraw just past that in both directions
1231 window_copy_redraw_lines(wp
, sy
, cy
- sy
+ 1);
1233 window_copy_redraw_lines(wp
, cy
, sy
- cy
+ 1);
1240 window_copy_copy_selection(struct window_pane
*wp
)
1242 struct window_copy_mode_data
*data
= wp
->modedata
;
1243 struct screen
*s
= &data
->screen
;
1246 u_int i
, xx
, yy
, sx
, sy
, ex
, ey
, limit
;
1247 u_int firstsx
, lastex
, restex
, restsx
;
1259 * The selection extends from selx,sely to (adjusted) cx,cy on
1263 /* Find start and end. */
1265 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1266 if (yy
< data
->sely
|| (yy
== data
->sely
&& xx
< data
->selx
)) {
1268 ex
= data
->selx
; ey
= data
->sely
;
1270 sx
= data
->selx
; sy
= data
->sely
;
1274 /* Trim ex to end of line. */
1275 xx
= window_copy_find_length(wp
, ey
);
1280 * Deal with rectangle-copy if necessary; four situations: start of
1281 * first line (firstsx), end of last line (lastex), start (restsx) and
1282 * end (restex) of all other lines.
1284 xx
= screen_size_x(s
);
1287 * Behave according to mode-keys. If it is emacs, copy like emacs,
1288 * keeping the top-left-most character, and dropping the
1289 * bottom-right-most, regardless of copy direction. If it is vi, also
1290 * keep bottom-right-most character.
1292 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
1293 if (data
->rectflag
) {
1295 * Need to ignore the column with the cursor in it, which for
1296 * rectangular copy means knowing which side the cursor is on.
1298 if (data
->selx
< data
->cx
) {
1299 /* Selection start is on the left. */
1300 if (keys
== MODEKEY_EMACS
) {
1305 lastex
= data
->cx
+ 1;
1306 restex
= data
->cx
+ 1;
1308 firstsx
= data
->selx
;
1309 restsx
= data
->selx
;
1311 /* Cursor is on the left. */
1312 lastex
= data
->selx
+ 1;
1313 restex
= data
->selx
+ 1;
1318 if (keys
== MODEKEY_EMACS
)
1327 /* Copy the lines. */
1329 window_copy_copy_line(wp
, &buf
, &off
, sy
, firstsx
, lastex
);
1331 window_copy_copy_line(wp
, &buf
, &off
, sy
, firstsx
, restex
);
1333 for (i
= sy
+ 1; i
< ey
; i
++) {
1334 window_copy_copy_line(
1335 wp
, &buf
, &off
, i
, restsx
, restex
);
1338 window_copy_copy_line(wp
, &buf
, &off
, ey
, restsx
, lastex
);
1341 /* Don't bother if no data. */
1346 off
--; /* remove final \n */
1348 /* Add the buffer to the stack. */
1349 limit
= options_get_number(&global_options
, "buffer-limit");
1350 paste_add(&global_buffers
, buf
, off
, limit
);
1354 window_copy_copy_line(struct window_pane
*wp
,
1355 char **buf
, size_t *off
, u_int sy
, u_int sx
, u_int ex
)
1357 struct window_copy_mode_data
*data
= wp
->modedata
;
1358 struct grid
*gd
= data
->backing
->grid
;
1359 const struct grid_cell
*gc
;
1360 const struct grid_utf8
*gu
;
1361 struct grid_line
*gl
;
1362 u_int i
, xx
, wrapped
= 0;
1369 * Work out if the line was wrapped at the screen edge and all of it is
1372 gl
= &gd
->linedata
[sy
];
1373 if (gl
->flags
& GRID_LINE_WRAPPED
&& gl
->cellsize
<= gd
->sx
)
1376 /* If the line was wrapped, don't strip spaces (use the full length). */
1380 xx
= window_copy_find_length(wp
, sy
);
1387 for (i
= sx
; i
< ex
; i
++) {
1388 gc
= grid_peek_cell(gd
, i
, sy
);
1389 if (gc
->flags
& GRID_FLAG_PADDING
)
1391 if (!(gc
->flags
& GRID_FLAG_UTF8
)) {
1392 *buf
= xrealloc(*buf
, 1, (*off
) + 1);
1393 (*buf
)[(*off
)++] = gc
->data
;
1395 gu
= grid_peek_utf8(gd
, i
, sy
);
1396 size
= grid_utf8_size(gu
);
1397 *buf
= xrealloc(*buf
, 1, (*off
) + size
);
1398 *off
+= grid_utf8_copy(gu
, *buf
+ *off
, size
);
1403 /* Only add a newline if the line wasn't wrapped. */
1404 if (!wrapped
|| ex
!= xx
) {
1405 *buf
= xrealloc(*buf
, 1, (*off
) + 1);
1406 (*buf
)[(*off
)++] = '\n';
1411 window_copy_clear_selection(struct window_pane
*wp
)
1413 struct window_copy_mode_data
*data
= wp
->modedata
;
1416 screen_clear_selection(&data
->screen
);
1418 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1419 px
= window_copy_find_length(wp
, py
);
1421 window_copy_update_cursor(wp
, px
, data
->cy
);
1425 window_copy_in_set(struct window_pane
*wp
, u_int px
, u_int py
, const char *set
)
1427 struct window_copy_mode_data
*data
= wp
->modedata
;
1428 const struct grid_cell
*gc
;
1430 gc
= grid_peek_cell(data
->backing
->grid
, px
, py
);
1431 if (gc
->flags
& (GRID_FLAG_PADDING
|GRID_FLAG_UTF8
))
1433 if (gc
->data
== 0x00 || gc
->data
== 0x7f)
1435 return (strchr(set
, gc
->data
) != NULL
);
1439 window_copy_find_length(struct window_pane
*wp
, u_int py
)
1441 struct window_copy_mode_data
*data
= wp
->modedata
;
1442 struct screen
*s
= data
->backing
;
1443 const struct grid_cell
*gc
;
1447 * If the pane has been resized, its grid can contain old overlong
1448 * lines. grid_peek_cell does not allow accessing cells beyond the
1449 * width of the grid, and screen_write_copy treats them as spaces, so
1450 * ignore them here too.
1452 px
= s
->grid
->linedata
[py
].cellsize
;
1453 if (px
> screen_size_x(s
))
1454 px
= screen_size_x(s
);
1456 gc
= grid_peek_cell(s
->grid
, px
- 1, py
);
1457 if (gc
->flags
& GRID_FLAG_UTF8
)
1459 if (gc
->data
!= ' ')
1467 window_copy_cursor_start_of_line(struct window_pane
*wp
)
1469 struct window_copy_mode_data
*data
= wp
->modedata
;
1470 struct screen
*back_s
= data
->backing
;
1471 struct grid
*gd
= back_s
->grid
;
1474 if (data
->cx
== 0) {
1475 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1476 while (py
> 0 && gd
->linedata
[py
-1].flags
& GRID_LINE_WRAPPED
) {
1477 window_copy_cursor_up(wp
, 0);
1478 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1481 window_copy_update_cursor(wp
, 0, data
->cy
);
1482 if (window_copy_update_selection(wp
))
1483 window_copy_redraw_lines(wp
, data
->cy
, 1);
1487 window_copy_cursor_back_to_indentation(struct window_pane
*wp
)
1489 struct window_copy_mode_data
*data
= wp
->modedata
;
1491 const struct grid_cell
*gc
;
1494 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1495 xx
= window_copy_find_length(wp
, py
);
1498 gc
= grid_peek_cell(data
->backing
->grid
, px
, py
);
1499 if (gc
->flags
& GRID_FLAG_UTF8
)
1501 if (gc
->data
!= ' ')
1506 window_copy_update_cursor(wp
, px
, data
->cy
);
1507 if (window_copy_update_selection(wp
))
1508 window_copy_redraw_lines(wp
, data
->cy
, 1);
1512 window_copy_cursor_end_of_line(struct window_pane
*wp
)
1514 struct window_copy_mode_data
*data
= wp
->modedata
;
1515 struct screen
*back_s
= data
->backing
;
1516 struct grid
*gd
= back_s
->grid
;
1519 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1520 px
= window_copy_find_length(wp
, py
);
1522 if (data
->cx
== px
) {
1523 if (data
->screen
.sel
.flag
&& data
->rectflag
)
1524 px
= screen_size_x(back_s
);
1525 if (gd
->linedata
[py
].flags
& GRID_LINE_WRAPPED
) {
1526 while (py
< gd
->sy
+ gd
->hsize
&&
1527 gd
->linedata
[py
].flags
& GRID_LINE_WRAPPED
) {
1528 window_copy_cursor_down(wp
, 0);
1529 py
= screen_hsize(back_s
)
1530 + data
->cy
- data
->oy
;
1532 px
= window_copy_find_length(wp
, py
);
1535 window_copy_update_cursor(wp
, px
, data
->cy
);
1537 if (window_copy_update_selection(wp
))
1538 window_copy_redraw_lines(wp
, data
->cy
, 1);
1542 window_copy_cursor_left(struct window_pane
*wp
)
1544 struct window_copy_mode_data
*data
= wp
->modedata
;
1546 if (data
->cx
== 0) {
1547 window_copy_cursor_up(wp
, 0);
1548 window_copy_cursor_end_of_line(wp
);
1550 window_copy_update_cursor(wp
, data
->cx
- 1, data
->cy
);
1551 if (window_copy_update_selection(wp
))
1552 window_copy_redraw_lines(wp
, data
->cy
, 1);
1557 window_copy_cursor_right(struct window_pane
*wp
)
1559 struct window_copy_mode_data
*data
= wp
->modedata
;
1562 if (data
->screen
.sel
.flag
&& data
->rectflag
)
1563 px
= screen_size_x(&data
->screen
);
1565 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1566 px
= window_copy_find_length(wp
, py
);
1569 if (data
->cx
>= px
) {
1570 window_copy_cursor_start_of_line(wp
);
1571 window_copy_cursor_down(wp
, 0);
1573 window_copy_update_cursor(wp
, data
->cx
+ 1, data
->cy
);
1574 if (window_copy_update_selection(wp
))
1575 window_copy_redraw_lines(wp
, data
->cy
, 1);
1580 window_copy_cursor_up(struct window_pane
*wp
, int scroll_only
)
1582 struct window_copy_mode_data
*data
= wp
->modedata
;
1583 struct screen
*s
= &data
->screen
;
1584 u_int ox
, oy
, px
, py
;
1586 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1587 ox
= window_copy_find_length(wp
, oy
);
1589 data
->lastcx
= data
->cx
;
1593 data
->cx
= data
->lastcx
;
1594 if (scroll_only
|| data
->cy
== 0) {
1595 window_copy_scroll_down(wp
, 1);
1597 if (data
->cy
== screen_size_y(s
) - 1)
1598 window_copy_redraw_lines(wp
, data
->cy
, 1);
1600 window_copy_redraw_lines(wp
, data
->cy
, 2);
1603 window_copy_update_cursor(wp
, data
->cx
, data
->cy
- 1);
1604 if (window_copy_update_selection(wp
)) {
1605 if (data
->cy
== screen_size_y(s
) - 1)
1606 window_copy_redraw_lines(wp
, data
->cy
, 1);
1608 window_copy_redraw_lines(wp
, data
->cy
, 2);
1612 if (!data
->screen
.sel
.flag
|| !data
->rectflag
) {
1613 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1614 px
= window_copy_find_length(wp
, py
);
1615 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
1617 window_copy_cursor_end_of_line(wp
);
1622 window_copy_cursor_down(struct window_pane
*wp
, int scroll_only
)
1624 struct window_copy_mode_data
*data
= wp
->modedata
;
1625 struct screen
*s
= &data
->screen
;
1626 u_int ox
, oy
, px
, py
;
1628 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1629 ox
= window_copy_find_length(wp
, oy
);
1631 data
->lastcx
= data
->cx
;
1635 data
->cx
= data
->lastcx
;
1636 if (scroll_only
|| data
->cy
== screen_size_y(s
) - 1) {
1637 window_copy_scroll_up(wp
, 1);
1638 if (scroll_only
&& data
->cy
> 0)
1639 window_copy_redraw_lines(wp
, data
->cy
- 1, 2);
1641 window_copy_update_cursor(wp
, data
->cx
, data
->cy
+ 1);
1642 if (window_copy_update_selection(wp
))
1643 window_copy_redraw_lines(wp
, data
->cy
- 1, 2);
1646 if (!data
->screen
.sel
.flag
|| !data
->rectflag
) {
1647 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1648 px
= window_copy_find_length(wp
, py
);
1649 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
1651 window_copy_cursor_end_of_line(wp
);
1656 window_copy_cursor_jump(struct window_pane
*wp
)
1658 struct window_copy_mode_data
*data
= wp
->modedata
;
1659 struct screen
*back_s
= data
->backing
;
1660 const struct grid_cell
*gc
;
1664 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1665 xx
= window_copy_find_length(wp
, py
);
1668 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1669 if ((gc
->flags
& (GRID_FLAG_PADDING
|GRID_FLAG_UTF8
)) == 0
1670 && gc
->data
== data
->jumpchar
) {
1672 window_copy_update_cursor(wp
, px
, data
->cy
);
1673 if (window_copy_update_selection(wp
))
1674 window_copy_redraw_lines(wp
, data
->cy
, 1);
1682 window_copy_cursor_jump_back(struct window_pane
*wp
)
1684 struct window_copy_mode_data
*data
= wp
->modedata
;
1685 struct screen
*back_s
= data
->backing
;
1686 const struct grid_cell
*gc
;
1690 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1696 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1697 if ((gc
->flags
& (GRID_FLAG_PADDING
|GRID_FLAG_UTF8
)) == 0
1698 && gc
->data
== data
->jumpchar
) {
1700 window_copy_update_cursor(wp
, px
, data
->cy
);
1701 if (window_copy_update_selection(wp
))
1702 window_copy_redraw_lines(wp
, data
->cy
, 1);
1712 window_copy_cursor_next_word(struct window_pane
*wp
, const char *separators
)
1714 struct window_copy_mode_data
*data
= wp
->modedata
;
1715 struct screen
*back_s
= data
->backing
;
1716 u_int px
, py
, xx
, yy
;
1720 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1721 xx
= window_copy_find_length(wp
, py
);
1722 yy
= screen_hsize(back_s
) + screen_size_y(back_s
) - 1;
1725 * First skip past any nonword characters and then any word characters.
1727 * expected is initially set to 0 for the former and then 1 for the
1732 window_copy_in_set(wp
, px
, py
, separators
) == expected
) {
1733 /* Move down if we're past the end of the line. */
1737 window_copy_cursor_down(wp
, 0);
1740 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1741 xx
= window_copy_find_length(wp
, py
);
1745 expected
= !expected
;
1746 } while (expected
== 1);
1748 window_copy_update_cursor(wp
, px
, data
->cy
);
1749 if (window_copy_update_selection(wp
))
1750 window_copy_redraw_lines(wp
, data
->cy
, 1);
1754 window_copy_cursor_next_word_end(struct window_pane
*wp
, const char *separators
)
1756 struct window_copy_mode_data
*data
= wp
->modedata
;
1757 struct screen
*back_s
= data
->backing
;
1758 u_int px
, py
, xx
, yy
;
1762 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1763 xx
= window_copy_find_length(wp
, py
);
1764 yy
= screen_hsize(back_s
) + screen_size_y(back_s
) - 1;
1767 * First skip past any word characters, then any nonword characters.
1769 * expected is initially set to 1 for the former and then 0 for the
1774 window_copy_in_set(wp
, px
, py
, separators
) == expected
) {
1775 /* Move down if we're past the end of the line. */
1779 window_copy_cursor_down(wp
, 0);
1782 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1783 xx
= window_copy_find_length(wp
, py
);
1787 expected
= !expected
;
1788 } while (expected
== 0);
1790 window_copy_update_cursor(wp
, px
, data
->cy
);
1791 if (window_copy_update_selection(wp
))
1792 window_copy_redraw_lines(wp
, data
->cy
, 1);
1795 /* Move to the previous place where a word begins. */
1797 window_copy_cursor_previous_word(struct window_pane
*wp
, const char *separators
)
1799 struct window_copy_mode_data
*data
= wp
->modedata
;
1803 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1805 /* Move back to the previous word character. */
1809 if (!window_copy_in_set(wp
, px
, py
, separators
))
1812 if (data
->cy
== 0 &&
1813 (screen_hsize(data
->backing
) == 0 ||
1814 data
->oy
>= screen_hsize(data
->backing
) - 1))
1816 window_copy_cursor_up(wp
, 0);
1818 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1819 px
= window_copy_find_length(wp
, py
);
1823 /* Move back to the beginning of this word. */
1824 while (px
> 0 && !window_copy_in_set(wp
, px
- 1, py
, separators
))
1828 window_copy_update_cursor(wp
, px
, data
->cy
);
1829 if (window_copy_update_selection(wp
))
1830 window_copy_redraw_lines(wp
, data
->cy
, 1);
1834 window_copy_scroll_up(struct window_pane
*wp
, u_int ny
)
1836 struct window_copy_mode_data
*data
= wp
->modedata
;
1837 struct screen
*s
= &data
->screen
;
1838 struct screen_write_ctx ctx
;
1846 screen_write_start(&ctx
, wp
, NULL
);
1847 screen_write_cursormove(&ctx
, 0, 0);
1848 screen_write_deleteline(&ctx
, ny
);
1849 window_copy_write_lines(wp
, &ctx
, screen_size_y(s
) - ny
, ny
);
1850 window_copy_write_line(wp
, &ctx
, 0);
1851 if (screen_size_y(s
) > 1)
1852 window_copy_write_line(wp
, &ctx
, 1);
1853 if (screen_size_y(s
) > 3)
1854 window_copy_write_line(wp
, &ctx
, screen_size_y(s
) - 2);
1855 if (s
->sel
.flag
&& screen_size_y(s
) > ny
) {
1856 window_copy_update_selection(wp
);
1857 window_copy_write_line(wp
, &ctx
, screen_size_y(s
) - ny
- 1);
1859 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1860 window_copy_update_selection(wp
);
1861 screen_write_stop(&ctx
);
1865 window_copy_scroll_down(struct window_pane
*wp
, u_int ny
)
1867 struct window_copy_mode_data
*data
= wp
->modedata
;
1868 struct screen
*s
= &data
->screen
;
1869 struct screen_write_ctx ctx
;
1871 if (ny
> screen_hsize(data
->backing
))
1874 if (data
->oy
> screen_hsize(data
->backing
) - ny
)
1875 ny
= screen_hsize(data
->backing
) - data
->oy
;
1880 screen_write_start(&ctx
, wp
, NULL
);
1881 screen_write_cursormove(&ctx
, 0, 0);
1882 screen_write_insertline(&ctx
, ny
);
1883 window_copy_write_lines(wp
, &ctx
, 0, ny
);
1884 if (s
->sel
.flag
&& screen_size_y(s
) > ny
) {
1885 window_copy_update_selection(wp
);
1886 window_copy_write_line(wp
, &ctx
, ny
);
1887 } else if (ny
== 1) /* nuke position */
1888 window_copy_write_line(wp
, &ctx
, 1);
1889 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1890 window_copy_update_selection(wp
);
1891 screen_write_stop(&ctx
);
1895 window_copy_rectangle_toggle(struct window_pane
*wp
)
1897 struct window_copy_mode_data
*data
= wp
->modedata
;
1900 data
->rectflag
= !data
->rectflag
;
1902 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1903 px
= window_copy_find_length(wp
, py
);
1905 window_copy_update_cursor(wp
, px
, data
->cy
);
1907 window_copy_update_selection(wp
);
1908 window_copy_redraw_screen(wp
);