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
*, int);
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_jump_to(struct window_pane
*);
71 void window_copy_cursor_jump_to_back(struct window_pane
*);
72 void window_copy_cursor_next_word(struct window_pane
*, const char *);
73 void window_copy_cursor_next_word_end(struct window_pane
*, const char *);
74 void window_copy_cursor_previous_word(struct window_pane
*, const char *);
75 void window_copy_scroll_up(struct window_pane
*, u_int
);
76 void window_copy_scroll_down(struct window_pane
*, u_int
);
77 void window_copy_rectangle_toggle(struct window_pane
*);
79 const struct window_mode window_copy_mode
= {
88 enum window_copy_input_type
{
90 WINDOW_COPY_NUMERICPREFIX
,
92 WINDOW_COPY_SEARCHDOWN
,
93 WINDOW_COPY_JUMPFORWARD
,
95 WINDOW_COPY_JUMPTOFORWARD
,
96 WINDOW_COPY_JUMPTOBACK
,
101 * Copy-mode's visible screen (the "screen" field) is filled from one of
102 * two sources: the original contents of the pane (used when we
103 * actually enter via the "copy-mode" command, to copy the contents of
104 * the current pane), or else a series of lines containing the output
105 * from an output-writing tmux command (such as any of the "show-*" or
106 * "list-*" commands).
108 * In either case, the full content of the copy-mode grid is pointed at
109 * by the "backing" field, and is copied into "screen" as needed (that
110 * is, when scrolling occurs). When copy-mode is backed by a pane,
111 * backing points directly at that pane's screen structure (&wp->base);
112 * when backed by a list of output-lines from a command, it points at
113 * a newly-allocated screen structure (which is deallocated when the
116 struct window_copy_mode_data
{
117 struct screen screen
;
119 struct screen
*backing
;
120 int backing_written
; /* backing display has started */
122 struct mode_key_data mdata
;
129 u_int rectflag
; /* are we in rectangle copy mode? */
134 u_int lastcx
; /* position in last line with content */
135 u_int lastsx
; /* size of last line with content */
137 enum window_copy_input_type inputtype
;
138 const char *inputprompt
;
143 enum window_copy_input_type searchtype
;
146 enum window_copy_input_type jumptype
;
151 window_copy_init(struct window_pane
*wp
)
153 struct window_copy_mode_data
*data
;
157 wp
->modedata
= data
= xmalloc(sizeof *data
);
165 data
->backing_written
= 0;
169 data
->inputtype
= WINDOW_COPY_OFF
;
170 data
->inputprompt
= NULL
;
171 data
->inputstr
= xstrdup("");
172 data
->numprefix
= -1;
174 data
->searchtype
= WINDOW_COPY_OFF
;
175 data
->searchstr
= NULL
;
178 bufferevent_disable(wp
->event
, EV_READ
|EV_WRITE
);
180 data
->jumptype
= WINDOW_COPY_OFF
;
181 data
->jumpchar
= '\0';
184 screen_init(s
, screen_size_x(&wp
->base
), screen_size_y(&wp
->base
), 0);
185 if (options_get_number(&wp
->window
->options
, "mode-mouse"))
186 s
->mode
|= MODE_MOUSE_STANDARD
;
188 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
189 if (keys
== MODEKEY_EMACS
)
190 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_copy
);
192 mode_key_init(&data
->mdata
, &mode_key_tree_vi_copy
);
194 data
->backing
= NULL
;
200 window_copy_init_from_pane(struct window_pane
*wp
)
202 struct window_copy_mode_data
*data
= wp
->modedata
;
203 struct screen
*s
= &data
->screen
;
204 struct screen_write_ctx ctx
;
207 if (wp
->mode
!= &window_copy_mode
)
208 fatalx("not in copy mode");
210 data
->backing
= &wp
->base
;
211 data
->cx
= data
->backing
->cx
;
212 data
->cy
= data
->backing
->cy
;
217 screen_write_start(&ctx
, NULL
, s
);
218 for (i
= 0; i
< screen_size_y(s
); i
++)
219 window_copy_write_line(wp
, &ctx
, i
);
220 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
221 screen_write_stop(&ctx
);
225 window_copy_init_for_output(struct window_pane
*wp
)
227 struct window_copy_mode_data
*data
= wp
->modedata
;
229 data
->backing
= xmalloc(sizeof *data
->backing
);
230 screen_init(data
->backing
, screen_size_x(&wp
->base
),
231 screen_size_y(&wp
->base
), UINT_MAX
);
232 data
->backing
->mode
&= ~MODE_WRAP
;
236 window_copy_free(struct window_pane
*wp
)
238 struct window_copy_mode_data
*data
= wp
->modedata
;
241 bufferevent_enable(wp
->event
, EV_READ
|EV_WRITE
);
243 if (data
->searchstr
!= NULL
)
244 xfree(data
->searchstr
);
245 xfree(data
->inputstr
);
247 if (data
->backing
!= &wp
->base
) {
248 screen_free(data
->backing
);
249 xfree(data
->backing
);
251 screen_free(&data
->screen
);
257 window_copy_add(struct window_pane
*wp
, const char *fmt
, ...)
262 window_copy_vadd(wp
, fmt
, ap
);
267 window_copy_vadd(struct window_pane
*wp
, const char *fmt
, va_list ap
)
269 struct window_copy_mode_data
*data
= wp
->modedata
;
270 struct screen
*backing
= data
->backing
;
271 struct screen_write_ctx back_ctx
, ctx
;
276 if (backing
== &wp
->base
)
279 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
280 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
282 old_hsize
= screen_hsize(data
->backing
);
283 screen_write_start(&back_ctx
, NULL
, backing
);
284 if (data
->backing_written
) {
286 * On the second or later line, do a CRLF before writing
287 * (so it's on a new line).
289 screen_write_carriagereturn(&back_ctx
);
290 screen_write_linefeed(&back_ctx
, 0);
292 data
->backing_written
= 1;
293 screen_write_vnputs(&back_ctx
, 0, &gc
, utf8flag
, fmt
, ap
);
294 screen_write_stop(&back_ctx
);
296 data
->oy
+= screen_hsize(data
->backing
) - old_hsize
;
298 screen_write_start(&ctx
, wp
, &data
->screen
);
301 * If the history has changed, draw the top line.
302 * (If there's any history at all, it has changed.)
304 if (screen_hsize(data
->backing
))
305 window_copy_redraw_lines(wp
, 0, 1);
307 /* Write the line, if it's visible. */
308 if (backing
->cy
+ data
->oy
< screen_size_y(backing
))
309 window_copy_redraw_lines(wp
, backing
->cy
, 1);
311 screen_write_stop(&ctx
);
315 window_copy_pageup(struct window_pane
*wp
)
317 struct window_copy_mode_data
*data
= wp
->modedata
;
318 struct screen
*s
= &data
->screen
;
322 if (screen_size_y(s
) > 2)
323 n
= screen_size_y(s
) - 2;
324 if (data
->oy
+ n
> screen_hsize(data
->backing
))
325 data
->oy
= screen_hsize(data
->backing
);
328 window_copy_update_selection(wp
);
329 window_copy_redraw_screen(wp
);
333 window_copy_resize(struct window_pane
*wp
, u_int sx
, u_int sy
)
335 struct window_copy_mode_data
*data
= wp
->modedata
;
336 struct screen
*s
= &data
->screen
;
337 struct screen_write_ctx ctx
;
339 screen_resize(s
, sx
, sy
);
340 if (data
->backing
!= &wp
->base
)
341 screen_resize(data
->backing
, sx
, sy
);
343 if (data
->cy
> sy
- 1)
347 if (data
->oy
> screen_hsize(data
->backing
))
348 data
->oy
= screen_hsize(data
->backing
);
350 window_copy_clear_selection(wp
);
352 screen_write_start(&ctx
, NULL
, s
);
353 window_copy_write_lines(wp
, &ctx
, 0, screen_size_y(s
) - 1);
354 screen_write_stop(&ctx
);
356 window_copy_redraw_screen(wp
);
360 window_copy_key(struct window_pane
*wp
, struct session
*sess
, int key
)
362 const char *word_separators
;
363 struct window_copy_mode_data
*data
= wp
->modedata
;
364 struct screen
*s
= &data
->screen
;
367 enum mode_key_cmd cmd
;
369 np
= data
->numprefix
;
373 if (data
->inputtype
== WINDOW_COPY_JUMPFORWARD
||
374 data
->inputtype
== WINDOW_COPY_JUMPBACK
||
375 data
->inputtype
== WINDOW_COPY_JUMPTOFORWARD
||
376 data
->inputtype
== WINDOW_COPY_JUMPTOBACK
) {
377 /* Ignore keys with modifiers. */
378 if ((key
& KEYC_MASK_MOD
) == 0) {
379 data
->jumpchar
= key
;
380 if (data
->inputtype
== WINDOW_COPY_JUMPFORWARD
) {
381 for (; np
!= 0; np
--)
382 window_copy_cursor_jump(wp
);
383 } else if (data
->inputtype
== WINDOW_COPY_JUMPBACK
) {
384 for (; np
!= 0; np
--)
385 window_copy_cursor_jump_back(wp
);
386 } else if (data
->inputtype
== WINDOW_COPY_JUMPTOFORWARD
) {
387 for (; np
!= 0; np
--)
388 window_copy_cursor_jump_to(wp
);
389 } else if (data
->inputtype
== WINDOW_COPY_JUMPTOBACK
) {
390 for (; np
!= 0; np
--)
391 window_copy_cursor_jump_to_back(wp
);
394 data
->jumptype
= data
->inputtype
;
395 data
->inputtype
= WINDOW_COPY_OFF
;
396 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
398 } else if (data
->inputtype
== WINDOW_COPY_NUMERICPREFIX
) {
399 if (window_copy_key_numeric_prefix(wp
, key
) == 0)
401 data
->inputtype
= WINDOW_COPY_OFF
;
402 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
403 } else if (data
->inputtype
!= WINDOW_COPY_OFF
) {
404 if (window_copy_key_input(wp
, key
) != 0)
409 cmd
= mode_key_lookup(&data
->mdata
, key
);
411 case MODEKEYCOPY_CANCEL
:
412 window_pane_reset_mode(wp
);
414 case MODEKEYCOPY_LEFT
:
415 for (; np
!= 0; np
--)
416 window_copy_cursor_left(wp
);
418 case MODEKEYCOPY_RIGHT
:
419 for (; np
!= 0; np
--)
420 window_copy_cursor_right(wp
);
423 for (; np
!= 0; np
--)
424 window_copy_cursor_up(wp
, 0);
426 case MODEKEYCOPY_DOWN
:
427 for (; np
!= 0; np
--)
428 window_copy_cursor_down(wp
, 0);
430 case MODEKEYCOPY_SCROLLUP
:
431 for (; np
!= 0; np
--)
432 window_copy_cursor_up(wp
, 1);
434 case MODEKEYCOPY_SCROLLDOWN
:
435 for (; np
!= 0; np
--)
436 window_copy_cursor_down(wp
, 1);
438 case MODEKEYCOPY_PREVIOUSPAGE
:
439 for (; np
!= 0; np
--)
440 window_copy_pageup(wp
);
442 case MODEKEYCOPY_NEXTPAGE
:
444 if (screen_size_y(s
) > 2)
445 n
= screen_size_y(s
) - 2;
446 for (; np
!= 0; np
--) {
452 window_copy_update_selection(wp
);
453 window_copy_redraw_screen(wp
);
455 case MODEKEYCOPY_HALFPAGEUP
:
456 n
= screen_size_y(s
) / 2;
457 for (; np
!= 0; np
--) {
458 if (data
->oy
+ n
> screen_hsize(data
->backing
))
459 data
->oy
= screen_hsize(data
->backing
);
463 window_copy_update_selection(wp
);
464 window_copy_redraw_screen(wp
);
466 case MODEKEYCOPY_HALFPAGEDOWN
:
467 n
= screen_size_y(s
) / 2;
468 for (; np
!= 0; np
--) {
474 window_copy_update_selection(wp
);
475 window_copy_redraw_screen(wp
);
477 case MODEKEYCOPY_TOPLINE
:
480 window_copy_update_selection(wp
);
481 window_copy_redraw_screen(wp
);
483 case MODEKEYCOPY_MIDDLELINE
:
485 data
->cy
= (screen_size_y(s
) - 1) / 2;
486 window_copy_update_selection(wp
);
487 window_copy_redraw_screen(wp
);
489 case MODEKEYCOPY_BOTTOMLINE
:
491 data
->cy
= screen_size_y(s
) - 1;
492 window_copy_update_selection(wp
);
493 window_copy_redraw_screen(wp
);
495 case MODEKEYCOPY_HISTORYTOP
:
498 data
->oy
= screen_hsize(data
->backing
);
499 window_copy_update_selection(wp
);
500 window_copy_redraw_screen(wp
);
502 case MODEKEYCOPY_HISTORYBOTTOM
:
504 data
->cy
= screen_size_y(s
) - 1;
506 window_copy_update_selection(wp
);
507 window_copy_redraw_screen(wp
);
509 case MODEKEYCOPY_STARTSELECTION
:
510 window_copy_start_selection(wp
);
511 window_copy_redraw_screen(wp
);
513 case MODEKEYCOPY_COPYLINE
:
514 case MODEKEYCOPY_SELECTLINE
:
515 window_copy_cursor_start_of_line(wp
);
517 case MODEKEYCOPY_COPYENDOFLINE
:
518 window_copy_start_selection(wp
);
520 window_copy_cursor_down(wp
, 0);
521 window_copy_cursor_end_of_line(wp
);
522 window_copy_redraw_screen(wp
);
524 /* If a copy command then copy the selection and exit. */
526 (cmd
== MODEKEYCOPY_COPYLINE
||
527 cmd
== MODEKEYCOPY_COPYENDOFLINE
)) {
528 window_copy_copy_selection(wp
, -1);
529 window_pane_reset_mode(wp
);
533 case MODEKEYCOPY_CLEARSELECTION
:
534 window_copy_clear_selection(wp
);
535 window_copy_redraw_screen(wp
);
537 case MODEKEYCOPY_COPYSELECTION
:
539 window_copy_copy_selection(wp
, data
->numprefix
);
540 window_pane_reset_mode(wp
);
544 case MODEKEYCOPY_STARTOFLINE
:
545 window_copy_cursor_start_of_line(wp
);
547 case MODEKEYCOPY_BACKTOINDENTATION
:
548 window_copy_cursor_back_to_indentation(wp
);
550 case MODEKEYCOPY_ENDOFLINE
:
551 window_copy_cursor_end_of_line(wp
);
553 case MODEKEYCOPY_NEXTSPACE
:
554 for (; np
!= 0; np
--)
555 window_copy_cursor_next_word(wp
, " ");
557 case MODEKEYCOPY_NEXTSPACEEND
:
558 for (; np
!= 0; np
--)
559 window_copy_cursor_next_word_end(wp
, " ");
561 case MODEKEYCOPY_NEXTWORD
:
563 options_get_string(&sess
->options
, "word-separators");
564 for (; np
!= 0; np
--)
565 window_copy_cursor_next_word(wp
, word_separators
);
567 case MODEKEYCOPY_NEXTWORDEND
:
569 options_get_string(&sess
->options
, "word-separators");
570 for (; np
!= 0; np
--)
571 window_copy_cursor_next_word_end(wp
, word_separators
);
573 case MODEKEYCOPY_PREVIOUSSPACE
:
574 for (; np
!= 0; np
--)
575 window_copy_cursor_previous_word(wp
, " ");
577 case MODEKEYCOPY_PREVIOUSWORD
:
579 options_get_string(&sess
->options
, "word-separators");
580 for (; np
!= 0; np
--)
581 window_copy_cursor_previous_word(wp
, word_separators
);
583 case MODEKEYCOPY_JUMP
:
584 data
->inputtype
= WINDOW_COPY_JUMPFORWARD
;
585 data
->inputprompt
= "Jump Forward";
586 *data
->inputstr
= '\0';
587 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
588 return; /* skip numprefix reset */
589 case MODEKEYCOPY_JUMPAGAIN
:
590 if (data
->jumptype
== WINDOW_COPY_JUMPFORWARD
) {
591 for (; np
!= 0; np
--)
592 window_copy_cursor_jump(wp
);
593 } else if (data
->jumptype
== WINDOW_COPY_JUMPBACK
) {
594 for (; np
!= 0; np
--)
595 window_copy_cursor_jump_back(wp
);
596 } else if (data
->jumptype
== WINDOW_COPY_JUMPTOFORWARD
) {
597 for (; np
!= 0; np
--)
598 window_copy_cursor_jump_to(wp
);
599 } else if (data
->jumptype
== WINDOW_COPY_JUMPTOBACK
) {
600 for (; np
!= 0; np
--)
601 window_copy_cursor_jump_to_back(wp
);
604 case MODEKEYCOPY_JUMPREVERSE
:
605 if (data
->jumptype
== WINDOW_COPY_JUMPFORWARD
) {
606 for (; np
!= 0; np
--)
607 window_copy_cursor_jump_back(wp
);
608 } else if (data
->jumptype
== WINDOW_COPY_JUMPBACK
) {
609 for (; np
!= 0; np
--)
610 window_copy_cursor_jump(wp
);
611 } else if (data
->jumptype
== WINDOW_COPY_JUMPTOFORWARD
) {
612 for (; np
!= 0; np
--)
613 window_copy_cursor_jump_to_back(wp
);
614 } else if (data
->jumptype
== WINDOW_COPY_JUMPTOBACK
) {
615 for (; np
!= 0; np
--)
616 window_copy_cursor_jump_to(wp
);
619 case MODEKEYCOPY_JUMPBACK
:
620 data
->inputtype
= WINDOW_COPY_JUMPBACK
;
621 data
->inputprompt
= "Jump Back";
622 *data
->inputstr
= '\0';
623 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
624 return; /* skip numprefix reset */
625 case MODEKEYCOPY_JUMPTO
:
626 data
->inputtype
= WINDOW_COPY_JUMPTOFORWARD
;
627 data
->inputprompt
= "Jump To";
628 *data
->inputstr
= '\0';
629 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
630 return; /* skip numprefix reset */
631 case MODEKEYCOPY_JUMPTOBACK
:
632 data
->inputtype
= WINDOW_COPY_JUMPTOBACK
;
633 data
->inputprompt
= "Jump To Back";
634 *data
->inputstr
= '\0';
635 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
636 return; /* skip numprefix reset */
637 case MODEKEYCOPY_SEARCHUP
:
638 data
->inputtype
= WINDOW_COPY_SEARCHUP
;
639 data
->inputprompt
= "Search Up";
641 case MODEKEYCOPY_SEARCHDOWN
:
642 data
->inputtype
= WINDOW_COPY_SEARCHDOWN
;
643 data
->inputprompt
= "Search Down";
645 case MODEKEYCOPY_SEARCHAGAIN
:
646 case MODEKEYCOPY_SEARCHREVERSE
:
647 switch (data
->searchtype
) {
648 case WINDOW_COPY_OFF
:
649 case WINDOW_COPY_GOTOLINE
:
650 case WINDOW_COPY_JUMPFORWARD
:
651 case WINDOW_COPY_JUMPBACK
:
652 case WINDOW_COPY_JUMPTOFORWARD
:
653 case WINDOW_COPY_JUMPTOBACK
:
654 case WINDOW_COPY_NUMERICPREFIX
:
656 case WINDOW_COPY_SEARCHUP
:
657 if (cmd
== MODEKEYCOPY_SEARCHAGAIN
) {
658 for (; np
!= 0; np
--) {
659 window_copy_search_up(
660 wp
, data
->searchstr
);
663 for (; np
!= 0; np
--) {
664 window_copy_search_down(
665 wp
, data
->searchstr
);
669 case WINDOW_COPY_SEARCHDOWN
:
670 if (cmd
== MODEKEYCOPY_SEARCHAGAIN
) {
671 for (; np
!= 0; np
--) {
672 window_copy_search_down(
673 wp
, data
->searchstr
);
676 for (; np
!= 0; np
--) {
677 window_copy_search_up(
678 wp
, data
->searchstr
);
684 case MODEKEYCOPY_GOTOLINE
:
685 data
->inputtype
= WINDOW_COPY_GOTOLINE
;
686 data
->inputprompt
= "Goto Line";
687 *data
->inputstr
= '\0';
689 case MODEKEYCOPY_STARTNUMBERPREFIX
:
690 key
&= KEYC_MASK_KEY
;
691 if (key
>= '0' && key
<= '9') {
692 data
->inputtype
= WINDOW_COPY_NUMERICPREFIX
;
694 window_copy_key_numeric_prefix(wp
, key
);
698 case MODEKEYCOPY_RECTANGLETOGGLE
:
699 window_copy_rectangle_toggle(wp
);
705 data
->numprefix
= -1;
709 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
710 if (keys
== MODEKEY_EMACS
)
711 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_edit
);
713 mode_key_init(&data
->mdata
, &mode_key_tree_vi_edit
);
715 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
719 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
720 if (keys
== MODEKEY_EMACS
)
721 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_copy
);
723 mode_key_init(&data
->mdata
, &mode_key_tree_vi_copy
);
725 data
->inputtype
= WINDOW_COPY_OFF
;
726 data
->inputprompt
= NULL
;
728 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
732 window_copy_key_input(struct window_pane
*wp
, int key
)
734 struct window_copy_mode_data
*data
= wp
->modedata
;
735 struct screen
*s
= &data
->screen
;
739 switch (mode_key_lookup(&data
->mdata
, key
)) {
740 case MODEKEYEDIT_CANCEL
:
741 data
->numprefix
= -1;
743 case MODEKEYEDIT_BACKSPACE
:
744 inputlen
= strlen(data
->inputstr
);
746 data
->inputstr
[inputlen
- 1] = '\0';
748 case MODEKEYEDIT_DELETELINE
:
749 *data
->inputstr
= '\0';
751 case MODEKEYEDIT_ENTER
:
752 np
= data
->numprefix
;
756 switch (data
->inputtype
) {
757 case WINDOW_COPY_OFF
:
758 case WINDOW_COPY_JUMPFORWARD
:
759 case WINDOW_COPY_JUMPBACK
:
760 case WINDOW_COPY_JUMPTOFORWARD
:
761 case WINDOW_COPY_JUMPTOBACK
:
762 case WINDOW_COPY_NUMERICPREFIX
:
764 case WINDOW_COPY_SEARCHUP
:
765 for (; np
!= 0; np
--)
766 window_copy_search_up(wp
, data
->inputstr
);
767 data
->searchtype
= data
->inputtype
;
768 data
->searchstr
= xstrdup(data
->inputstr
);
770 case WINDOW_COPY_SEARCHDOWN
:
771 for (; np
!= 0; np
--)
772 window_copy_search_down(wp
, data
->inputstr
);
773 data
->searchtype
= data
->inputtype
;
774 data
->searchstr
= xstrdup(data
->inputstr
);
776 case WINDOW_COPY_GOTOLINE
:
777 window_copy_goto_line(wp
, data
->inputstr
);
778 *data
->inputstr
= '\0';
781 data
->numprefix
= -1;
784 if (key
< 32 || key
> 126)
786 inputlen
= strlen(data
->inputstr
) + 2;
788 data
->inputstr
= xrealloc(data
->inputstr
, 1, inputlen
);
789 data
->inputstr
[inputlen
- 2] = key
;
790 data
->inputstr
[inputlen
- 1] = '\0';
796 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
801 window_copy_key_numeric_prefix(struct window_pane
*wp
, int key
)
803 struct window_copy_mode_data
*data
= wp
->modedata
;
804 struct screen
*s
= &data
->screen
;
806 key
&= KEYC_MASK_KEY
;
807 if (key
< '0' || key
> '9')
810 if (data
->numprefix
>= 100) /* no more than three digits */
812 data
->numprefix
= data
->numprefix
* 10 + key
- '0';
814 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
821 struct window_pane
*wp
, struct session
*sess
, struct mouse_event
*m
)
823 struct window_copy_mode_data
*data
= wp
->modedata
;
824 struct screen
*s
= &data
->screen
;
827 if (m
->x
>= screen_size_x(s
))
829 if (m
->y
>= screen_size_y(s
))
832 /* If mouse wheel (buttons 4 and 5), scroll. */
833 if ((m
->b
& MOUSE_45
)) {
834 if ((m
->b
& MOUSE_BUTTON
) == MOUSE_1
) {
835 for (i
= 0; i
< 5; i
++)
836 window_copy_cursor_up(wp
, 0);
837 } else if ((m
->b
& MOUSE_BUTTON
) == MOUSE_2
) {
838 for (i
= 0; i
< 5; i
++)
839 window_copy_cursor_down(wp
, 0);
847 * If already reading motion, move the cursor while buttons are still
848 * pressed, or stop the selection on their release.
850 if (s
->mode
& MODE_MOUSE_BUTTON
) {
851 if ((m
->b
& MOUSE_BUTTON
) != MOUSE_UP
) {
852 window_copy_update_cursor(wp
, m
->x
, m
->y
);
853 if (window_copy_update_selection(wp
))
854 window_copy_redraw_screen(wp
);
860 /* Otherwise if other buttons pressed, start selection and motion. */
861 if ((m
->b
& MOUSE_BUTTON
) != MOUSE_UP
) {
862 s
->mode
&= ~MODE_MOUSE_STANDARD
;
863 s
->mode
|= MODE_MOUSE_BUTTON
;
865 window_copy_update_cursor(wp
, m
->x
, m
->y
);
866 window_copy_start_selection(wp
);
867 window_copy_redraw_screen(wp
);
873 s
->mode
&= ~MODE_MOUSE_BUTTON
;
874 s
->mode
|= MODE_MOUSE_STANDARD
;
876 window_copy_copy_selection(wp
, -1);
877 window_pane_reset_mode(wp
);
882 window_copy_scroll_to(struct window_pane
*wp
, u_int px
, u_int py
)
884 struct window_copy_mode_data
*data
= wp
->modedata
;
885 struct grid
*gd
= data
->backing
->grid
;
894 } else if (py
> gd
->hsize
+ gd
->sy
- gap
) {
896 data
->cy
= py
- gd
->hsize
;
898 offset
= py
+ gap
- gd
->sy
;
899 data
->cy
= py
- offset
;
901 data
->oy
= gd
->hsize
- offset
;
903 window_copy_update_selection(wp
);
904 window_copy_redraw_screen(wp
);
908 window_copy_search_compare(
909 struct grid
*gd
, u_int px
, u_int py
, struct grid
*sgd
, u_int spx
)
911 const struct grid_cell
*gc
, *sgc
;
912 const struct grid_utf8
*gu
, *sgu
;
914 gc
= grid_peek_cell(gd
, px
, py
);
915 sgc
= grid_peek_cell(sgd
, spx
, 0);
917 if ((gc
->flags
& GRID_FLAG_UTF8
) != (sgc
->flags
& GRID_FLAG_UTF8
))
920 if (gc
->flags
& GRID_FLAG_UTF8
) {
921 gu
= grid_peek_utf8(gd
, px
, py
);
922 sgu
= grid_peek_utf8(sgd
, spx
, 0);
923 if (grid_utf8_compare(gu
, sgu
))
926 if (gc
->data
== sgc
->data
)
933 window_copy_search_lr(struct grid
*gd
,
934 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
)
938 for (ax
= first
; ax
< last
; ax
++) {
939 if (ax
+ sgd
->sx
>= gd
->sx
)
941 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
943 if (!window_copy_search_compare(gd
, px
, py
, sgd
, bx
))
955 window_copy_search_rl(struct grid
*gd
,
956 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
)
960 for (ax
= last
+ 1; ax
> first
; ax
--) {
961 if (gd
->sx
- (ax
- 1) < sgd
->sx
)
963 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
965 if (!window_copy_search_compare(gd
, px
, py
, sgd
, bx
))
977 window_copy_search_up(struct window_pane
*wp
, const char *searchstr
)
979 struct window_copy_mode_data
*data
= wp
->modedata
;
980 struct screen
*s
= data
->backing
, ss
;
981 struct screen_write_ctx ctx
;
982 struct grid
*gd
= s
->grid
, *sgd
;
985 u_int i
, last
, fx
, fy
, px
;
986 int utf8flag
, n
, wrapped
, wrapflag
;
988 if (*searchstr
== '\0')
990 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
991 wrapflag
= options_get_number(&wp
->window
->options
, "wrap-search");
992 searchlen
= screen_write_strlen(utf8flag
, "%s", searchstr
);
994 screen_init(&ss
, searchlen
, 1, 0);
995 screen_write_start(&ctx
, NULL
, &ss
);
996 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
997 screen_write_nputs(&ctx
, -1, &gc
, utf8flag
, "%s", searchstr
);
998 screen_write_stop(&ctx
);
1001 fy
= gd
->hsize
- data
->oy
+ data
->cy
;
1014 for (i
= fy
+ 1; i
> 0; i
--) {
1015 last
= screen_size_x(s
);
1018 n
= window_copy_search_rl(gd
, sgd
, &px
, i
- 1, 0, last
);
1020 window_copy_scroll_to(wp
, px
, i
- 1);
1024 if (wrapflag
&& !n
&& !wrapped
) {
1026 fy
= gd
->hsize
+ gd
->sy
- 1;
1035 window_copy_search_down(struct window_pane
*wp
, const char *searchstr
)
1037 struct window_copy_mode_data
*data
= wp
->modedata
;
1038 struct screen
*s
= data
->backing
, ss
;
1039 struct screen_write_ctx ctx
;
1040 struct grid
*gd
= s
->grid
, *sgd
;
1041 struct grid_cell gc
;
1043 u_int i
, first
, fx
, fy
, px
;
1044 int utf8flag
, n
, wrapped
, wrapflag
;
1046 if (*searchstr
== '\0')
1048 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
1049 wrapflag
= options_get_number(&wp
->window
->options
, "wrap-search");
1050 searchlen
= screen_write_strlen(utf8flag
, "%s", searchstr
);
1052 screen_init(&ss
, searchlen
, 1, 0);
1053 screen_write_start(&ctx
, NULL
, &ss
);
1054 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1055 screen_write_nputs(&ctx
, -1, &gc
, utf8flag
, "%s", searchstr
);
1056 screen_write_stop(&ctx
);
1059 fy
= gd
->hsize
- data
->oy
+ data
->cy
;
1061 if (fx
== gd
->sx
- 1) {
1062 if (fy
== gd
->hsize
+ gd
->sy
)
1072 for (i
= fy
+ 1; i
< gd
->hsize
+ gd
->sy
; i
++) {
1076 n
= window_copy_search_lr(gd
, sgd
, &px
, i
- 1, first
, gd
->sx
);
1078 window_copy_scroll_to(wp
, px
, i
- 1);
1082 if (wrapflag
&& !n
&& !wrapped
) {
1093 window_copy_goto_line(struct window_pane
*wp
, const char *linestr
)
1095 struct window_copy_mode_data
*data
= wp
->modedata
;
1099 lineno
= strtonum(linestr
, 0, screen_hsize(data
->backing
), &errstr
);
1104 window_copy_update_selection(wp
);
1105 window_copy_redraw_screen(wp
);
1109 window_copy_write_line(
1110 struct window_pane
*wp
, struct screen_write_ctx
*ctx
, u_int py
)
1112 struct window_copy_mode_data
*data
= wp
->modedata
;
1113 struct screen
*s
= &data
->screen
;
1114 struct options
*oo
= &wp
->window
->options
;
1115 struct grid_cell gc
;
1117 size_t last
, xoff
= 0, size
= 0;
1119 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1120 colour_set_fg(&gc
, options_get_number(oo
, "mode-fg"));
1121 colour_set_bg(&gc
, options_get_number(oo
, "mode-bg"));
1122 gc
.attr
|= options_get_number(oo
, "mode-attr");
1124 last
= screen_size_y(s
) - 1;
1126 size
= xsnprintf(hdr
, sizeof hdr
,
1127 "[%u/%u]", data
->oy
, screen_hsize(data
->backing
));
1128 if (size
> screen_size_x(s
))
1129 size
= screen_size_x(s
);
1130 screen_write_cursormove(ctx
, screen_size_x(s
) - size
, 0);
1131 screen_write_puts(ctx
, &gc
, "%s", hdr
);
1132 } else if (py
== last
&& data
->inputtype
!= WINDOW_COPY_OFF
) {
1133 if (data
->inputtype
== WINDOW_COPY_NUMERICPREFIX
) {
1134 xoff
= size
= xsnprintf(hdr
, sizeof hdr
,
1135 "Repeat: %u", data
->numprefix
);
1137 xoff
= size
= xsnprintf(hdr
, sizeof hdr
,
1138 "%s: %s", data
->inputprompt
, data
->inputstr
);
1140 screen_write_cursormove(ctx
, 0, last
);
1141 screen_write_puts(ctx
, &gc
, "%s", hdr
);
1145 screen_write_cursormove(ctx
, xoff
, py
);
1146 screen_write_copy(ctx
, data
->backing
, xoff
,
1147 (screen_hsize(data
->backing
) - data
->oy
) + py
,
1148 screen_size_x(s
) - size
, 1);
1150 if (py
== data
->cy
&& data
->cx
== screen_size_x(s
)) {
1151 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1152 screen_write_cursormove(ctx
, screen_size_x(s
) - 1, py
);
1153 screen_write_putc(ctx
, &gc
, '$');
1158 window_copy_write_lines(
1159 struct window_pane
*wp
, struct screen_write_ctx
*ctx
, u_int py
, u_int ny
)
1163 for (yy
= py
; yy
< py
+ ny
; yy
++)
1164 window_copy_write_line(wp
, ctx
, py
);
1168 window_copy_redraw_lines(struct window_pane
*wp
, u_int py
, u_int ny
)
1170 struct window_copy_mode_data
*data
= wp
->modedata
;
1171 struct screen_write_ctx ctx
;
1174 screen_write_start(&ctx
, wp
, NULL
);
1175 for (i
= py
; i
< py
+ ny
; i
++)
1176 window_copy_write_line(wp
, &ctx
, i
);
1177 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1178 screen_write_stop(&ctx
);
1182 window_copy_redraw_screen(struct window_pane
*wp
)
1184 struct window_copy_mode_data
*data
= wp
->modedata
;
1186 window_copy_redraw_lines(wp
, 0, screen_size_y(&data
->screen
));
1190 window_copy_update_cursor(struct window_pane
*wp
, u_int cx
, u_int cy
)
1192 struct window_copy_mode_data
*data
= wp
->modedata
;
1193 struct screen
*s
= &data
->screen
;
1194 struct screen_write_ctx ctx
;
1195 u_int old_cx
, old_cy
;
1197 old_cx
= data
->cx
; old_cy
= data
->cy
;
1198 data
->cx
= cx
; data
->cy
= cy
;
1199 if (old_cx
== screen_size_x(s
))
1200 window_copy_redraw_lines(wp
, old_cy
, 1);
1201 if (data
->cx
== screen_size_x(s
))
1202 window_copy_redraw_lines(wp
, data
->cy
, 1);
1204 screen_write_start(&ctx
, wp
, NULL
);
1205 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1206 screen_write_stop(&ctx
);
1211 window_copy_start_selection(struct window_pane
*wp
)
1213 struct window_copy_mode_data
*data
= wp
->modedata
;
1214 struct screen
*s
= &data
->screen
;
1216 data
->selx
= data
->cx
;
1217 data
->sely
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1220 window_copy_update_selection(wp
);
1224 window_copy_update_selection(struct window_pane
*wp
)
1226 struct window_copy_mode_data
*data
= wp
->modedata
;
1227 struct screen
*s
= &data
->screen
;
1228 struct options
*oo
= &wp
->window
->options
;
1229 struct grid_cell gc
;
1230 u_int sx
, sy
, ty
, cy
;
1236 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1237 colour_set_fg(&gc
, options_get_number(oo
, "mode-fg"));
1238 colour_set_bg(&gc
, options_get_number(oo
, "mode-bg"));
1239 gc
.attr
|= options_get_number(oo
, "mode-attr");
1241 /* Find top of screen. */
1242 ty
= screen_hsize(data
->backing
) - data
->oy
;
1244 /* Adjust the selection. */
1247 if (sy
< ty
) { /* above screen */
1248 if (!data
->rectflag
)
1251 } else if (sy
> ty
+ screen_size_y(s
) - 1) { /* below screen */
1252 if (!data
->rectflag
)
1253 sx
= screen_size_x(s
) - 1;
1254 sy
= screen_size_y(s
) - 1;
1257 sy
= screen_hsize(s
) + sy
;
1259 screen_set_selection(s
,
1260 sx
, sy
, data
->cx
, screen_hsize(s
) + data
->cy
, data
->rectflag
, &gc
);
1262 if (data
->rectflag
) {
1264 * Can't rely on the caller to redraw the right lines for
1265 * rectangle selection - find the highest line and the number
1266 * of lines, and redraw just past that in both directions
1270 window_copy_redraw_lines(wp
, sy
, cy
- sy
+ 1);
1272 window_copy_redraw_lines(wp
, cy
, sy
- cy
+ 1);
1279 window_copy_copy_selection(struct window_pane
*wp
, int idx
)
1281 struct window_copy_mode_data
*data
= wp
->modedata
;
1282 struct screen
*s
= &data
->screen
;
1285 u_int i
, xx
, yy
, sx
, sy
, ex
, ey
, limit
;
1286 u_int firstsx
, lastex
, restex
, restsx
;
1298 * The selection extends from selx,sely to (adjusted) cx,cy on
1302 /* Find start and end. */
1304 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1305 if (yy
< data
->sely
|| (yy
== data
->sely
&& xx
< data
->selx
)) {
1307 ex
= data
->selx
; ey
= data
->sely
;
1309 sx
= data
->selx
; sy
= data
->sely
;
1313 /* Trim ex to end of line. */
1314 xx
= window_copy_find_length(wp
, ey
);
1319 * Deal with rectangle-copy if necessary; four situations: start of
1320 * first line (firstsx), end of last line (lastex), start (restsx) and
1321 * end (restex) of all other lines.
1323 xx
= screen_size_x(s
);
1326 * Behave according to mode-keys. If it is emacs, copy like emacs,
1327 * keeping the top-left-most character, and dropping the
1328 * bottom-right-most, regardless of copy direction. If it is vi, also
1329 * keep bottom-right-most character.
1331 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
1332 if (data
->rectflag
) {
1334 * Need to ignore the column with the cursor in it, which for
1335 * rectangular copy means knowing which side the cursor is on.
1337 if (data
->selx
< data
->cx
) {
1338 /* Selection start is on the left. */
1339 if (keys
== MODEKEY_EMACS
) {
1344 lastex
= data
->cx
+ 1;
1345 restex
= data
->cx
+ 1;
1347 firstsx
= data
->selx
;
1348 restsx
= data
->selx
;
1350 /* Cursor is on the left. */
1351 lastex
= data
->selx
+ 1;
1352 restex
= data
->selx
+ 1;
1357 if (keys
== MODEKEY_EMACS
)
1366 /* Copy the lines. */
1368 window_copy_copy_line(wp
, &buf
, &off
, sy
, firstsx
, lastex
);
1370 window_copy_copy_line(wp
, &buf
, &off
, sy
, firstsx
, restex
);
1372 for (i
= sy
+ 1; i
< ey
; i
++) {
1373 window_copy_copy_line(
1374 wp
, &buf
, &off
, i
, restsx
, restex
);
1377 window_copy_copy_line(wp
, &buf
, &off
, ey
, restsx
, lastex
);
1380 /* Don't bother if no data. */
1385 off
--; /* remove final \n */
1387 if (options_get_number(&global_options
, "set-clipboard"))
1388 screen_write_setselection(&wp
->ictx
.ctx
, buf
, off
);
1390 /* Add the buffer to the stack. */
1392 limit
= options_get_number(&global_options
, "buffer-limit");
1393 paste_add(&global_buffers
, buf
, off
, limit
);
1395 paste_replace(&global_buffers
, idx
, buf
, off
);
1399 window_copy_copy_line(struct window_pane
*wp
,
1400 char **buf
, size_t *off
, u_int sy
, u_int sx
, u_int ex
)
1402 struct window_copy_mode_data
*data
= wp
->modedata
;
1403 struct grid
*gd
= data
->backing
->grid
;
1404 const struct grid_cell
*gc
;
1405 const struct grid_utf8
*gu
;
1406 struct grid_line
*gl
;
1407 u_int i
, xx
, wrapped
= 0;
1414 * Work out if the line was wrapped at the screen edge and all of it is
1417 gl
= &gd
->linedata
[sy
];
1418 if (gl
->flags
& GRID_LINE_WRAPPED
&& gl
->cellsize
<= gd
->sx
)
1421 /* If the line was wrapped, don't strip spaces (use the full length). */
1425 xx
= window_copy_find_length(wp
, sy
);
1432 for (i
= sx
; i
< ex
; i
++) {
1433 gc
= grid_peek_cell(gd
, i
, sy
);
1434 if (gc
->flags
& GRID_FLAG_PADDING
)
1436 if (!(gc
->flags
& GRID_FLAG_UTF8
)) {
1437 *buf
= xrealloc(*buf
, 1, (*off
) + 1);
1438 (*buf
)[(*off
)++] = gc
->data
;
1440 gu
= grid_peek_utf8(gd
, i
, sy
);
1441 size
= grid_utf8_size(gu
);
1442 *buf
= xrealloc(*buf
, 1, (*off
) + size
);
1443 *off
+= grid_utf8_copy(gu
, *buf
+ *off
, size
);
1448 /* Only add a newline if the line wasn't wrapped. */
1449 if (!wrapped
|| ex
!= xx
) {
1450 *buf
= xrealloc(*buf
, 1, (*off
) + 1);
1451 (*buf
)[(*off
)++] = '\n';
1456 window_copy_clear_selection(struct window_pane
*wp
)
1458 struct window_copy_mode_data
*data
= wp
->modedata
;
1461 screen_clear_selection(&data
->screen
);
1463 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1464 px
= window_copy_find_length(wp
, py
);
1466 window_copy_update_cursor(wp
, px
, data
->cy
);
1470 window_copy_in_set(struct window_pane
*wp
, u_int px
, u_int py
, const char *set
)
1472 struct window_copy_mode_data
*data
= wp
->modedata
;
1473 const struct grid_cell
*gc
;
1475 gc
= grid_peek_cell(data
->backing
->grid
, px
, py
);
1476 if (gc
->flags
& (GRID_FLAG_PADDING
|GRID_FLAG_UTF8
))
1478 if (gc
->data
== 0x00 || gc
->data
== 0x7f)
1480 return (strchr(set
, gc
->data
) != NULL
);
1484 window_copy_find_length(struct window_pane
*wp
, u_int py
)
1486 struct window_copy_mode_data
*data
= wp
->modedata
;
1487 struct screen
*s
= data
->backing
;
1488 const struct grid_cell
*gc
;
1492 * If the pane has been resized, its grid can contain old overlong
1493 * lines. grid_peek_cell does not allow accessing cells beyond the
1494 * width of the grid, and screen_write_copy treats them as spaces, so
1495 * ignore them here too.
1497 px
= s
->grid
->linedata
[py
].cellsize
;
1498 if (px
> screen_size_x(s
))
1499 px
= screen_size_x(s
);
1501 gc
= grid_peek_cell(s
->grid
, px
- 1, py
);
1502 if (gc
->flags
& GRID_FLAG_UTF8
)
1504 if (gc
->data
!= ' ')
1512 window_copy_cursor_start_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 if (data
->cx
== 0) {
1520 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1521 while (py
> 0 && gd
->linedata
[py
-1].flags
& GRID_LINE_WRAPPED
) {
1522 window_copy_cursor_up(wp
, 0);
1523 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1526 window_copy_update_cursor(wp
, 0, data
->cy
);
1527 if (window_copy_update_selection(wp
))
1528 window_copy_redraw_lines(wp
, data
->cy
, 1);
1532 window_copy_cursor_back_to_indentation(struct window_pane
*wp
)
1534 struct window_copy_mode_data
*data
= wp
->modedata
;
1536 const struct grid_cell
*gc
;
1539 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1540 xx
= window_copy_find_length(wp
, py
);
1543 gc
= grid_peek_cell(data
->backing
->grid
, px
, py
);
1544 if (gc
->flags
& GRID_FLAG_UTF8
)
1546 if (gc
->data
!= ' ')
1551 window_copy_update_cursor(wp
, px
, data
->cy
);
1552 if (window_copy_update_selection(wp
))
1553 window_copy_redraw_lines(wp
, data
->cy
, 1);
1557 window_copy_cursor_end_of_line(struct window_pane
*wp
)
1559 struct window_copy_mode_data
*data
= wp
->modedata
;
1560 struct screen
*back_s
= data
->backing
;
1561 struct grid
*gd
= back_s
->grid
;
1564 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1565 px
= window_copy_find_length(wp
, py
);
1567 if (data
->cx
== px
) {
1568 if (data
->screen
.sel
.flag
&& data
->rectflag
)
1569 px
= screen_size_x(back_s
);
1570 if (gd
->linedata
[py
].flags
& GRID_LINE_WRAPPED
) {
1571 while (py
< gd
->sy
+ gd
->hsize
&&
1572 gd
->linedata
[py
].flags
& GRID_LINE_WRAPPED
) {
1573 window_copy_cursor_down(wp
, 0);
1574 py
= screen_hsize(back_s
)
1575 + data
->cy
- data
->oy
;
1577 px
= window_copy_find_length(wp
, py
);
1580 window_copy_update_cursor(wp
, px
, data
->cy
);
1582 if (window_copy_update_selection(wp
))
1583 window_copy_redraw_lines(wp
, data
->cy
, 1);
1587 window_copy_cursor_left(struct window_pane
*wp
)
1589 struct window_copy_mode_data
*data
= wp
->modedata
;
1591 if (data
->cx
== 0) {
1592 window_copy_cursor_up(wp
, 0);
1593 window_copy_cursor_end_of_line(wp
);
1595 window_copy_update_cursor(wp
, data
->cx
- 1, data
->cy
);
1596 if (window_copy_update_selection(wp
))
1597 window_copy_redraw_lines(wp
, data
->cy
, 1);
1602 window_copy_cursor_right(struct window_pane
*wp
)
1604 struct window_copy_mode_data
*data
= wp
->modedata
;
1607 if (data
->screen
.sel
.flag
&& data
->rectflag
)
1608 px
= screen_size_x(&data
->screen
);
1610 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1611 px
= window_copy_find_length(wp
, py
);
1614 if (data
->cx
>= px
) {
1615 window_copy_cursor_start_of_line(wp
);
1616 window_copy_cursor_down(wp
, 0);
1618 window_copy_update_cursor(wp
, data
->cx
+ 1, data
->cy
);
1619 if (window_copy_update_selection(wp
))
1620 window_copy_redraw_lines(wp
, data
->cy
, 1);
1625 window_copy_cursor_up(struct window_pane
*wp
, int scroll_only
)
1627 struct window_copy_mode_data
*data
= wp
->modedata
;
1628 struct screen
*s
= &data
->screen
;
1629 u_int ox
, oy
, px
, py
;
1631 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1632 ox
= window_copy_find_length(wp
, oy
);
1633 if (data
->cx
!= ox
) {
1634 data
->lastcx
= data
->cx
;
1638 data
->cx
= data
->lastcx
;
1639 if (scroll_only
|| data
->cy
== 0) {
1640 window_copy_scroll_down(wp
, 1);
1642 if (data
->cy
== screen_size_y(s
) - 1)
1643 window_copy_redraw_lines(wp
, data
->cy
, 1);
1645 window_copy_redraw_lines(wp
, data
->cy
, 2);
1648 window_copy_update_cursor(wp
, data
->cx
, data
->cy
- 1);
1649 if (window_copy_update_selection(wp
)) {
1650 if (data
->cy
== screen_size_y(s
) - 1)
1651 window_copy_redraw_lines(wp
, data
->cy
, 1);
1653 window_copy_redraw_lines(wp
, data
->cy
, 2);
1657 if (!data
->screen
.sel
.flag
|| !data
->rectflag
) {
1658 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1659 px
= window_copy_find_length(wp
, py
);
1660 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
1662 window_copy_cursor_end_of_line(wp
);
1667 window_copy_cursor_down(struct window_pane
*wp
, int scroll_only
)
1669 struct window_copy_mode_data
*data
= wp
->modedata
;
1670 struct screen
*s
= &data
->screen
;
1671 u_int ox
, oy
, px
, py
;
1673 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1674 ox
= window_copy_find_length(wp
, oy
);
1675 if (data
->cx
!= ox
) {
1676 data
->lastcx
= data
->cx
;
1680 data
->cx
= data
->lastcx
;
1681 if (scroll_only
|| data
->cy
== screen_size_y(s
) - 1) {
1682 window_copy_scroll_up(wp
, 1);
1683 if (scroll_only
&& data
->cy
> 0)
1684 window_copy_redraw_lines(wp
, data
->cy
- 1, 2);
1686 window_copy_update_cursor(wp
, data
->cx
, data
->cy
+ 1);
1687 if (window_copy_update_selection(wp
))
1688 window_copy_redraw_lines(wp
, data
->cy
- 1, 2);
1691 if (!data
->screen
.sel
.flag
|| !data
->rectflag
) {
1692 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1693 px
= window_copy_find_length(wp
, py
);
1694 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
1696 window_copy_cursor_end_of_line(wp
);
1701 window_copy_cursor_jump(struct window_pane
*wp
)
1703 struct window_copy_mode_data
*data
= wp
->modedata
;
1704 struct screen
*back_s
= data
->backing
;
1705 const struct grid_cell
*gc
;
1709 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1710 xx
= window_copy_find_length(wp
, py
);
1713 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1714 if ((gc
->flags
& (GRID_FLAG_PADDING
|GRID_FLAG_UTF8
)) == 0
1715 && gc
->data
== data
->jumpchar
) {
1717 window_copy_update_cursor(wp
, px
, data
->cy
);
1718 if (window_copy_update_selection(wp
))
1719 window_copy_redraw_lines(wp
, data
->cy
, 1);
1727 window_copy_cursor_jump_back(struct window_pane
*wp
)
1729 struct window_copy_mode_data
*data
= wp
->modedata
;
1730 struct screen
*back_s
= data
->backing
;
1731 const struct grid_cell
*gc
;
1735 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1741 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1742 if ((gc
->flags
& (GRID_FLAG_PADDING
|GRID_FLAG_UTF8
)) == 0
1743 && gc
->data
== data
->jumpchar
) {
1745 window_copy_update_cursor(wp
, px
, data
->cy
);
1746 if (window_copy_update_selection(wp
))
1747 window_copy_redraw_lines(wp
, data
->cy
, 1);
1757 window_copy_cursor_jump_to(struct window_pane
*wp
)
1759 struct window_copy_mode_data
*data
= wp
->modedata
;
1760 struct screen
*back_s
= data
->backing
;
1761 const struct grid_cell
*gc
;
1765 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1766 xx
= window_copy_find_length(wp
, py
);
1769 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1770 if ((gc
->flags
& (GRID_FLAG_PADDING
|GRID_FLAG_UTF8
)) == 0
1771 && gc
->data
== data
->jumpchar
) {
1773 window_copy_update_cursor(wp
, px
- 1, data
->cy
);
1774 if (window_copy_update_selection(wp
))
1775 window_copy_redraw_lines(wp
, data
->cy
, 1);
1783 window_copy_cursor_jump_to_back(struct window_pane
*wp
)
1785 struct window_copy_mode_data
*data
= wp
->modedata
;
1786 struct screen
*back_s
= data
->backing
;
1787 const struct grid_cell
*gc
;
1791 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1797 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1798 if ((gc
->flags
& (GRID_FLAG_PADDING
|GRID_FLAG_UTF8
)) == 0
1799 && gc
->data
== data
->jumpchar
) {
1801 window_copy_update_cursor(wp
, px
+ 1, data
->cy
);
1802 if (window_copy_update_selection(wp
))
1803 window_copy_redraw_lines(wp
, data
->cy
, 1);
1813 window_copy_cursor_next_word(struct window_pane
*wp
, const char *separators
)
1815 struct window_copy_mode_data
*data
= wp
->modedata
;
1816 struct screen
*back_s
= data
->backing
;
1817 u_int px
, py
, xx
, yy
;
1821 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1822 xx
= window_copy_find_length(wp
, py
);
1823 yy
= screen_hsize(back_s
) + screen_size_y(back_s
) - 1;
1826 * First skip past any nonword characters and then any word characters.
1828 * expected is initially set to 0 for the former and then 1 for the
1833 window_copy_in_set(wp
, px
, py
, separators
) == expected
) {
1834 /* Move down if we're past the end of the line. */
1838 window_copy_cursor_down(wp
, 0);
1841 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1842 xx
= window_copy_find_length(wp
, py
);
1846 expected
= !expected
;
1847 } while (expected
== 1);
1849 window_copy_update_cursor(wp
, px
, data
->cy
);
1850 if (window_copy_update_selection(wp
))
1851 window_copy_redraw_lines(wp
, data
->cy
, 1);
1855 window_copy_cursor_next_word_end(struct window_pane
*wp
, const char *separators
)
1857 struct window_copy_mode_data
*data
= wp
->modedata
;
1858 struct screen
*back_s
= data
->backing
;
1859 u_int px
, py
, xx
, yy
;
1863 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1864 xx
= window_copy_find_length(wp
, py
);
1865 yy
= screen_hsize(back_s
) + screen_size_y(back_s
) - 1;
1868 * First skip past any word characters, then any nonword characters.
1870 * expected is initially set to 1 for the former and then 0 for the
1875 window_copy_in_set(wp
, px
, py
, separators
) == expected
) {
1876 /* Move down if we're past the end of the line. */
1880 window_copy_cursor_down(wp
, 0);
1883 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1884 xx
= window_copy_find_length(wp
, py
);
1888 expected
= !expected
;
1889 } while (expected
== 0);
1891 window_copy_update_cursor(wp
, px
, data
->cy
);
1892 if (window_copy_update_selection(wp
))
1893 window_copy_redraw_lines(wp
, data
->cy
, 1);
1896 /* Move to the previous place where a word begins. */
1898 window_copy_cursor_previous_word(struct window_pane
*wp
, const char *separators
)
1900 struct window_copy_mode_data
*data
= wp
->modedata
;
1904 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1906 /* Move back to the previous word character. */
1910 if (!window_copy_in_set(wp
, px
, py
, separators
))
1913 if (data
->cy
== 0 &&
1914 (screen_hsize(data
->backing
) == 0 ||
1915 data
->oy
>= screen_hsize(data
->backing
) - 1))
1917 window_copy_cursor_up(wp
, 0);
1919 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1920 px
= window_copy_find_length(wp
, py
);
1924 /* Move back to the beginning of this word. */
1925 while (px
> 0 && !window_copy_in_set(wp
, px
- 1, py
, separators
))
1929 window_copy_update_cursor(wp
, px
, data
->cy
);
1930 if (window_copy_update_selection(wp
))
1931 window_copy_redraw_lines(wp
, data
->cy
, 1);
1935 window_copy_scroll_up(struct window_pane
*wp
, u_int ny
)
1937 struct window_copy_mode_data
*data
= wp
->modedata
;
1938 struct screen
*s
= &data
->screen
;
1939 struct screen_write_ctx ctx
;
1947 screen_write_start(&ctx
, wp
, NULL
);
1948 screen_write_cursormove(&ctx
, 0, 0);
1949 screen_write_deleteline(&ctx
, ny
);
1950 window_copy_write_lines(wp
, &ctx
, screen_size_y(s
) - ny
, ny
);
1951 window_copy_write_line(wp
, &ctx
, 0);
1952 if (screen_size_y(s
) > 1)
1953 window_copy_write_line(wp
, &ctx
, 1);
1954 if (screen_size_y(s
) > 3)
1955 window_copy_write_line(wp
, &ctx
, screen_size_y(s
) - 2);
1956 if (s
->sel
.flag
&& screen_size_y(s
) > ny
) {
1957 window_copy_update_selection(wp
);
1958 window_copy_write_line(wp
, &ctx
, screen_size_y(s
) - ny
- 1);
1960 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1961 window_copy_update_selection(wp
);
1962 screen_write_stop(&ctx
);
1966 window_copy_scroll_down(struct window_pane
*wp
, u_int ny
)
1968 struct window_copy_mode_data
*data
= wp
->modedata
;
1969 struct screen
*s
= &data
->screen
;
1970 struct screen_write_ctx ctx
;
1972 if (ny
> screen_hsize(data
->backing
))
1975 if (data
->oy
> screen_hsize(data
->backing
) - ny
)
1976 ny
= screen_hsize(data
->backing
) - data
->oy
;
1981 screen_write_start(&ctx
, wp
, NULL
);
1982 screen_write_cursormove(&ctx
, 0, 0);
1983 screen_write_insertline(&ctx
, ny
);
1984 window_copy_write_lines(wp
, &ctx
, 0, ny
);
1985 if (s
->sel
.flag
&& screen_size_y(s
) > ny
) {
1986 window_copy_update_selection(wp
);
1987 window_copy_write_line(wp
, &ctx
, ny
);
1988 } else if (ny
== 1) /* nuke position */
1989 window_copy_write_line(wp
, &ctx
, 1);
1990 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1991 window_copy_update_selection(wp
);
1992 screen_write_stop(&ctx
);
1996 window_copy_rectangle_toggle(struct window_pane
*wp
)
1998 struct window_copy_mode_data
*data
= wp
->modedata
;
2001 data
->rectflag
= !data
->rectflag
;
2003 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2004 px
= window_copy_find_length(wp
, py
);
2006 window_copy_update_cursor(wp
, px
, data
->cy
);
2008 window_copy_update_selection(wp
);
2009 window_copy_redraw_screen(wp
);