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_get_selection(struct window_pane
*, size_t *);
56 void window_copy_copy_buffer(struct window_pane
*, int, void *, size_t);
57 void window_copy_copy_pipe(struct window_pane
*, int, const char *);
58 void window_copy_copy_selection(struct window_pane
*, int);
59 void window_copy_clear_selection(struct window_pane
*);
60 void window_copy_copy_line(
61 struct window_pane
*, char **, size_t *, u_int
, u_int
, u_int
);
62 int window_copy_in_set(struct window_pane
*, u_int
, u_int
, const char *);
63 u_int
window_copy_find_length(struct window_pane
*, u_int
);
64 void window_copy_cursor_start_of_line(struct window_pane
*);
65 void window_copy_cursor_back_to_indentation(struct window_pane
*);
66 void window_copy_cursor_end_of_line(struct window_pane
*);
67 void window_copy_cursor_left(struct window_pane
*);
68 void window_copy_cursor_right(struct window_pane
*);
69 void window_copy_cursor_up(struct window_pane
*, int);
70 void window_copy_cursor_down(struct window_pane
*, int);
71 void window_copy_cursor_jump(struct window_pane
*);
72 void window_copy_cursor_jump_back(struct window_pane
*);
73 void window_copy_cursor_jump_to(struct window_pane
*);
74 void window_copy_cursor_jump_to_back(struct window_pane
*);
75 void window_copy_cursor_next_word(struct window_pane
*, const char *);
76 void window_copy_cursor_next_word_end(struct window_pane
*, const char *);
77 void window_copy_cursor_previous_word(struct window_pane
*, const char *);
78 void window_copy_scroll_up(struct window_pane
*, u_int
);
79 void window_copy_scroll_down(struct window_pane
*, u_int
);
80 void window_copy_rectangle_toggle(struct window_pane
*);
82 const struct window_mode window_copy_mode
= {
91 enum window_copy_input_type
{
93 WINDOW_COPY_NUMERICPREFIX
,
95 WINDOW_COPY_SEARCHDOWN
,
96 WINDOW_COPY_JUMPFORWARD
,
98 WINDOW_COPY_JUMPTOFORWARD
,
99 WINDOW_COPY_JUMPTOBACK
,
100 WINDOW_COPY_GOTOLINE
,
104 * Copy-mode's visible screen (the "screen" field) is filled from one of
105 * two sources: the original contents of the pane (used when we
106 * actually enter via the "copy-mode" command, to copy the contents of
107 * the current pane), or else a series of lines containing the output
108 * from an output-writing tmux command (such as any of the "show-*" or
109 * "list-*" commands).
111 * In either case, the full content of the copy-mode grid is pointed at
112 * by the "backing" field, and is copied into "screen" as needed (that
113 * is, when scrolling occurs). When copy-mode is backed by a pane,
114 * backing points directly at that pane's screen structure (&wp->base);
115 * when backed by a list of output-lines from a command, it points at
116 * a newly-allocated screen structure (which is deallocated when the
119 struct window_copy_mode_data
{
120 struct screen screen
;
122 struct screen
*backing
;
123 int backing_written
; /* backing display has started */
125 struct mode_key_data mdata
;
132 u_int rectflag
; /* are we in rectangle copy mode? */
137 u_int lastcx
; /* position in last line with content */
138 u_int lastsx
; /* size of last line with content */
140 enum window_copy_input_type inputtype
;
141 const char *inputprompt
;
146 enum window_copy_input_type searchtype
;
149 enum window_copy_input_type jumptype
;
154 window_copy_init(struct window_pane
*wp
)
156 struct window_copy_mode_data
*data
;
160 wp
->modedata
= data
= xmalloc(sizeof *data
);
168 data
->backing_written
= 0;
172 data
->inputtype
= WINDOW_COPY_OFF
;
173 data
->inputprompt
= NULL
;
174 data
->inputstr
= xstrdup("");
175 data
->numprefix
= -1;
177 data
->searchtype
= WINDOW_COPY_OFF
;
178 data
->searchstr
= NULL
;
181 bufferevent_disable(wp
->event
, EV_READ
|EV_WRITE
);
183 data
->jumptype
= WINDOW_COPY_OFF
;
184 data
->jumpchar
= '\0';
187 screen_init(s
, screen_size_x(&wp
->base
), screen_size_y(&wp
->base
), 0);
188 if (options_get_number(&wp
->window
->options
, "mode-mouse"))
189 s
->mode
|= MODE_MOUSE_STANDARD
;
191 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
192 if (keys
== MODEKEY_EMACS
)
193 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_copy
);
195 mode_key_init(&data
->mdata
, &mode_key_tree_vi_copy
);
197 data
->backing
= NULL
;
203 window_copy_init_from_pane(struct window_pane
*wp
)
205 struct window_copy_mode_data
*data
= wp
->modedata
;
206 struct screen
*s
= &data
->screen
;
207 struct screen_write_ctx ctx
;
210 if (wp
->mode
!= &window_copy_mode
)
211 fatalx("not in copy mode");
213 data
->backing
= &wp
->base
;
214 data
->cx
= data
->backing
->cx
;
215 data
->cy
= data
->backing
->cy
;
220 screen_write_start(&ctx
, NULL
, s
);
221 for (i
= 0; i
< screen_size_y(s
); i
++)
222 window_copy_write_line(wp
, &ctx
, i
);
223 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
224 screen_write_stop(&ctx
);
228 window_copy_init_for_output(struct window_pane
*wp
)
230 struct window_copy_mode_data
*data
= wp
->modedata
;
232 data
->backing
= xmalloc(sizeof *data
->backing
);
233 screen_init(data
->backing
, screen_size_x(&wp
->base
),
234 screen_size_y(&wp
->base
), UINT_MAX
);
235 data
->backing
->mode
&= ~MODE_WRAP
;
239 window_copy_free(struct window_pane
*wp
)
241 struct window_copy_mode_data
*data
= wp
->modedata
;
244 bufferevent_enable(wp
->event
, EV_READ
|EV_WRITE
);
246 free(data
->searchstr
);
247 free(data
->inputstr
);
249 if (data
->backing
!= &wp
->base
) {
250 screen_free(data
->backing
);
253 screen_free(&data
->screen
);
259 window_copy_add(struct window_pane
*wp
, const char *fmt
, ...)
264 window_copy_vadd(wp
, fmt
, ap
);
269 window_copy_vadd(struct window_pane
*wp
, const char *fmt
, va_list ap
)
271 struct window_copy_mode_data
*data
= wp
->modedata
;
272 struct screen
*backing
= data
->backing
;
273 struct screen_write_ctx back_ctx
, ctx
;
278 if (backing
== &wp
->base
)
281 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
282 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
284 old_hsize
= screen_hsize(data
->backing
);
285 screen_write_start(&back_ctx
, NULL
, backing
);
286 if (data
->backing_written
) {
288 * On the second or later line, do a CRLF before writing
289 * (so it's on a new line).
291 screen_write_carriagereturn(&back_ctx
);
292 screen_write_linefeed(&back_ctx
, 0);
294 data
->backing_written
= 1;
295 screen_write_vnputs(&back_ctx
, 0, &gc
, utf8flag
, fmt
, ap
);
296 screen_write_stop(&back_ctx
);
298 data
->oy
+= screen_hsize(data
->backing
) - old_hsize
;
300 screen_write_start(&ctx
, wp
, &data
->screen
);
303 * If the history has changed, draw the top line.
304 * (If there's any history at all, it has changed.)
306 if (screen_hsize(data
->backing
))
307 window_copy_redraw_lines(wp
, 0, 1);
309 /* Write the line, if it's visible. */
310 if (backing
->cy
+ data
->oy
< screen_size_y(backing
))
311 window_copy_redraw_lines(wp
, backing
->cy
, 1);
313 screen_write_stop(&ctx
);
317 window_copy_pageup(struct window_pane
*wp
)
319 struct window_copy_mode_data
*data
= wp
->modedata
;
320 struct screen
*s
= &data
->screen
;
324 if (screen_size_y(s
) > 2)
325 n
= screen_size_y(s
) - 2;
326 if (data
->oy
+ n
> screen_hsize(data
->backing
))
327 data
->oy
= screen_hsize(data
->backing
);
330 window_copy_update_selection(wp
);
331 window_copy_redraw_screen(wp
);
335 window_copy_resize(struct window_pane
*wp
, u_int sx
, u_int sy
)
337 struct window_copy_mode_data
*data
= wp
->modedata
;
338 struct screen
*s
= &data
->screen
;
339 struct screen_write_ctx ctx
;
341 screen_resize(s
, sx
, sy
, 0);
342 if (data
->backing
!= &wp
->base
)
343 screen_resize(data
->backing
, sx
, sy
, 0);
345 if (data
->cy
> sy
- 1)
349 if (data
->oy
> screen_hsize(data
->backing
))
350 data
->oy
= screen_hsize(data
->backing
);
352 window_copy_clear_selection(wp
);
354 screen_write_start(&ctx
, NULL
, s
);
355 window_copy_write_lines(wp
, &ctx
, 0, screen_size_y(s
) - 1);
356 screen_write_stop(&ctx
);
358 window_copy_redraw_screen(wp
);
362 window_copy_key(struct window_pane
*wp
, struct session
*sess
, int key
)
364 const char *word_separators
;
365 struct window_copy_mode_data
*data
= wp
->modedata
;
366 struct screen
*s
= &data
->screen
;
369 enum mode_key_cmd cmd
;
372 np
= data
->numprefix
;
376 if (data
->inputtype
== WINDOW_COPY_JUMPFORWARD
||
377 data
->inputtype
== WINDOW_COPY_JUMPBACK
||
378 data
->inputtype
== WINDOW_COPY_JUMPTOFORWARD
||
379 data
->inputtype
== WINDOW_COPY_JUMPTOBACK
) {
380 /* Ignore keys with modifiers. */
381 if ((key
& KEYC_MASK_MOD
) == 0) {
382 data
->jumpchar
= key
;
383 if (data
->inputtype
== WINDOW_COPY_JUMPFORWARD
) {
384 for (; np
!= 0; np
--)
385 window_copy_cursor_jump(wp
);
386 } else if (data
->inputtype
== WINDOW_COPY_JUMPBACK
) {
387 for (; np
!= 0; np
--)
388 window_copy_cursor_jump_back(wp
);
389 } else if (data
->inputtype
== WINDOW_COPY_JUMPTOFORWARD
) {
390 for (; np
!= 0; np
--)
391 window_copy_cursor_jump_to(wp
);
392 } else if (data
->inputtype
== WINDOW_COPY_JUMPTOBACK
) {
393 for (; np
!= 0; np
--)
394 window_copy_cursor_jump_to_back(wp
);
397 data
->jumptype
= data
->inputtype
;
398 data
->inputtype
= WINDOW_COPY_OFF
;
399 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
401 } else if (data
->inputtype
== WINDOW_COPY_NUMERICPREFIX
) {
402 if (window_copy_key_numeric_prefix(wp
, key
) == 0)
404 data
->inputtype
= WINDOW_COPY_OFF
;
405 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
406 } else if (data
->inputtype
!= WINDOW_COPY_OFF
) {
407 if (window_copy_key_input(wp
, key
) != 0)
412 cmd
= mode_key_lookup(&data
->mdata
, key
, &arg
);
414 case MODEKEYCOPY_CANCEL
:
415 window_pane_reset_mode(wp
);
417 case MODEKEYCOPY_LEFT
:
418 for (; np
!= 0; np
--)
419 window_copy_cursor_left(wp
);
421 case MODEKEYCOPY_RIGHT
:
422 for (; np
!= 0; np
--)
423 window_copy_cursor_right(wp
);
426 for (; np
!= 0; np
--)
427 window_copy_cursor_up(wp
, 0);
429 case MODEKEYCOPY_DOWN
:
430 for (; np
!= 0; np
--)
431 window_copy_cursor_down(wp
, 0);
433 case MODEKEYCOPY_SCROLLUP
:
434 for (; np
!= 0; np
--)
435 window_copy_cursor_up(wp
, 1);
437 case MODEKEYCOPY_SCROLLDOWN
:
438 for (; np
!= 0; np
--)
439 window_copy_cursor_down(wp
, 1);
441 case MODEKEYCOPY_PREVIOUSPAGE
:
442 for (; np
!= 0; np
--)
443 window_copy_pageup(wp
);
445 case MODEKEYCOPY_NEXTPAGE
:
447 if (screen_size_y(s
) > 2)
448 n
= screen_size_y(s
) - 2;
449 for (; np
!= 0; np
--) {
455 window_copy_update_selection(wp
);
456 window_copy_redraw_screen(wp
);
458 case MODEKEYCOPY_HALFPAGEUP
:
459 n
= screen_size_y(s
) / 2;
460 for (; np
!= 0; np
--) {
461 if (data
->oy
+ n
> screen_hsize(data
->backing
))
462 data
->oy
= screen_hsize(data
->backing
);
466 window_copy_update_selection(wp
);
467 window_copy_redraw_screen(wp
);
469 case MODEKEYCOPY_HALFPAGEDOWN
:
470 n
= screen_size_y(s
) / 2;
471 for (; np
!= 0; np
--) {
477 window_copy_update_selection(wp
);
478 window_copy_redraw_screen(wp
);
480 case MODEKEYCOPY_TOPLINE
:
483 window_copy_update_selection(wp
);
484 window_copy_redraw_screen(wp
);
486 case MODEKEYCOPY_MIDDLELINE
:
488 data
->cy
= (screen_size_y(s
) - 1) / 2;
489 window_copy_update_selection(wp
);
490 window_copy_redraw_screen(wp
);
492 case MODEKEYCOPY_BOTTOMLINE
:
494 data
->cy
= screen_size_y(s
) - 1;
495 window_copy_update_selection(wp
);
496 window_copy_redraw_screen(wp
);
498 case MODEKEYCOPY_HISTORYTOP
:
501 data
->oy
= screen_hsize(data
->backing
);
502 window_copy_update_selection(wp
);
503 window_copy_redraw_screen(wp
);
505 case MODEKEYCOPY_HISTORYBOTTOM
:
507 data
->cy
= screen_size_y(s
) - 1;
509 window_copy_update_selection(wp
);
510 window_copy_redraw_screen(wp
);
512 case MODEKEYCOPY_STARTSELECTION
:
513 window_copy_start_selection(wp
);
514 window_copy_redraw_screen(wp
);
516 case MODEKEYCOPY_COPYLINE
:
517 case MODEKEYCOPY_SELECTLINE
:
518 window_copy_cursor_start_of_line(wp
);
520 case MODEKEYCOPY_COPYENDOFLINE
:
521 window_copy_start_selection(wp
);
523 window_copy_cursor_down(wp
, 0);
524 window_copy_cursor_end_of_line(wp
);
525 window_copy_redraw_screen(wp
);
527 /* If a copy command then copy the selection and exit. */
529 (cmd
== MODEKEYCOPY_COPYLINE
||
530 cmd
== MODEKEYCOPY_COPYENDOFLINE
)) {
531 window_copy_copy_selection(wp
, -1);
532 window_pane_reset_mode(wp
);
536 case MODEKEYCOPY_CLEARSELECTION
:
537 window_copy_clear_selection(wp
);
538 window_copy_redraw_screen(wp
);
540 case MODEKEYCOPY_COPYPIPE
:
542 window_copy_copy_pipe(wp
, data
->numprefix
, arg
);
543 window_pane_reset_mode(wp
);
547 case MODEKEYCOPY_COPYSELECTION
:
549 window_copy_copy_selection(wp
, data
->numprefix
);
550 window_pane_reset_mode(wp
);
554 case MODEKEYCOPY_STARTOFLINE
:
555 window_copy_cursor_start_of_line(wp
);
557 case MODEKEYCOPY_BACKTOINDENTATION
:
558 window_copy_cursor_back_to_indentation(wp
);
560 case MODEKEYCOPY_ENDOFLINE
:
561 window_copy_cursor_end_of_line(wp
);
563 case MODEKEYCOPY_NEXTSPACE
:
564 for (; np
!= 0; np
--)
565 window_copy_cursor_next_word(wp
, " ");
567 case MODEKEYCOPY_NEXTSPACEEND
:
568 for (; np
!= 0; np
--)
569 window_copy_cursor_next_word_end(wp
, " ");
571 case MODEKEYCOPY_NEXTWORD
:
573 options_get_string(&sess
->options
, "word-separators");
574 for (; np
!= 0; np
--)
575 window_copy_cursor_next_word(wp
, word_separators
);
577 case MODEKEYCOPY_NEXTWORDEND
:
579 options_get_string(&sess
->options
, "word-separators");
580 for (; np
!= 0; np
--)
581 window_copy_cursor_next_word_end(wp
, word_separators
);
583 case MODEKEYCOPY_PREVIOUSSPACE
:
584 for (; np
!= 0; np
--)
585 window_copy_cursor_previous_word(wp
, " ");
587 case MODEKEYCOPY_PREVIOUSWORD
:
589 options_get_string(&sess
->options
, "word-separators");
590 for (; np
!= 0; np
--)
591 window_copy_cursor_previous_word(wp
, word_separators
);
593 case MODEKEYCOPY_JUMP
:
594 data
->inputtype
= WINDOW_COPY_JUMPFORWARD
;
595 data
->inputprompt
= "Jump Forward";
596 *data
->inputstr
= '\0';
597 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
598 return; /* skip numprefix reset */
599 case MODEKEYCOPY_JUMPAGAIN
:
600 if (data
->jumptype
== WINDOW_COPY_JUMPFORWARD
) {
601 for (; np
!= 0; np
--)
602 window_copy_cursor_jump(wp
);
603 } else if (data
->jumptype
== WINDOW_COPY_JUMPBACK
) {
604 for (; np
!= 0; np
--)
605 window_copy_cursor_jump_back(wp
);
606 } else if (data
->jumptype
== WINDOW_COPY_JUMPTOFORWARD
) {
607 for (; np
!= 0; np
--)
608 window_copy_cursor_jump_to(wp
);
609 } else if (data
->jumptype
== WINDOW_COPY_JUMPTOBACK
) {
610 for (; np
!= 0; np
--)
611 window_copy_cursor_jump_to_back(wp
);
614 case MODEKEYCOPY_JUMPREVERSE
:
615 if (data
->jumptype
== WINDOW_COPY_JUMPFORWARD
) {
616 for (; np
!= 0; np
--)
617 window_copy_cursor_jump_back(wp
);
618 } else if (data
->jumptype
== WINDOW_COPY_JUMPBACK
) {
619 for (; np
!= 0; np
--)
620 window_copy_cursor_jump(wp
);
621 } else if (data
->jumptype
== WINDOW_COPY_JUMPTOFORWARD
) {
622 for (; np
!= 0; np
--)
623 window_copy_cursor_jump_to_back(wp
);
624 } else if (data
->jumptype
== WINDOW_COPY_JUMPTOBACK
) {
625 for (; np
!= 0; np
--)
626 window_copy_cursor_jump_to(wp
);
629 case MODEKEYCOPY_JUMPBACK
:
630 data
->inputtype
= WINDOW_COPY_JUMPBACK
;
631 data
->inputprompt
= "Jump Back";
632 *data
->inputstr
= '\0';
633 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
634 return; /* skip numprefix reset */
635 case MODEKEYCOPY_JUMPTO
:
636 data
->inputtype
= WINDOW_COPY_JUMPTOFORWARD
;
637 data
->inputprompt
= "Jump To";
638 *data
->inputstr
= '\0';
639 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
640 return; /* skip numprefix reset */
641 case MODEKEYCOPY_JUMPTOBACK
:
642 data
->inputtype
= WINDOW_COPY_JUMPTOBACK
;
643 data
->inputprompt
= "Jump To Back";
644 *data
->inputstr
= '\0';
645 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
646 return; /* skip numprefix reset */
647 case MODEKEYCOPY_SEARCHUP
:
648 data
->inputtype
= WINDOW_COPY_SEARCHUP
;
649 data
->inputprompt
= "Search Up";
651 case MODEKEYCOPY_SEARCHDOWN
:
652 data
->inputtype
= WINDOW_COPY_SEARCHDOWN
;
653 data
->inputprompt
= "Search Down";
655 case MODEKEYCOPY_SEARCHAGAIN
:
656 case MODEKEYCOPY_SEARCHREVERSE
:
657 switch (data
->searchtype
) {
658 case WINDOW_COPY_OFF
:
659 case WINDOW_COPY_GOTOLINE
:
660 case WINDOW_COPY_JUMPFORWARD
:
661 case WINDOW_COPY_JUMPBACK
:
662 case WINDOW_COPY_JUMPTOFORWARD
:
663 case WINDOW_COPY_JUMPTOBACK
:
664 case WINDOW_COPY_NUMERICPREFIX
:
666 case WINDOW_COPY_SEARCHUP
:
667 if (cmd
== MODEKEYCOPY_SEARCHAGAIN
) {
668 for (; np
!= 0; np
--) {
669 window_copy_search_up(
670 wp
, data
->searchstr
);
673 for (; np
!= 0; np
--) {
674 window_copy_search_down(
675 wp
, data
->searchstr
);
679 case WINDOW_COPY_SEARCHDOWN
:
680 if (cmd
== MODEKEYCOPY_SEARCHAGAIN
) {
681 for (; np
!= 0; np
--) {
682 window_copy_search_down(
683 wp
, data
->searchstr
);
686 for (; np
!= 0; np
--) {
687 window_copy_search_up(
688 wp
, data
->searchstr
);
694 case MODEKEYCOPY_GOTOLINE
:
695 data
->inputtype
= WINDOW_COPY_GOTOLINE
;
696 data
->inputprompt
= "Goto Line";
697 *data
->inputstr
= '\0';
699 case MODEKEYCOPY_STARTNUMBERPREFIX
:
700 key
&= KEYC_MASK_KEY
;
701 if (key
>= '0' && key
<= '9') {
702 data
->inputtype
= WINDOW_COPY_NUMERICPREFIX
;
704 window_copy_key_numeric_prefix(wp
, key
);
708 case MODEKEYCOPY_RECTANGLETOGGLE
:
709 window_copy_rectangle_toggle(wp
);
715 data
->numprefix
= -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_edit
);
723 mode_key_init(&data
->mdata
, &mode_key_tree_vi_edit
);
725 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
729 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
730 if (keys
== MODEKEY_EMACS
)
731 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_copy
);
733 mode_key_init(&data
->mdata
, &mode_key_tree_vi_copy
);
735 data
->inputtype
= WINDOW_COPY_OFF
;
736 data
->inputprompt
= NULL
;
738 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
742 window_copy_key_input(struct window_pane
*wp
, int key
)
744 struct window_copy_mode_data
*data
= wp
->modedata
;
745 struct screen
*s
= &data
->screen
;
749 switch (mode_key_lookup(&data
->mdata
, key
, NULL
)) {
750 case MODEKEYEDIT_CANCEL
:
751 data
->numprefix
= -1;
753 case MODEKEYEDIT_BACKSPACE
:
754 inputlen
= strlen(data
->inputstr
);
756 data
->inputstr
[inputlen
- 1] = '\0';
758 case MODEKEYEDIT_DELETELINE
:
759 *data
->inputstr
= '\0';
761 case MODEKEYEDIT_ENTER
:
762 np
= data
->numprefix
;
766 switch (data
->inputtype
) {
767 case WINDOW_COPY_OFF
:
768 case WINDOW_COPY_JUMPFORWARD
:
769 case WINDOW_COPY_JUMPBACK
:
770 case WINDOW_COPY_JUMPTOFORWARD
:
771 case WINDOW_COPY_JUMPTOBACK
:
772 case WINDOW_COPY_NUMERICPREFIX
:
774 case WINDOW_COPY_SEARCHUP
:
775 for (; np
!= 0; np
--)
776 window_copy_search_up(wp
, data
->inputstr
);
777 data
->searchtype
= data
->inputtype
;
778 data
->searchstr
= xstrdup(data
->inputstr
);
780 case WINDOW_COPY_SEARCHDOWN
:
781 for (; np
!= 0; np
--)
782 window_copy_search_down(wp
, data
->inputstr
);
783 data
->searchtype
= data
->inputtype
;
784 data
->searchstr
= xstrdup(data
->inputstr
);
786 case WINDOW_COPY_GOTOLINE
:
787 window_copy_goto_line(wp
, data
->inputstr
);
788 *data
->inputstr
= '\0';
791 data
->numprefix
= -1;
794 if (key
< 32 || key
> 126)
796 inputlen
= strlen(data
->inputstr
) + 2;
798 data
->inputstr
= xrealloc(data
->inputstr
, 1, inputlen
);
799 data
->inputstr
[inputlen
- 2] = key
;
800 data
->inputstr
[inputlen
- 1] = '\0';
806 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
811 window_copy_key_numeric_prefix(struct window_pane
*wp
, int key
)
813 struct window_copy_mode_data
*data
= wp
->modedata
;
814 struct screen
*s
= &data
->screen
;
816 key
&= KEYC_MASK_KEY
;
817 if (key
< '0' || key
> '9')
820 if (data
->numprefix
>= 100) /* no more than three digits */
822 data
->numprefix
= data
->numprefix
* 10 + key
- '0';
824 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
830 struct window_pane
*wp
, struct session
*sess
, struct mouse_event
*m
)
832 struct window_copy_mode_data
*data
= wp
->modedata
;
833 struct screen
*s
= &data
->screen
;
836 if (m
->x
>= screen_size_x(s
))
838 if (m
->y
>= screen_size_y(s
))
841 /* If mouse wheel (buttons 4 and 5), scroll. */
842 if (m
->event
== MOUSE_EVENT_WHEEL
) {
843 if (m
->wheel
== MOUSE_WHEEL_UP
) {
844 for (i
= 0; i
< 5; i
++)
845 window_copy_cursor_up(wp
, 1);
846 } else if (m
->wheel
== MOUSE_WHEEL_DOWN
) {
847 for (i
= 0; i
< 5; i
++)
848 window_copy_cursor_down(wp
, 1);
856 * If already reading motion, move the cursor while buttons are still
857 * pressed, or stop the selection on their release.
859 if (s
->mode
& MODE_MOUSE_BUTTON
) {
860 if (~m
->event
& MOUSE_EVENT_UP
) {
861 window_copy_update_cursor(wp
, m
->x
, m
->y
);
862 if (window_copy_update_selection(wp
))
863 window_copy_redraw_screen(wp
);
869 /* Otherwise if other buttons pressed, start selection and motion. */
870 if (~m
->event
& MOUSE_EVENT_UP
) {
871 s
->mode
&= ~MODE_MOUSE_STANDARD
;
872 s
->mode
|= MODE_MOUSE_BUTTON
;
874 window_copy_update_cursor(wp
, m
->x
, m
->y
);
875 window_copy_start_selection(wp
);
876 window_copy_redraw_screen(wp
);
882 s
->mode
&= ~MODE_MOUSE_BUTTON
;
883 s
->mode
|= MODE_MOUSE_STANDARD
;
885 window_copy_copy_selection(wp
, -1);
886 window_pane_reset_mode(wp
);
891 window_copy_scroll_to(struct window_pane
*wp
, u_int px
, u_int py
)
893 struct window_copy_mode_data
*data
= wp
->modedata
;
894 struct grid
*gd
= data
->backing
->grid
;
903 } else if (py
> gd
->hsize
+ gd
->sy
- gap
) {
905 data
->cy
= py
- gd
->hsize
;
907 offset
= py
+ gap
- gd
->sy
;
908 data
->cy
= py
- offset
;
910 data
->oy
= gd
->hsize
- offset
;
912 window_copy_update_selection(wp
);
913 window_copy_redraw_screen(wp
);
917 window_copy_search_compare(
918 struct grid
*gd
, u_int px
, u_int py
, struct grid
*sgd
, u_int spx
)
920 const struct grid_cell
*gc
, *sgc
;
921 struct utf8_data ud
, sud
;
923 gc
= grid_peek_cell(gd
, px
, py
);
924 grid_cell_get(gc
, &ud
);
925 sgc
= grid_peek_cell(sgd
, spx
, 0);
926 grid_cell_get(sgc
, &sud
);
928 if (ud
.size
!= sud
.size
|| ud
.width
!= sud
.width
)
930 return (memcmp(ud
.data
, sud
.data
, ud
.size
) == 0);
934 window_copy_search_lr(struct grid
*gd
,
935 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
)
939 for (ax
= first
; ax
< last
; ax
++) {
940 if (ax
+ sgd
->sx
>= gd
->sx
)
942 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
944 if (!window_copy_search_compare(gd
, px
, py
, sgd
, bx
))
956 window_copy_search_rl(struct grid
*gd
,
957 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
)
961 for (ax
= last
+ 1; ax
> first
; ax
--) {
962 if (gd
->sx
- (ax
- 1) < sgd
->sx
)
964 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
966 if (!window_copy_search_compare(gd
, px
, py
, sgd
, bx
))
978 window_copy_search_up(struct window_pane
*wp
, const char *searchstr
)
980 struct window_copy_mode_data
*data
= wp
->modedata
;
981 struct screen
*s
= data
->backing
, ss
;
982 struct screen_write_ctx ctx
;
983 struct grid
*gd
= s
->grid
, *sgd
;
986 u_int i
, last
, fx
, fy
, px
;
987 int utf8flag
, n
, wrapped
, wrapflag
;
989 if (*searchstr
== '\0')
991 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
992 wrapflag
= options_get_number(&wp
->window
->options
, "wrap-search");
993 searchlen
= screen_write_strlen(utf8flag
, "%s", searchstr
);
995 screen_init(&ss
, searchlen
, 1, 0);
996 screen_write_start(&ctx
, NULL
, &ss
);
997 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
998 screen_write_nputs(&ctx
, -1, &gc
, utf8flag
, "%s", searchstr
);
999 screen_write_stop(&ctx
);
1002 fy
= gd
->hsize
- data
->oy
+ data
->cy
;
1015 for (i
= fy
+ 1; i
> 0; i
--) {
1016 last
= screen_size_x(s
);
1019 n
= window_copy_search_rl(gd
, sgd
, &px
, i
- 1, 0, last
);
1021 window_copy_scroll_to(wp
, px
, i
- 1);
1025 if (wrapflag
&& !n
&& !wrapped
) {
1027 fy
= gd
->hsize
+ gd
->sy
- 1;
1036 window_copy_search_down(struct window_pane
*wp
, const char *searchstr
)
1038 struct window_copy_mode_data
*data
= wp
->modedata
;
1039 struct screen
*s
= data
->backing
, ss
;
1040 struct screen_write_ctx ctx
;
1041 struct grid
*gd
= s
->grid
, *sgd
;
1042 struct grid_cell gc
;
1044 u_int i
, first
, fx
, fy
, px
;
1045 int utf8flag
, n
, wrapped
, wrapflag
;
1047 if (*searchstr
== '\0')
1049 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
1050 wrapflag
= options_get_number(&wp
->window
->options
, "wrap-search");
1051 searchlen
= screen_write_strlen(utf8flag
, "%s", searchstr
);
1053 screen_init(&ss
, searchlen
, 1, 0);
1054 screen_write_start(&ctx
, NULL
, &ss
);
1055 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1056 screen_write_nputs(&ctx
, -1, &gc
, utf8flag
, "%s", searchstr
);
1057 screen_write_stop(&ctx
);
1060 fy
= gd
->hsize
- data
->oy
+ data
->cy
;
1062 if (fx
== gd
->sx
- 1) {
1063 if (fy
== gd
->hsize
+ gd
->sy
)
1073 for (i
= fy
+ 1; i
< gd
->hsize
+ gd
->sy
+ 1; i
++) {
1077 n
= window_copy_search_lr(gd
, sgd
, &px
, i
- 1, first
, gd
->sx
);
1079 window_copy_scroll_to(wp
, px
, i
- 1);
1083 if (wrapflag
&& !n
&& !wrapped
) {
1094 window_copy_goto_line(struct window_pane
*wp
, const char *linestr
)
1096 struct window_copy_mode_data
*data
= wp
->modedata
;
1100 lineno
= strtonum(linestr
, 0, screen_hsize(data
->backing
), &errstr
);
1105 window_copy_update_selection(wp
);
1106 window_copy_redraw_screen(wp
);
1110 window_copy_write_line(
1111 struct window_pane
*wp
, struct screen_write_ctx
*ctx
, u_int py
)
1113 struct window_copy_mode_data
*data
= wp
->modedata
;
1114 struct screen
*s
= &data
->screen
;
1115 struct options
*oo
= &wp
->window
->options
;
1116 struct grid_cell gc
;
1118 size_t last
, xoff
= 0, size
= 0;
1120 window_mode_attrs(&gc
, oo
);
1122 last
= screen_size_y(s
) - 1;
1124 size
= xsnprintf(hdr
, sizeof hdr
,
1125 "[%u/%u]", data
->oy
, screen_hsize(data
->backing
));
1126 if (size
> screen_size_x(s
))
1127 size
= screen_size_x(s
);
1128 screen_write_cursormove(ctx
, screen_size_x(s
) - size
, 0);
1129 screen_write_puts(ctx
, &gc
, "%s", hdr
);
1130 } else if (py
== last
&& data
->inputtype
!= WINDOW_COPY_OFF
) {
1131 if (data
->inputtype
== WINDOW_COPY_NUMERICPREFIX
) {
1132 xoff
= size
= xsnprintf(hdr
, sizeof hdr
,
1133 "Repeat: %u", data
->numprefix
);
1135 xoff
= size
= xsnprintf(hdr
, sizeof hdr
,
1136 "%s: %s", data
->inputprompt
, data
->inputstr
);
1138 screen_write_cursormove(ctx
, 0, last
);
1139 screen_write_puts(ctx
, &gc
, "%s", hdr
);
1143 screen_write_cursormove(ctx
, xoff
, py
);
1144 screen_write_copy(ctx
, data
->backing
, xoff
,
1145 (screen_hsize(data
->backing
) - data
->oy
) + py
,
1146 screen_size_x(s
) - size
, 1);
1148 if (py
== data
->cy
&& data
->cx
== screen_size_x(s
)) {
1149 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1150 screen_write_cursormove(ctx
, screen_size_x(s
) - 1, py
);
1151 screen_write_putc(ctx
, &gc
, '$');
1156 window_copy_write_lines(
1157 struct window_pane
*wp
, struct screen_write_ctx
*ctx
, u_int py
, u_int ny
)
1161 for (yy
= py
; yy
< py
+ ny
; yy
++)
1162 window_copy_write_line(wp
, ctx
, py
);
1166 window_copy_redraw_lines(struct window_pane
*wp
, u_int py
, u_int ny
)
1168 struct window_copy_mode_data
*data
= wp
->modedata
;
1169 struct screen_write_ctx ctx
;
1172 screen_write_start(&ctx
, wp
, NULL
);
1173 for (i
= py
; i
< py
+ ny
; i
++)
1174 window_copy_write_line(wp
, &ctx
, i
);
1175 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1176 screen_write_stop(&ctx
);
1180 window_copy_redraw_screen(struct window_pane
*wp
)
1182 struct window_copy_mode_data
*data
= wp
->modedata
;
1184 window_copy_redraw_lines(wp
, 0, screen_size_y(&data
->screen
));
1188 window_copy_update_cursor(struct window_pane
*wp
, u_int cx
, u_int cy
)
1190 struct window_copy_mode_data
*data
= wp
->modedata
;
1191 struct screen
*s
= &data
->screen
;
1192 struct screen_write_ctx ctx
;
1193 u_int old_cx
, old_cy
;
1195 old_cx
= data
->cx
; old_cy
= data
->cy
;
1196 data
->cx
= cx
; data
->cy
= cy
;
1197 if (old_cx
== screen_size_x(s
))
1198 window_copy_redraw_lines(wp
, old_cy
, 1);
1199 if (data
->cx
== screen_size_x(s
))
1200 window_copy_redraw_lines(wp
, data
->cy
, 1);
1202 screen_write_start(&ctx
, wp
, NULL
);
1203 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1204 screen_write_stop(&ctx
);
1209 window_copy_start_selection(struct window_pane
*wp
)
1211 struct window_copy_mode_data
*data
= wp
->modedata
;
1212 struct screen
*s
= &data
->screen
;
1214 data
->selx
= data
->cx
;
1215 data
->sely
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1218 window_copy_update_selection(wp
);
1222 window_copy_update_selection(struct window_pane
*wp
)
1224 struct window_copy_mode_data
*data
= wp
->modedata
;
1225 struct screen
*s
= &data
->screen
;
1226 struct options
*oo
= &wp
->window
->options
;
1227 struct grid_cell gc
;
1228 u_int sx
, sy
, ty
, cy
;
1234 window_mode_attrs(&gc
, oo
);
1236 /* Find top of screen. */
1237 ty
= screen_hsize(data
->backing
) - data
->oy
;
1239 /* Adjust the selection. */
1242 if (sy
< ty
) { /* above screen */
1243 if (!data
->rectflag
)
1246 } else if (sy
> ty
+ screen_size_y(s
) - 1) { /* below screen */
1247 if (!data
->rectflag
)
1248 sx
= screen_size_x(s
) - 1;
1249 sy
= screen_size_y(s
) - 1;
1252 sy
= screen_hsize(s
) + sy
;
1254 screen_set_selection(s
,
1255 sx
, sy
, data
->cx
, screen_hsize(s
) + data
->cy
, data
->rectflag
, &gc
);
1257 if (data
->rectflag
) {
1259 * Can't rely on the caller to redraw the right lines for
1260 * rectangle selection - find the highest line and the number
1261 * of lines, and redraw just past that in both directions
1265 window_copy_redraw_lines(wp
, sy
, cy
- sy
+ 1);
1267 window_copy_redraw_lines(wp
, cy
, sy
- cy
+ 1);
1274 window_copy_get_selection(struct window_pane
*wp
, size_t *len
)
1276 struct window_copy_mode_data
*data
= wp
->modedata
;
1277 struct screen
*s
= &data
->screen
;
1280 u_int i
, xx
, yy
, sx
, sy
, ex
, ey
;
1281 u_int firstsx
, lastex
, restex
, restsx
;
1293 * The selection extends from selx,sely to (adjusted) cx,cy on
1297 /* Find start and end. */
1299 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1300 if (yy
< data
->sely
|| (yy
== data
->sely
&& xx
< data
->selx
)) {
1302 ex
= data
->selx
; ey
= data
->sely
;
1304 sx
= data
->selx
; sy
= data
->sely
;
1308 /* Trim ex to end of line. */
1309 xx
= window_copy_find_length(wp
, ey
);
1314 * Deal with rectangle-copy if necessary; four situations: start of
1315 * first line (firstsx), end of last line (lastex), start (restsx) and
1316 * end (restex) of all other lines.
1318 xx
= screen_size_x(s
);
1321 * Behave according to mode-keys. If it is emacs, copy like emacs,
1322 * keeping the top-left-most character, and dropping the
1323 * bottom-right-most, regardless of copy direction. If it is vi, also
1324 * keep bottom-right-most character.
1326 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
1327 if (data
->rectflag
) {
1329 * Need to ignore the column with the cursor in it, which for
1330 * rectangular copy means knowing which side the cursor is on.
1332 if (data
->selx
< data
->cx
) {
1333 /* Selection start is on the left. */
1334 if (keys
== MODEKEY_EMACS
) {
1339 lastex
= data
->cx
+ 1;
1340 restex
= data
->cx
+ 1;
1342 firstsx
= data
->selx
;
1343 restsx
= data
->selx
;
1345 /* Cursor is on the left. */
1346 lastex
= data
->selx
+ 1;
1347 restex
= data
->selx
+ 1;
1352 if (keys
== MODEKEY_EMACS
)
1361 /* Copy the lines. */
1363 window_copy_copy_line(wp
, &buf
, &off
, sy
, firstsx
, lastex
);
1365 window_copy_copy_line(wp
, &buf
, &off
, sy
, firstsx
, restex
);
1367 for (i
= sy
+ 1; i
< ey
; i
++) {
1368 window_copy_copy_line(
1369 wp
, &buf
, &off
, i
, restsx
, restex
);
1372 window_copy_copy_line(wp
, &buf
, &off
, ey
, restsx
, lastex
);
1375 /* Don't bother if no data. */
1380 *len
= off
- 1; /* remove final \n */
1385 window_copy_copy_buffer(struct window_pane
*wp
, int idx
, void *buf
, size_t len
)
1389 if (options_get_number(&global_options
, "set-clipboard"))
1390 screen_write_setselection(&wp
->ictx
.ctx
, buf
, len
);
1393 limit
= options_get_number(&global_options
, "buffer-limit");
1394 paste_add(&global_buffers
, buf
, len
, limit
);
1396 paste_replace(&global_buffers
, idx
, buf
, len
);
1400 window_copy_copy_pipe(struct window_pane
*wp
, int idx
, const char *arg
)
1406 buf
= window_copy_get_selection(wp
, &len
);
1410 f
= popen(arg
, "w");
1412 fwrite(buf
, 1, len
, f
);
1416 window_copy_copy_buffer(wp
, idx
, buf
, len
);
1420 window_copy_copy_selection(struct window_pane
*wp
, int idx
)
1425 buf
= window_copy_get_selection(wp
, &len
);
1429 window_copy_copy_buffer(wp
, idx
, buf
, len
);
1433 window_copy_copy_line(struct window_pane
*wp
,
1434 char **buf
, size_t *off
, u_int sy
, u_int sx
, u_int ex
)
1436 struct window_copy_mode_data
*data
= wp
->modedata
;
1437 struct grid
*gd
= data
->backing
->grid
;
1438 const struct grid_cell
*gc
;
1439 struct grid_line
*gl
;
1440 struct utf8_data ud
;
1441 u_int i
, xx
, wrapped
= 0;
1447 * Work out if the line was wrapped at the screen edge and all of it is
1450 gl
= &gd
->linedata
[sy
];
1451 if (gl
->flags
& GRID_LINE_WRAPPED
&& gl
->cellsize
<= gd
->sx
)
1454 /* If the line was wrapped, don't strip spaces (use the full length). */
1458 xx
= window_copy_find_length(wp
, sy
);
1465 for (i
= sx
; i
< ex
; i
++) {
1466 gc
= grid_peek_cell(gd
, i
, sy
);
1467 if (gc
->flags
& GRID_FLAG_PADDING
)
1469 grid_cell_get(gc
, &ud
);
1471 *buf
= xrealloc(*buf
, 1, (*off
) + ud
.size
);
1472 memcpy(*buf
+ *off
, ud
.data
, ud
.size
);
1477 /* Only add a newline if the line wasn't wrapped. */
1478 if (!wrapped
|| ex
!= xx
) {
1479 *buf
= xrealloc(*buf
, 1, (*off
) + 1);
1480 (*buf
)[(*off
)++] = '\n';
1485 window_copy_clear_selection(struct window_pane
*wp
)
1487 struct window_copy_mode_data
*data
= wp
->modedata
;
1490 screen_clear_selection(&data
->screen
);
1492 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1493 px
= window_copy_find_length(wp
, py
);
1495 window_copy_update_cursor(wp
, px
, data
->cy
);
1499 window_copy_in_set(struct window_pane
*wp
, u_int px
, u_int py
, const char *set
)
1501 struct window_copy_mode_data
*data
= wp
->modedata
;
1502 const struct grid_cell
*gc
;
1503 struct utf8_data ud
;
1505 gc
= grid_peek_cell(data
->backing
->grid
, px
, py
);
1506 grid_cell_get(gc
, &ud
);
1507 if (ud
.size
!= 1 || gc
->flags
& GRID_FLAG_PADDING
)
1509 if (*ud
.data
== 0x00 || *ud
.data
== 0x7f)
1511 return (strchr(set
, *ud
.data
) != NULL
);
1515 window_copy_find_length(struct window_pane
*wp
, u_int py
)
1517 struct window_copy_mode_data
*data
= wp
->modedata
;
1518 struct screen
*s
= data
->backing
;
1519 const struct grid_cell
*gc
;
1520 struct utf8_data ud
;
1524 * If the pane has been resized, its grid can contain old overlong
1525 * lines. grid_peek_cell does not allow accessing cells beyond the
1526 * width of the grid, and screen_write_copy treats them as spaces, so
1527 * ignore them here too.
1529 px
= s
->grid
->linedata
[py
].cellsize
;
1530 if (px
> screen_size_x(s
))
1531 px
= screen_size_x(s
);
1533 gc
= grid_peek_cell(s
->grid
, px
- 1, py
);
1534 grid_cell_get(gc
, &ud
);
1535 if (ud
.size
!= 1 || *ud
.data
!= ' ')
1543 window_copy_cursor_start_of_line(struct window_pane
*wp
)
1545 struct window_copy_mode_data
*data
= wp
->modedata
;
1546 struct screen
*back_s
= data
->backing
;
1547 struct grid
*gd
= back_s
->grid
;
1550 if (data
->cx
== 0) {
1551 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1552 while (py
> 0 && gd
->linedata
[py
-1].flags
& GRID_LINE_WRAPPED
) {
1553 window_copy_cursor_up(wp
, 0);
1554 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1557 window_copy_update_cursor(wp
, 0, data
->cy
);
1558 if (window_copy_update_selection(wp
))
1559 window_copy_redraw_lines(wp
, data
->cy
, 1);
1563 window_copy_cursor_back_to_indentation(struct window_pane
*wp
)
1565 struct window_copy_mode_data
*data
= wp
->modedata
;
1567 const struct grid_cell
*gc
;
1568 struct utf8_data ud
;
1571 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1572 xx
= window_copy_find_length(wp
, py
);
1575 gc
= grid_peek_cell(data
->backing
->grid
, px
, py
);
1576 grid_cell_get(gc
, &ud
);
1577 if (ud
.size
!= 1 || *ud
.data
!= ' ')
1582 window_copy_update_cursor(wp
, px
, data
->cy
);
1583 if (window_copy_update_selection(wp
))
1584 window_copy_redraw_lines(wp
, data
->cy
, 1);
1588 window_copy_cursor_end_of_line(struct window_pane
*wp
)
1590 struct window_copy_mode_data
*data
= wp
->modedata
;
1591 struct screen
*back_s
= data
->backing
;
1592 struct grid
*gd
= back_s
->grid
;
1595 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1596 px
= window_copy_find_length(wp
, py
);
1598 if (data
->cx
== px
) {
1599 if (data
->screen
.sel
.flag
&& data
->rectflag
)
1600 px
= screen_size_x(back_s
);
1601 if (gd
->linedata
[py
].flags
& GRID_LINE_WRAPPED
) {
1602 while (py
< gd
->sy
+ gd
->hsize
&&
1603 gd
->linedata
[py
].flags
& GRID_LINE_WRAPPED
) {
1604 window_copy_cursor_down(wp
, 0);
1605 py
= screen_hsize(back_s
)
1606 + data
->cy
- data
->oy
;
1608 px
= window_copy_find_length(wp
, py
);
1611 window_copy_update_cursor(wp
, px
, data
->cy
);
1613 if (window_copy_update_selection(wp
))
1614 window_copy_redraw_lines(wp
, data
->cy
, 1);
1618 window_copy_cursor_left(struct window_pane
*wp
)
1620 struct window_copy_mode_data
*data
= wp
->modedata
;
1622 if (data
->cx
== 0) {
1623 window_copy_cursor_up(wp
, 0);
1624 window_copy_cursor_end_of_line(wp
);
1626 window_copy_update_cursor(wp
, data
->cx
- 1, data
->cy
);
1627 if (window_copy_update_selection(wp
))
1628 window_copy_redraw_lines(wp
, data
->cy
, 1);
1633 window_copy_cursor_right(struct window_pane
*wp
)
1635 struct window_copy_mode_data
*data
= wp
->modedata
;
1638 if (data
->screen
.sel
.flag
&& data
->rectflag
)
1639 px
= screen_size_x(&data
->screen
);
1641 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1642 px
= window_copy_find_length(wp
, py
);
1645 if (data
->cx
>= px
) {
1646 window_copy_cursor_start_of_line(wp
);
1647 window_copy_cursor_down(wp
, 0);
1649 window_copy_update_cursor(wp
, data
->cx
+ 1, data
->cy
);
1650 if (window_copy_update_selection(wp
))
1651 window_copy_redraw_lines(wp
, data
->cy
, 1);
1656 window_copy_cursor_up(struct window_pane
*wp
, int scroll_only
)
1658 struct window_copy_mode_data
*data
= wp
->modedata
;
1659 struct screen
*s
= &data
->screen
;
1660 u_int ox
, oy
, px
, py
;
1662 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1663 ox
= window_copy_find_length(wp
, oy
);
1664 if (data
->cx
!= ox
) {
1665 data
->lastcx
= data
->cx
;
1669 data
->cx
= data
->lastcx
;
1670 if (scroll_only
|| data
->cy
== 0) {
1671 window_copy_scroll_down(wp
, 1);
1673 if (data
->cy
== screen_size_y(s
) - 1)
1674 window_copy_redraw_lines(wp
, data
->cy
, 1);
1676 window_copy_redraw_lines(wp
, data
->cy
, 2);
1679 window_copy_update_cursor(wp
, data
->cx
, data
->cy
- 1);
1680 if (window_copy_update_selection(wp
)) {
1681 if (data
->cy
== screen_size_y(s
) - 1)
1682 window_copy_redraw_lines(wp
, data
->cy
, 1);
1684 window_copy_redraw_lines(wp
, data
->cy
, 2);
1688 if (!data
->screen
.sel
.flag
|| !data
->rectflag
) {
1689 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1690 px
= window_copy_find_length(wp
, py
);
1691 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
1693 window_copy_cursor_end_of_line(wp
);
1698 window_copy_cursor_down(struct window_pane
*wp
, int scroll_only
)
1700 struct window_copy_mode_data
*data
= wp
->modedata
;
1701 struct screen
*s
= &data
->screen
;
1702 u_int ox
, oy
, px
, py
;
1704 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1705 ox
= window_copy_find_length(wp
, oy
);
1706 if (data
->cx
!= ox
) {
1707 data
->lastcx
= data
->cx
;
1711 data
->cx
= data
->lastcx
;
1712 if (scroll_only
|| data
->cy
== screen_size_y(s
) - 1) {
1713 window_copy_scroll_up(wp
, 1);
1714 if (scroll_only
&& data
->cy
> 0)
1715 window_copy_redraw_lines(wp
, data
->cy
- 1, 2);
1717 window_copy_update_cursor(wp
, data
->cx
, data
->cy
+ 1);
1718 if (window_copy_update_selection(wp
))
1719 window_copy_redraw_lines(wp
, data
->cy
- 1, 2);
1722 if (!data
->screen
.sel
.flag
|| !data
->rectflag
) {
1723 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1724 px
= window_copy_find_length(wp
, py
);
1725 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
1727 window_copy_cursor_end_of_line(wp
);
1732 window_copy_cursor_jump(struct window_pane
*wp
)
1734 struct window_copy_mode_data
*data
= wp
->modedata
;
1735 struct screen
*back_s
= data
->backing
;
1736 const struct grid_cell
*gc
;
1737 struct utf8_data ud
;
1741 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1742 xx
= window_copy_find_length(wp
, py
);
1745 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1746 grid_cell_get(gc
, &ud
);
1747 if (!(gc
->flags
& GRID_FLAG_PADDING
) &&
1748 ud
.size
== 1 && *ud
.data
== data
->jumpchar
) {
1749 window_copy_update_cursor(wp
, px
, data
->cy
);
1750 if (window_copy_update_selection(wp
))
1751 window_copy_redraw_lines(wp
, data
->cy
, 1);
1759 window_copy_cursor_jump_back(struct window_pane
*wp
)
1761 struct window_copy_mode_data
*data
= wp
->modedata
;
1762 struct screen
*back_s
= data
->backing
;
1763 const struct grid_cell
*gc
;
1764 struct utf8_data ud
;
1768 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1774 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1775 grid_cell_get(gc
, &ud
);
1776 if (!(gc
->flags
& GRID_FLAG_PADDING
) &&
1777 ud
.size
== 1 && *ud
.data
== data
->jumpchar
) {
1778 window_copy_update_cursor(wp
, px
, data
->cy
);
1779 if (window_copy_update_selection(wp
))
1780 window_copy_redraw_lines(wp
, data
->cy
, 1);
1790 window_copy_cursor_jump_to(struct window_pane
*wp
)
1792 struct window_copy_mode_data
*data
= wp
->modedata
;
1793 struct screen
*back_s
= data
->backing
;
1794 const struct grid_cell
*gc
;
1795 struct utf8_data ud
;
1799 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1800 xx
= window_copy_find_length(wp
, py
);
1803 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1804 grid_cell_get(gc
, &ud
);
1805 if (!(gc
->flags
& GRID_FLAG_PADDING
) &&
1806 ud
.size
== 1 && *ud
.data
== data
->jumpchar
) {
1807 window_copy_update_cursor(wp
, px
- 1, data
->cy
);
1808 if (window_copy_update_selection(wp
))
1809 window_copy_redraw_lines(wp
, data
->cy
, 1);
1817 window_copy_cursor_jump_to_back(struct window_pane
*wp
)
1819 struct window_copy_mode_data
*data
= wp
->modedata
;
1820 struct screen
*back_s
= data
->backing
;
1821 const struct grid_cell
*gc
;
1822 struct utf8_data ud
;
1826 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1832 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1833 grid_cell_get(gc
, &ud
);
1834 if (!(gc
->flags
& GRID_FLAG_PADDING
) &&
1835 ud
.size
== 1 && *ud
.data
== data
->jumpchar
) {
1836 window_copy_update_cursor(wp
, px
+ 1, data
->cy
);
1837 if (window_copy_update_selection(wp
))
1838 window_copy_redraw_lines(wp
, data
->cy
, 1);
1848 window_copy_cursor_next_word(struct window_pane
*wp
, const char *separators
)
1850 struct window_copy_mode_data
*data
= wp
->modedata
;
1851 struct screen
*back_s
= data
->backing
;
1852 u_int px
, py
, xx
, yy
;
1856 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1857 xx
= window_copy_find_length(wp
, py
);
1858 yy
= screen_hsize(back_s
) + screen_size_y(back_s
) - 1;
1861 * First skip past any nonword characters and then any word characters.
1863 * expected is initially set to 0 for the former and then 1 for the
1868 window_copy_in_set(wp
, px
, py
, separators
) == expected
) {
1869 /* Move down if we're past the end of the line. */
1873 window_copy_cursor_down(wp
, 0);
1876 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1877 xx
= window_copy_find_length(wp
, py
);
1881 expected
= !expected
;
1882 } while (expected
== 1);
1884 window_copy_update_cursor(wp
, px
, data
->cy
);
1885 if (window_copy_update_selection(wp
))
1886 window_copy_redraw_lines(wp
, data
->cy
, 1);
1890 window_copy_cursor_next_word_end(struct window_pane
*wp
, const char *separators
)
1892 struct window_copy_mode_data
*data
= wp
->modedata
;
1893 struct screen
*back_s
= data
->backing
;
1894 u_int px
, py
, xx
, yy
;
1898 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1899 xx
= window_copy_find_length(wp
, py
);
1900 yy
= screen_hsize(back_s
) + screen_size_y(back_s
) - 1;
1903 * First skip past any word characters, then any nonword characters.
1905 * expected is initially set to 1 for the former and then 0 for the
1910 window_copy_in_set(wp
, px
, py
, separators
) == expected
) {
1911 /* Move down if we're past the end of the line. */
1915 window_copy_cursor_down(wp
, 0);
1918 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1919 xx
= window_copy_find_length(wp
, py
);
1923 expected
= !expected
;
1924 } while (expected
== 0);
1926 window_copy_update_cursor(wp
, px
, data
->cy
);
1927 if (window_copy_update_selection(wp
))
1928 window_copy_redraw_lines(wp
, data
->cy
, 1);
1931 /* Move to the previous place where a word begins. */
1933 window_copy_cursor_previous_word(struct window_pane
*wp
, const char *separators
)
1935 struct window_copy_mode_data
*data
= wp
->modedata
;
1939 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1941 /* Move back to the previous word character. */
1945 if (!window_copy_in_set(wp
, px
, py
, separators
))
1948 if (data
->cy
== 0 &&
1949 (screen_hsize(data
->backing
) == 0 ||
1950 data
->oy
>= screen_hsize(data
->backing
) - 1))
1952 window_copy_cursor_up(wp
, 0);
1954 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1955 px
= window_copy_find_length(wp
, py
);
1959 /* Move back to the beginning of this word. */
1960 while (px
> 0 && !window_copy_in_set(wp
, px
- 1, py
, separators
))
1964 window_copy_update_cursor(wp
, px
, data
->cy
);
1965 if (window_copy_update_selection(wp
))
1966 window_copy_redraw_lines(wp
, data
->cy
, 1);
1970 window_copy_scroll_up(struct window_pane
*wp
, u_int ny
)
1972 struct window_copy_mode_data
*data
= wp
->modedata
;
1973 struct screen
*s
= &data
->screen
;
1974 struct screen_write_ctx ctx
;
1982 screen_write_start(&ctx
, wp
, NULL
);
1983 screen_write_cursormove(&ctx
, 0, 0);
1984 screen_write_deleteline(&ctx
, ny
);
1985 window_copy_write_lines(wp
, &ctx
, screen_size_y(s
) - ny
, ny
);
1986 window_copy_write_line(wp
, &ctx
, 0);
1987 if (screen_size_y(s
) > 1)
1988 window_copy_write_line(wp
, &ctx
, 1);
1989 if (screen_size_y(s
) > 3)
1990 window_copy_write_line(wp
, &ctx
, screen_size_y(s
) - 2);
1991 if (s
->sel
.flag
&& screen_size_y(s
) > ny
) {
1992 window_copy_update_selection(wp
);
1993 window_copy_write_line(wp
, &ctx
, screen_size_y(s
) - ny
- 1);
1995 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1996 window_copy_update_selection(wp
);
1997 screen_write_stop(&ctx
);
2001 window_copy_scroll_down(struct window_pane
*wp
, u_int ny
)
2003 struct window_copy_mode_data
*data
= wp
->modedata
;
2004 struct screen
*s
= &data
->screen
;
2005 struct screen_write_ctx ctx
;
2007 if (ny
> screen_hsize(data
->backing
))
2010 if (data
->oy
> screen_hsize(data
->backing
) - ny
)
2011 ny
= screen_hsize(data
->backing
) - data
->oy
;
2016 screen_write_start(&ctx
, wp
, NULL
);
2017 screen_write_cursormove(&ctx
, 0, 0);
2018 screen_write_insertline(&ctx
, ny
);
2019 window_copy_write_lines(wp
, &ctx
, 0, ny
);
2020 if (s
->sel
.flag
&& screen_size_y(s
) > ny
) {
2021 window_copy_update_selection(wp
);
2022 window_copy_write_line(wp
, &ctx
, ny
);
2023 } else if (ny
== 1) /* nuke position */
2024 window_copy_write_line(wp
, &ctx
, 1);
2025 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
2026 window_copy_update_selection(wp
);
2027 screen_write_stop(&ctx
);
2031 window_copy_rectangle_toggle(struct window_pane
*wp
)
2033 struct window_copy_mode_data
*data
= wp
->modedata
;
2036 data
->rectflag
= !data
->rectflag
;
2038 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2039 px
= window_copy_find_length(wp
, py
);
2041 window_copy_update_cursor(wp
, px
, data
->cy
);
2043 window_copy_update_selection(wp
);
2044 window_copy_redraw_screen(wp
);