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 client
*, 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 client
*, 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
*, struct client
*);
56 void window_copy_clear_selection(struct window_pane
*);
57 void window_copy_copy_line(
58 struct window_pane
*, char **, size_t *, u_int
, u_int
, u_int
);
59 int window_copy_in_set(struct window_pane
*, u_int
, u_int
, const char *);
60 u_int
window_copy_find_length(struct window_pane
*, u_int
);
61 void window_copy_cursor_start_of_line(struct window_pane
*);
62 void window_copy_cursor_back_to_indentation(struct window_pane
*);
63 void window_copy_cursor_end_of_line(struct window_pane
*);
64 void window_copy_cursor_left(struct window_pane
*);
65 void window_copy_cursor_right(struct window_pane
*);
66 void window_copy_cursor_up(struct window_pane
*, int);
67 void window_copy_cursor_down(struct window_pane
*, int);
68 void window_copy_cursor_jump(struct window_pane
*);
69 void window_copy_cursor_jump_back(struct window_pane
*);
70 void window_copy_cursor_next_word(struct window_pane
*, const char *);
71 void window_copy_cursor_next_word_end(struct window_pane
*, const char *);
72 void window_copy_cursor_previous_word(struct window_pane
*, const char *);
73 void window_copy_scroll_up(struct window_pane
*, u_int
);
74 void window_copy_scroll_down(struct window_pane
*, u_int
);
75 void window_copy_rectangle_toggle(struct window_pane
*);
77 const struct window_mode window_copy_mode
= {
86 enum window_copy_input_type
{
88 WINDOW_COPY_NUMERICPREFIX
,
90 WINDOW_COPY_SEARCHDOWN
,
91 WINDOW_COPY_JUMPFORWARD
,
97 * Copy-mode's visible screen (the "screen" field) is filled from one of
98 * two sources: the original contents of the pane (used when we
99 * actually enter via the "copy-mode" command, to copy the contents of
100 * the current pane), or else a series of lines containing the output
101 * from an output-writing tmux command (such as any of the "show-*" or
102 * "list-*" commands).
104 * In either case, the full content of the copy-mode grid is pointed at
105 * by the "backing" field, and is copied into "screen" as needed (that
106 * is, when scrolling occurs). When copy-mode is backed by a pane,
107 * backing points directly at that pane's screen structure (&wp->base);
108 * when backed by a list of output-lines from a command, it points at
109 * a newly-allocated screen structure (which is deallocated when the
112 struct window_copy_mode_data
{
113 struct screen screen
;
115 struct screen
*backing
;
116 int backing_written
; /* backing display has started */
118 struct mode_key_data mdata
;
125 u_int rectflag
; /* are we in rectangle copy mode? */
130 u_int lastcx
; /* position in last line with content */
131 u_int lastsx
; /* size of last line with content */
133 enum window_copy_input_type inputtype
;
134 const char *inputprompt
;
139 enum window_copy_input_type searchtype
;
142 enum window_copy_input_type jumptype
;
147 window_copy_init(struct window_pane
*wp
)
149 struct window_copy_mode_data
*data
;
153 wp
->modedata
= data
= xmalloc(sizeof *data
);
161 data
->backing_written
= 0;
165 data
->inputtype
= WINDOW_COPY_OFF
;
166 data
->inputprompt
= NULL
;
167 data
->inputstr
= xstrdup("");
170 data
->searchtype
= WINDOW_COPY_OFF
;
171 data
->searchstr
= NULL
;
173 wp
->flags
|= PANE_FREEZE
;
174 bufferevent_disable(wp
->event
, EV_READ
|EV_WRITE
);
176 data
->jumptype
= WINDOW_COPY_OFF
;
177 data
->jumpchar
= '\0';
180 screen_init(s
, screen_size_x(&wp
->base
), screen_size_y(&wp
->base
), 0);
181 if (options_get_number(&wp
->window
->options
, "mode-mouse"))
182 s
->mode
|= MODE_MOUSE
;
184 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
185 if (keys
== MODEKEY_EMACS
)
186 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_copy
);
188 mode_key_init(&data
->mdata
, &mode_key_tree_vi_copy
);
190 data
->backing
= NULL
;
196 window_copy_init_from_pane(struct window_pane
*wp
)
198 struct window_copy_mode_data
*data
= wp
->modedata
;
199 struct screen
*s
= &data
->screen
;
200 struct screen_write_ctx ctx
;
203 if (wp
->mode
!= &window_copy_mode
)
204 fatalx("not in copy mode");
206 data
->backing
= &wp
->base
;
207 data
->cx
= data
->backing
->cx
;
208 data
->cy
= data
->backing
->cy
;
213 screen_write_start(&ctx
, NULL
, s
);
214 for (i
= 0; i
< screen_size_y(s
); i
++)
215 window_copy_write_line(wp
, &ctx
, i
);
216 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
217 screen_write_stop(&ctx
);
221 window_copy_init_for_output(struct window_pane
*wp
)
223 struct window_copy_mode_data
*data
= wp
->modedata
;
225 data
->backing
= xmalloc(sizeof *data
->backing
);
226 screen_init(data
->backing
, screen_size_x(&wp
->base
),
227 screen_size_y(&wp
->base
), UINT_MAX
);
228 data
->backing
->mode
&= ~MODE_WRAP
;
232 window_copy_free(struct window_pane
*wp
)
234 struct window_copy_mode_data
*data
= wp
->modedata
;
236 wp
->flags
&= ~PANE_FREEZE
;
237 bufferevent_enable(wp
->event
, EV_READ
|EV_WRITE
);
239 if (data
->searchstr
!= NULL
)
240 xfree(data
->searchstr
);
241 xfree(data
->inputstr
);
243 if (data
->backing
!= &wp
->base
) {
244 screen_free(data
->backing
);
245 xfree(data
->backing
);
247 screen_free(&data
->screen
);
253 window_copy_add(struct window_pane
*wp
, const char *fmt
, ...)
258 window_copy_vadd(wp
, fmt
, ap
);
263 window_copy_vadd(struct window_pane
*wp
, const char *fmt
, va_list ap
)
265 struct window_copy_mode_data
*data
= wp
->modedata
;
266 struct screen
*backing
= data
->backing
;
267 struct screen_write_ctx back_ctx
, ctx
;
272 if (backing
== &wp
->base
)
275 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
276 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
278 old_hsize
= screen_hsize(data
->backing
);
279 screen_write_start(&back_ctx
, NULL
, backing
);
280 if (data
->backing_written
) {
282 * On the second or later line, do a CRLF before writing
283 * (so it's on a new line).
285 screen_write_carriagereturn(&back_ctx
);
286 screen_write_linefeed(&back_ctx
, 0);
288 data
->backing_written
= 1;
289 screen_write_vnputs(&back_ctx
, 0, &gc
, utf8flag
, fmt
, ap
);
290 screen_write_stop(&back_ctx
);
292 data
->oy
+= screen_hsize(data
->backing
) - old_hsize
;
294 screen_write_start(&ctx
, wp
, &data
->screen
);
297 * If the history has changed, draw the top line.
298 * (If there's any history at all, it has changed.)
300 if (screen_hsize(data
->backing
))
301 window_copy_redraw_lines(wp
, 0, 1);
303 /* Write the line, if it's visible. */
304 if (backing
->cy
+ data
->oy
< screen_size_y(backing
))
305 window_copy_redraw_lines(wp
, backing
->cy
, 1);
307 screen_write_stop(&ctx
);
311 window_copy_pageup(struct window_pane
*wp
)
313 struct window_copy_mode_data
*data
= wp
->modedata
;
314 struct screen
*s
= &data
->screen
;
318 if (screen_size_y(s
) > 2)
319 n
= screen_size_y(s
) - 2;
320 if (data
->oy
+ n
> screen_hsize(data
->backing
))
321 data
->oy
= screen_hsize(data
->backing
);
324 window_copy_update_selection(wp
);
325 window_copy_redraw_screen(wp
);
329 window_copy_resize(struct window_pane
*wp
, u_int sx
, u_int sy
)
331 struct window_copy_mode_data
*data
= wp
->modedata
;
332 struct screen
*s
= &data
->screen
;
333 struct screen_write_ctx ctx
;
335 screen_resize(s
, sx
, sy
);
336 if (data
->backing
!= &wp
->base
)
337 screen_resize(data
->backing
, sx
, sy
);
339 if (data
->cy
> sy
- 1)
344 window_copy_clear_selection(wp
);
346 screen_write_start(&ctx
, NULL
, s
);
347 window_copy_write_lines(wp
, &ctx
, 0, screen_size_y(s
) - 1);
348 screen_write_stop(&ctx
);
350 window_copy_redraw_screen(wp
);
354 window_copy_key(struct window_pane
*wp
, struct client
*c
, int key
)
356 const char *word_separators
;
357 struct window_copy_mode_data
*data
= wp
->modedata
;
358 struct screen
*s
= &data
->screen
;
361 enum mode_key_cmd cmd
;
363 np
= data
->numprefix
;
367 if (data
->inputtype
== WINDOW_COPY_JUMPFORWARD
368 || data
->inputtype
== WINDOW_COPY_JUMPBACK
) {
369 /* Ignore keys with modifiers. */
370 if ((key
& 0xff00) == 0) {
371 data
->jumpchar
= key
;
372 if (data
->inputtype
== WINDOW_COPY_JUMPFORWARD
) {
373 for (; np
!= 0; np
--)
374 window_copy_cursor_jump(wp
);
376 for (; np
!= 0; np
--)
377 window_copy_cursor_jump_back(wp
);
380 data
->jumptype
= data
->inputtype
;
381 data
->inputtype
= WINDOW_COPY_OFF
;
382 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
384 } if (data
->inputtype
== WINDOW_COPY_NUMERICPREFIX
) {
385 if (window_copy_key_numeric_prefix(wp
, key
) == 0)
387 data
->inputtype
= WINDOW_COPY_OFF
;
388 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
389 } else if (data
->inputtype
!= WINDOW_COPY_OFF
) {
390 if (window_copy_key_input(wp
, key
) != 0)
395 cmd
= mode_key_lookup(&data
->mdata
, key
);
397 case MODEKEYCOPY_CANCEL
:
398 window_pane_reset_mode(wp
);
400 case MODEKEYCOPY_LEFT
:
401 for (; np
!= 0; np
--)
402 window_copy_cursor_left(wp
);
404 case MODEKEYCOPY_RIGHT
:
405 for (; np
!= 0; np
--)
406 window_copy_cursor_right(wp
);
409 for (; np
!= 0; np
--)
410 window_copy_cursor_up(wp
, 0);
412 case MODEKEYCOPY_DOWN
:
413 for (; np
!= 0; np
--)
414 window_copy_cursor_down(wp
, 0);
416 case MODEKEYCOPY_SCROLLUP
:
417 for (; np
!= 0; np
--)
418 window_copy_cursor_up(wp
, 1);
420 case MODEKEYCOPY_SCROLLDOWN
:
421 for (; np
!= 0; np
--)
422 window_copy_cursor_down(wp
, 1);
424 case MODEKEYCOPY_PREVIOUSPAGE
:
425 for (; np
!= 0; np
--)
426 window_copy_pageup(wp
);
428 case MODEKEYCOPY_NEXTPAGE
:
430 if (screen_size_y(s
) > 2)
431 n
= screen_size_y(s
) - 2;
432 for (; np
!= 0; np
--) {
438 window_copy_update_selection(wp
);
439 window_copy_redraw_screen(wp
);
441 case MODEKEYCOPY_HALFPAGEUP
:
442 n
= screen_size_y(s
) / 2;
443 for (; np
!= 0; np
--) {
444 if (data
->oy
+ n
> screen_hsize(data
->backing
))
445 data
->oy
= screen_hsize(data
->backing
);
449 window_copy_update_selection(wp
);
450 window_copy_redraw_screen(wp
);
452 case MODEKEYCOPY_HALFPAGEDOWN
:
453 n
= screen_size_y(s
) / 2;
454 for (; np
!= 0; np
--) {
460 window_copy_update_selection(wp
);
461 window_copy_redraw_screen(wp
);
463 case MODEKEYCOPY_TOPLINE
:
466 window_copy_update_selection(wp
);
467 window_copy_redraw_screen(wp
);
469 case MODEKEYCOPY_MIDDLELINE
:
471 data
->cy
= (screen_size_y(s
) - 1) / 2;
472 window_copy_update_selection(wp
);
473 window_copy_redraw_screen(wp
);
475 case MODEKEYCOPY_BOTTOMLINE
:
477 data
->cy
= screen_size_y(s
) - 1;
478 window_copy_update_selection(wp
);
479 window_copy_redraw_screen(wp
);
481 case MODEKEYCOPY_HISTORYTOP
:
484 data
->oy
= screen_hsize(data
->backing
);
485 window_copy_update_selection(wp
);
486 window_copy_redraw_screen(wp
);
488 case MODEKEYCOPY_HISTORYBOTTOM
:
490 data
->cy
= screen_size_y(s
) - 1;
492 window_copy_update_selection(wp
);
493 window_copy_redraw_screen(wp
);
495 case MODEKEYCOPY_STARTSELECTION
:
496 window_copy_start_selection(wp
);
497 window_copy_redraw_screen(wp
);
499 case MODEKEYCOPY_CLEARSELECTION
:
500 window_copy_clear_selection(wp
);
501 window_copy_redraw_screen(wp
);
503 case MODEKEYCOPY_COPYSELECTION
:
504 if (c
!= NULL
&& c
->session
!= NULL
) {
505 window_copy_copy_selection(wp
, c
);
506 window_pane_reset_mode(wp
);
510 case MODEKEYCOPY_STARTOFLINE
:
511 window_copy_cursor_start_of_line(wp
);
513 case MODEKEYCOPY_BACKTOINDENTATION
:
514 window_copy_cursor_back_to_indentation(wp
);
516 case MODEKEYCOPY_ENDOFLINE
:
517 window_copy_cursor_end_of_line(wp
);
519 case MODEKEYCOPY_NEXTSPACE
:
520 for (; np
!= 0; np
--)
521 window_copy_cursor_next_word(wp
, " ");
523 case MODEKEYCOPY_NEXTSPACEEND
:
524 for (; np
!= 0; np
--)
525 window_copy_cursor_next_word_end(wp
, " ");
527 case MODEKEYCOPY_NEXTWORD
:
529 options_get_string(&wp
->window
->options
, "word-separators");
530 for (; np
!= 0; np
--)
531 window_copy_cursor_next_word(wp
, word_separators
);
533 case MODEKEYCOPY_NEXTWORDEND
:
535 options_get_string(&wp
->window
->options
, "word-separators");
536 for (; np
!= 0; np
--)
537 window_copy_cursor_next_word_end(wp
, word_separators
);
539 case MODEKEYCOPY_PREVIOUSSPACE
:
540 for (; np
!= 0; np
--)
541 window_copy_cursor_previous_word(wp
, " ");
543 case MODEKEYCOPY_PREVIOUSWORD
:
545 options_get_string(&wp
->window
->options
, "word-separators");
546 for (; np
!= 0; np
--)
547 window_copy_cursor_previous_word(wp
, word_separators
);
549 case MODEKEYCOPY_JUMP
:
550 data
->inputtype
= WINDOW_COPY_JUMPFORWARD
;
551 data
->inputprompt
= "Jump Forward";
552 *data
->inputstr
= '\0';
553 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
554 return; /* skip numprefix reset */
555 case MODEKEYCOPY_JUMPAGAIN
:
556 if (data
->jumptype
== WINDOW_COPY_JUMPFORWARD
) {
557 for (; np
!= 0; np
--)
558 window_copy_cursor_jump(wp
);
559 } else if (data
->jumptype
== WINDOW_COPY_JUMPBACK
) {
560 for (; np
!= 0; np
--)
561 window_copy_cursor_jump_back(wp
);
564 case MODEKEYCOPY_JUMPREVERSE
:
565 if (data
->jumptype
== WINDOW_COPY_JUMPFORWARD
) {
566 for (; np
!= 0; np
--)
567 window_copy_cursor_jump_back(wp
);
568 } else if (data
->jumptype
== WINDOW_COPY_JUMPBACK
) {
569 for (; np
!= 0; np
--)
570 window_copy_cursor_jump(wp
);
573 case MODEKEYCOPY_JUMPBACK
:
574 data
->inputtype
= WINDOW_COPY_JUMPBACK
;
575 data
->inputprompt
= "Jump Back";
576 *data
->inputstr
= '\0';
577 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
578 return; /* skip numprefix reset */
579 case MODEKEYCOPY_SEARCHUP
:
580 data
->inputtype
= WINDOW_COPY_SEARCHUP
;
581 data
->inputprompt
= "Search Up";
583 case MODEKEYCOPY_SEARCHDOWN
:
584 data
->inputtype
= WINDOW_COPY_SEARCHDOWN
;
585 data
->inputprompt
= "Search Down";
587 case MODEKEYCOPY_SEARCHAGAIN
:
588 case MODEKEYCOPY_SEARCHREVERSE
:
589 switch (data
->searchtype
) {
590 case WINDOW_COPY_OFF
:
591 case WINDOW_COPY_GOTOLINE
:
592 case WINDOW_COPY_JUMPFORWARD
:
593 case WINDOW_COPY_JUMPBACK
:
594 case WINDOW_COPY_NUMERICPREFIX
:
596 case WINDOW_COPY_SEARCHUP
:
597 if (cmd
== MODEKEYCOPY_SEARCHAGAIN
) {
598 for (; np
!= 0; np
--) {
599 window_copy_search_up(
600 wp
, data
->searchstr
);
603 for (; np
!= 0; np
--) {
604 window_copy_search_down(
605 wp
, data
->searchstr
);
609 case WINDOW_COPY_SEARCHDOWN
:
610 if (cmd
== MODEKEYCOPY_SEARCHAGAIN
) {
611 for (; np
!= 0; np
--) {
612 window_copy_search_down(
613 wp
, data
->searchstr
);
616 for (; np
!= 0; np
--) {
617 window_copy_search_up(
618 wp
, data
->searchstr
);
624 case MODEKEYCOPY_GOTOLINE
:
625 data
->inputtype
= WINDOW_COPY_GOTOLINE
;
626 data
->inputprompt
= "Goto Line";
627 *data
->inputstr
= '\0';
629 case MODEKEYCOPY_STARTNUMBERPREFIX
:
631 if (key
>= '0' && key
<= '9') {
632 data
->inputtype
= WINDOW_COPY_NUMERICPREFIX
;
634 window_copy_key_numeric_prefix(wp
, key
);
638 case MODEKEYCOPY_RECTANGLETOGGLE
:
639 window_copy_rectangle_toggle(wp
);
649 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
650 if (keys
== MODEKEY_EMACS
)
651 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_edit
);
653 mode_key_init(&data
->mdata
, &mode_key_tree_vi_edit
);
655 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
659 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
660 if (keys
== MODEKEY_EMACS
)
661 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_copy
);
663 mode_key_init(&data
->mdata
, &mode_key_tree_vi_copy
);
665 data
->inputtype
= WINDOW_COPY_OFF
;
666 data
->inputprompt
= NULL
;
668 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
672 window_copy_key_input(struct window_pane
*wp
, int key
)
674 struct window_copy_mode_data
*data
= wp
->modedata
;
675 struct screen
*s
= &data
->screen
;
679 switch (mode_key_lookup(&data
->mdata
, key
)) {
680 case MODEKEYEDIT_CANCEL
:
683 case MODEKEYEDIT_BACKSPACE
:
684 inputlen
= strlen(data
->inputstr
);
686 data
->inputstr
[inputlen
- 1] = '\0';
688 case MODEKEYEDIT_DELETELINE
:
689 *data
->inputstr
= '\0';
691 case MODEKEYEDIT_ENTER
:
692 np
= data
->numprefix
;
696 switch (data
->inputtype
) {
697 case WINDOW_COPY_OFF
:
698 case WINDOW_COPY_JUMPFORWARD
:
699 case WINDOW_COPY_JUMPBACK
:
700 case WINDOW_COPY_NUMERICPREFIX
:
702 case WINDOW_COPY_SEARCHUP
:
703 for (; np
!= 0; np
--)
704 window_copy_search_up(wp
, data
->inputstr
);
705 data
->searchtype
= data
->inputtype
;
706 data
->searchstr
= xstrdup(data
->inputstr
);
708 case WINDOW_COPY_SEARCHDOWN
:
709 for (; np
!= 0; np
--)
710 window_copy_search_down(wp
, data
->inputstr
);
711 data
->searchtype
= data
->inputtype
;
712 data
->searchstr
= xstrdup(data
->inputstr
);
714 case WINDOW_COPY_GOTOLINE
:
715 window_copy_goto_line(wp
, data
->inputstr
);
716 *data
->inputstr
= '\0';
722 if (key
< 32 || key
> 126)
724 inputlen
= strlen(data
->inputstr
) + 2;
726 data
->inputstr
= xrealloc(data
->inputstr
, 1, inputlen
);
727 data
->inputstr
[inputlen
- 2] = key
;
728 data
->inputstr
[inputlen
- 1] = '\0';
734 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
739 window_copy_key_numeric_prefix(struct window_pane
*wp
, int key
)
741 struct window_copy_mode_data
*data
= wp
->modedata
;
742 struct screen
*s
= &data
->screen
;
745 if (key
< '0' || key
> '9')
748 if (data
->numprefix
>= 100) /* no more than three digits */
750 data
->numprefix
= data
->numprefix
* 10 + key
- '0';
752 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
759 struct window_pane
*wp
, unused
struct client
*c
, struct mouse_event
*m
)
761 struct window_copy_mode_data
*data
= wp
->modedata
;
762 struct screen
*s
= &data
->screen
;
766 if (m
->x
>= screen_size_x(s
))
768 if (m
->y
>= screen_size_y(s
))
771 window_copy_update_cursor(wp
, m
->x
, m
->y
);
772 if (window_copy_update_selection(wp
))
773 window_copy_redraw_screen(wp
);
777 window_copy_scroll_to(struct window_pane
*wp
, u_int px
, u_int py
)
779 struct window_copy_mode_data
*data
= wp
->modedata
;
780 struct grid
*gd
= data
->backing
->grid
;
789 } else if (py
> gd
->hsize
+ gd
->sy
- gap
) {
791 data
->cy
= py
- gd
->hsize
;
793 offset
= py
+ gap
- gd
->sy
;
794 data
->cy
= py
- offset
;
796 data
->oy
= gd
->hsize
- offset
;
798 window_copy_update_selection(wp
);
799 window_copy_redraw_screen(wp
);
803 window_copy_search_compare(
804 struct grid
*gd
, u_int px
, u_int py
, struct grid
*sgd
, u_int spx
)
806 const struct grid_cell
*gc
, *sgc
;
807 const struct grid_utf8
*gu
, *sgu
;
809 gc
= grid_peek_cell(gd
, px
, py
);
810 sgc
= grid_peek_cell(sgd
, spx
, 0);
812 if ((gc
->flags
& GRID_FLAG_UTF8
) != (sgc
->flags
& GRID_FLAG_UTF8
))
815 if (gc
->flags
& GRID_FLAG_UTF8
) {
816 gu
= grid_peek_utf8(gd
, px
, py
);
817 sgu
= grid_peek_utf8(sgd
, spx
, 0);
818 if (grid_utf8_compare(gu
, sgu
))
821 if (gc
->data
== sgc
->data
)
828 window_copy_search_lr(struct grid
*gd
,
829 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
)
833 for (ax
= first
; ax
< last
; ax
++) {
834 if (ax
+ sgd
->sx
>= gd
->sx
)
836 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
838 if (!window_copy_search_compare(gd
, px
, py
, sgd
, bx
))
850 window_copy_search_rl(struct grid
*gd
,
851 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
)
855 for (ax
= last
+ 1; ax
> first
; ax
--) {
856 if (gd
->sx
- (ax
- 1) < sgd
->sx
)
858 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
860 if (!window_copy_search_compare(gd
, px
, py
, sgd
, bx
))
872 window_copy_search_up(struct window_pane
*wp
, const char *searchstr
)
874 struct window_copy_mode_data
*data
= wp
->modedata
;
875 struct screen
*s
= data
->backing
, ss
;
876 struct screen_write_ctx ctx
;
877 struct grid
*gd
= s
->grid
, *sgd
;
880 u_int i
, last
, fx
, fy
, px
;
881 int utf8flag
, n
, wrapped
;
883 if (*searchstr
== '\0')
885 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
886 searchlen
= screen_write_strlen(utf8flag
, "%s", searchstr
);
888 screen_init(&ss
, searchlen
, 1, 0);
889 screen_write_start(&ctx
, NULL
, &ss
);
890 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
891 screen_write_nputs(&ctx
, -1, &gc
, utf8flag
, "%s", searchstr
);
892 screen_write_stop(&ctx
);
895 fy
= gd
->hsize
- data
->oy
+ data
->cy
;
908 for (i
= fy
+ 1; i
> 0; i
--) {
909 last
= screen_size_x(s
);
912 n
= window_copy_search_rl(gd
, sgd
, &px
, i
- 1, 0, last
);
914 window_copy_scroll_to(wp
, px
, i
- 1);
918 if (!n
&& !wrapped
) {
920 fy
= gd
->hsize
+ gd
->sy
- 1;
929 window_copy_search_down(struct window_pane
*wp
, const char *searchstr
)
931 struct window_copy_mode_data
*data
= wp
->modedata
;
932 struct screen
*s
= data
->backing
, ss
;
933 struct screen_write_ctx ctx
;
934 struct grid
*gd
= s
->grid
, *sgd
;
937 u_int i
, first
, fx
, fy
, px
;
938 int utf8flag
, n
, wrapped
;
940 if (*searchstr
== '\0')
942 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
943 searchlen
= screen_write_strlen(utf8flag
, "%s", searchstr
);
945 screen_init(&ss
, searchlen
, 1, 0);
946 screen_write_start(&ctx
, NULL
, &ss
);
947 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
948 screen_write_nputs(&ctx
, -1, &gc
, utf8flag
, "%s", searchstr
);
949 screen_write_stop(&ctx
);
952 fy
= gd
->hsize
- data
->oy
+ data
->cy
;
954 if (fx
== gd
->sx
- 1) {
955 if (fy
== gd
->hsize
+ gd
->sy
)
965 for (i
= fy
+ 1; i
< gd
->hsize
+ gd
->sy
; i
++) {
969 n
= window_copy_search_lr(gd
, sgd
, &px
, i
- 1, first
, gd
->sx
);
971 window_copy_scroll_to(wp
, px
, i
- 1);
975 if (!n
&& !wrapped
) {
986 window_copy_goto_line(struct window_pane
*wp
, const char *linestr
)
988 struct window_copy_mode_data
*data
= wp
->modedata
;
992 lineno
= strtonum(linestr
, 0, screen_hsize(data
->backing
), &errstr
);
997 window_copy_update_selection(wp
);
998 window_copy_redraw_screen(wp
);
1002 window_copy_write_line(
1003 struct window_pane
*wp
, struct screen_write_ctx
*ctx
, u_int py
)
1005 struct window_copy_mode_data
*data
= wp
->modedata
;
1006 struct screen
*s
= &data
->screen
;
1007 struct options
*oo
= &wp
->window
->options
;
1008 struct grid_cell gc
;
1010 size_t last
, xoff
= 0, size
= 0;
1012 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1013 colour_set_fg(&gc
, options_get_number(oo
, "mode-fg"));
1014 colour_set_bg(&gc
, options_get_number(oo
, "mode-bg"));
1015 gc
.attr
|= options_get_number(oo
, "mode-attr");
1017 last
= screen_size_y(s
) - 1;
1019 size
= xsnprintf(hdr
, sizeof hdr
,
1020 "[%u/%u]", data
->oy
, screen_hsize(data
->backing
));
1021 screen_write_cursormove(ctx
, screen_size_x(s
) - size
, 0);
1022 screen_write_puts(ctx
, &gc
, "%s", hdr
);
1023 } else if (py
== last
&& data
->inputtype
!= WINDOW_COPY_OFF
) {
1024 if (data
->inputtype
== WINDOW_COPY_NUMERICPREFIX
) {
1025 xoff
= size
= xsnprintf(hdr
, sizeof hdr
,
1026 "Repeat: %u", data
->numprefix
);
1028 xoff
= size
= xsnprintf(hdr
, sizeof hdr
,
1029 "%s: %s", data
->inputprompt
, data
->inputstr
);
1031 screen_write_cursormove(ctx
, 0, last
);
1032 screen_write_puts(ctx
, &gc
, "%s", hdr
);
1036 screen_write_cursormove(ctx
, xoff
, py
);
1037 screen_write_copy(ctx
, data
->backing
, xoff
,
1038 (screen_hsize(data
->backing
) - data
->oy
) + py
,
1039 screen_size_x(s
) - size
, 1);
1041 if (py
== data
->cy
&& data
->cx
== screen_size_x(s
)) {
1042 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1043 screen_write_cursormove(ctx
, screen_size_x(s
) - 1, py
);
1044 screen_write_putc(ctx
, &gc
, '$');
1049 window_copy_write_lines(
1050 struct window_pane
*wp
, struct screen_write_ctx
*ctx
, u_int py
, u_int ny
)
1054 for (yy
= py
; yy
< py
+ ny
; yy
++)
1055 window_copy_write_line(wp
, ctx
, py
);
1059 window_copy_redraw_lines(struct window_pane
*wp
, u_int py
, u_int ny
)
1061 struct window_copy_mode_data
*data
= wp
->modedata
;
1062 struct screen_write_ctx ctx
;
1065 screen_write_start(&ctx
, wp
, NULL
);
1066 for (i
= py
; i
< py
+ ny
; i
++)
1067 window_copy_write_line(wp
, &ctx
, i
);
1068 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1069 screen_write_stop(&ctx
);
1073 window_copy_redraw_screen(struct window_pane
*wp
)
1075 struct window_copy_mode_data
*data
= wp
->modedata
;
1077 window_copy_redraw_lines(wp
, 0, screen_size_y(&data
->screen
));
1081 window_copy_update_cursor(struct window_pane
*wp
, u_int cx
, u_int cy
)
1083 struct window_copy_mode_data
*data
= wp
->modedata
;
1084 struct screen
*s
= &data
->screen
;
1085 struct screen_write_ctx ctx
;
1086 u_int old_cx
, old_cy
;
1088 old_cx
= data
->cx
; old_cy
= data
->cy
;
1089 data
->cx
= cx
; data
->cy
= cy
;
1090 if (old_cx
== screen_size_x(s
))
1091 window_copy_redraw_lines(wp
, old_cy
, 1);
1092 if (data
->cx
== screen_size_x(s
))
1093 window_copy_redraw_lines(wp
, data
->cy
, 1);
1095 screen_write_start(&ctx
, wp
, NULL
);
1096 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1097 screen_write_stop(&ctx
);
1102 window_copy_start_selection(struct window_pane
*wp
)
1104 struct window_copy_mode_data
*data
= wp
->modedata
;
1105 struct screen
*s
= &data
->screen
;
1107 data
->selx
= data
->cx
;
1108 data
->sely
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1111 window_copy_update_selection(wp
);
1115 window_copy_update_selection(struct window_pane
*wp
)
1117 struct window_copy_mode_data
*data
= wp
->modedata
;
1118 struct screen
*s
= &data
->screen
;
1119 struct options
*oo
= &wp
->window
->options
;
1120 struct grid_cell gc
;
1121 u_int sx
, sy
, ty
, cy
;
1127 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
1128 colour_set_fg(&gc
, options_get_number(oo
, "mode-fg"));
1129 colour_set_bg(&gc
, options_get_number(oo
, "mode-bg"));
1130 gc
.attr
|= options_get_number(oo
, "mode-attr");
1132 /* Find top of screen. */
1133 ty
= screen_hsize(data
->backing
) - data
->oy
;
1135 /* Adjust the selection. */
1138 if (sy
< ty
) { /* above screen */
1139 if (!data
->rectflag
)
1142 } else if (sy
> ty
+ screen_size_y(s
) - 1) { /* below screen */
1143 if (!data
->rectflag
)
1144 sx
= screen_size_x(s
) - 1;
1145 sy
= screen_size_y(s
) - 1;
1148 sy
= screen_hsize(s
) + sy
;
1150 screen_set_selection(s
,
1151 sx
, sy
, data
->cx
, screen_hsize(s
) + data
->cy
, data
->rectflag
, &gc
);
1153 if (data
->rectflag
) {
1155 * Can't rely on the caller to redraw the right lines for
1156 * rectangle selection - find the highest line and the number
1157 * of lines, and redraw just past that in both directions
1161 window_copy_redraw_lines(wp
, sy
, cy
- sy
+ 1);
1163 window_copy_redraw_lines(wp
, cy
, sy
- cy
+ 1);
1170 window_copy_copy_selection(struct window_pane
*wp
, struct client
*c
)
1172 struct window_copy_mode_data
*data
= wp
->modedata
;
1173 struct screen
*s
= &data
->screen
;
1176 u_int i
, xx
, yy
, sx
, sy
, ex
, ey
, limit
;
1177 u_int firstsx
, lastex
, restex
, restsx
;
1188 * The selection extends from selx,sely to (adjusted) cx,cy on
1192 /* Find start and end. */
1194 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1195 if (yy
< data
->sely
|| (yy
== data
->sely
&& xx
< data
->selx
)) {
1197 ex
= data
->selx
; ey
= data
->sely
;
1199 sx
= data
->selx
; sy
= data
->sely
;
1203 /* Trim ex to end of line. */
1204 xx
= window_copy_find_length(wp
, ey
);
1209 * Deal with rectangle-copy if necessary; four situations: start of
1210 * first line (firstsx), end of last line (lastex), start (restsx) and
1211 * end (restex) of all other lines.
1213 xx
= screen_size_x(s
);
1214 if (data
->rectflag
) {
1216 * Need to ignore the column with the cursor in it, which for
1217 * rectangular copy means knowing which side the cursor is on.
1219 if (data
->selx
< data
->cx
) {
1220 /* Selection start is on the left. */
1223 firstsx
= data
->selx
;
1224 restsx
= data
->selx
;
1226 /* Cursor is on the left. */
1227 lastex
= data
->selx
+ 1;
1228 restex
= data
->selx
+ 1;
1229 firstsx
= data
->cx
+ 1;
1230 restsx
= data
->cx
+ 1;
1234 * Like emacs, keep the top-left-most character, and drop the
1235 * bottom-right-most, regardless of copy direction.
1243 /* Copy the lines. */
1245 window_copy_copy_line(wp
, &buf
, &off
, sy
, firstsx
, lastex
);
1247 window_copy_copy_line(wp
, &buf
, &off
, sy
, firstsx
, restex
);
1249 for (i
= sy
+ 1; i
< ey
; i
++) {
1250 window_copy_copy_line(
1251 wp
, &buf
, &off
, i
, restsx
, restex
);
1254 window_copy_copy_line(wp
, &buf
, &off
, ey
, restsx
, lastex
);
1257 /* Don't bother if no data. */
1262 off
--; /* remove final \n */
1264 /* Add the buffer to the stack. */
1265 limit
= options_get_number(&c
->session
->options
, "buffer-limit");
1266 paste_add(&c
->session
->buffers
, buf
, off
, limit
);
1270 window_copy_copy_line(struct window_pane
*wp
,
1271 char **buf
, size_t *off
, u_int sy
, u_int sx
, u_int ex
)
1273 struct window_copy_mode_data
*data
= wp
->modedata
;
1274 struct grid
*gd
= data
->backing
->grid
;
1275 const struct grid_cell
*gc
;
1276 const struct grid_utf8
*gu
;
1277 struct grid_line
*gl
;
1278 u_int i
, xx
, wrapped
= 0;
1285 * Work out if the line was wrapped at the screen edge and all of it is
1288 gl
= &gd
->linedata
[sy
];
1289 if (gl
->flags
& GRID_LINE_WRAPPED
&& gl
->cellsize
<= gd
->sx
)
1292 /* If the line was wrapped, don't strip spaces (use the full length). */
1296 xx
= window_copy_find_length(wp
, sy
);
1303 for (i
= sx
; i
< ex
; i
++) {
1304 gc
= grid_peek_cell(gd
, i
, sy
);
1305 if (gc
->flags
& GRID_FLAG_PADDING
)
1307 if (!(gc
->flags
& GRID_FLAG_UTF8
)) {
1308 *buf
= xrealloc(*buf
, 1, (*off
) + 1);
1309 (*buf
)[(*off
)++] = gc
->data
;
1311 gu
= grid_peek_utf8(gd
, i
, sy
);
1312 size
= grid_utf8_size(gu
);
1313 *buf
= xrealloc(*buf
, 1, (*off
) + size
);
1314 *off
+= grid_utf8_copy(gu
, *buf
+ *off
, size
);
1319 /* Only add a newline if the line wasn't wrapped. */
1320 if (!wrapped
|| ex
!= xx
) {
1321 *buf
= xrealloc(*buf
, 1, (*off
) + 1);
1322 (*buf
)[(*off
)++] = '\n';
1327 window_copy_clear_selection(struct window_pane
*wp
)
1329 struct window_copy_mode_data
*data
= wp
->modedata
;
1332 screen_clear_selection(&data
->screen
);
1334 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1335 px
= window_copy_find_length(wp
, py
);
1337 window_copy_update_cursor(wp
, px
, data
->cy
);
1341 window_copy_in_set(struct window_pane
*wp
, u_int px
, u_int py
, const char *set
)
1343 struct window_copy_mode_data
*data
= wp
->modedata
;
1344 const struct grid_cell
*gc
;
1346 gc
= grid_peek_cell(data
->backing
->grid
, px
, py
);
1347 if (gc
->flags
& (GRID_FLAG_PADDING
|GRID_FLAG_UTF8
))
1349 if (gc
->data
== 0x00 || gc
->data
== 0x7f)
1351 return (strchr(set
, gc
->data
) != NULL
);
1355 window_copy_find_length(struct window_pane
*wp
, u_int py
)
1357 struct window_copy_mode_data
*data
= wp
->modedata
;
1358 struct screen
*s
= data
->backing
;
1359 const struct grid_cell
*gc
;
1363 * If the pane has been resized, its grid can contain old overlong
1364 * lines. grid_peek_cell does not allow accessing cells beyond the
1365 * width of the grid, and screen_write_copy treats them as spaces, so
1366 * ignore them here too.
1368 px
= s
->grid
->linedata
[py
].cellsize
;
1369 if (px
> screen_size_x(s
))
1370 px
= screen_size_x(s
);
1372 gc
= grid_peek_cell(s
->grid
, px
- 1, py
);
1373 if (gc
->flags
& GRID_FLAG_UTF8
)
1375 if (gc
->data
!= ' ')
1383 window_copy_cursor_start_of_line(struct window_pane
*wp
)
1385 struct window_copy_mode_data
*data
= wp
->modedata
;
1387 window_copy_update_cursor(wp
, 0, data
->cy
);
1388 if (window_copy_update_selection(wp
))
1389 window_copy_redraw_lines(wp
, data
->cy
, 1);
1393 window_copy_cursor_back_to_indentation(struct window_pane
*wp
)
1395 struct window_copy_mode_data
*data
= wp
->modedata
;
1397 const struct grid_cell
*gc
;
1400 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1401 xx
= window_copy_find_length(wp
, py
);
1404 gc
= grid_peek_cell(data
->backing
->grid
, px
, py
);
1405 if (gc
->flags
& GRID_FLAG_UTF8
)
1407 if (gc
->data
!= ' ')
1412 window_copy_update_cursor(wp
, px
, data
->cy
);
1413 if (window_copy_update_selection(wp
))
1414 window_copy_redraw_lines(wp
, data
->cy
, 1);
1418 window_copy_cursor_end_of_line(struct window_pane
*wp
)
1420 struct window_copy_mode_data
*data
= wp
->modedata
;
1421 struct screen
*back_s
= data
->backing
;
1422 struct grid
*gd
= back_s
->grid
;
1425 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1426 px
= window_copy_find_length(wp
, py
);
1428 if (data
->cx
== px
) {
1429 if (data
->screen
.sel
.flag
&& data
->rectflag
)
1430 px
= screen_size_x(back_s
);
1431 if (gd
->linedata
[py
].flags
& GRID_LINE_WRAPPED
) {
1432 while (py
< gd
->sy
+ gd
->hsize
&&
1433 gd
->linedata
[py
].flags
& GRID_LINE_WRAPPED
) {
1434 window_copy_cursor_down(wp
, 0);
1435 py
= screen_hsize(back_s
)
1436 + data
->cy
- data
->oy
;
1438 px
= window_copy_find_length(wp
, py
);
1441 window_copy_update_cursor(wp
, px
, data
->cy
);
1443 if (window_copy_update_selection(wp
))
1444 window_copy_redraw_lines(wp
, data
->cy
, 1);
1448 window_copy_cursor_left(struct window_pane
*wp
)
1450 struct window_copy_mode_data
*data
= wp
->modedata
;
1452 if (data
->cx
== 0) {
1453 window_copy_cursor_up(wp
, 0);
1454 window_copy_cursor_end_of_line(wp
);
1456 window_copy_update_cursor(wp
, data
->cx
- 1, data
->cy
);
1457 if (window_copy_update_selection(wp
))
1458 window_copy_redraw_lines(wp
, data
->cy
, 1);
1463 window_copy_cursor_right(struct window_pane
*wp
)
1465 struct window_copy_mode_data
*data
= wp
->modedata
;
1468 if (data
->screen
.sel
.flag
&& data
->rectflag
)
1469 px
= screen_size_x(&data
->screen
);
1471 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1472 px
= window_copy_find_length(wp
, py
);
1475 if (data
->cx
>= px
) {
1476 window_copy_cursor_start_of_line(wp
);
1477 window_copy_cursor_down(wp
, 0);
1479 window_copy_update_cursor(wp
, data
->cx
+ 1, data
->cy
);
1480 if (window_copy_update_selection(wp
))
1481 window_copy_redraw_lines(wp
, data
->cy
, 1);
1486 window_copy_cursor_up(struct window_pane
*wp
, int scroll_only
)
1488 struct window_copy_mode_data
*data
= wp
->modedata
;
1489 struct screen
*s
= &data
->screen
;
1490 u_int ox
, oy
, px
, py
;
1492 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1493 ox
= window_copy_find_length(wp
, oy
);
1495 data
->lastcx
= data
->cx
;
1499 data
->cx
= data
->lastcx
;
1500 if (scroll_only
|| data
->cy
== 0) {
1501 window_copy_scroll_down(wp
, 1);
1503 if (data
->cy
== screen_size_y(s
) - 1)
1504 window_copy_redraw_lines(wp
, data
->cy
, 1);
1506 window_copy_redraw_lines(wp
, data
->cy
, 2);
1509 window_copy_update_cursor(wp
, data
->cx
, data
->cy
- 1);
1510 if (window_copy_update_selection(wp
)) {
1511 if (data
->cy
== screen_size_y(s
) - 1)
1512 window_copy_redraw_lines(wp
, data
->cy
, 1);
1514 window_copy_redraw_lines(wp
, data
->cy
, 2);
1518 if (!data
->screen
.sel
.flag
|| !data
->rectflag
) {
1519 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1520 px
= window_copy_find_length(wp
, py
);
1521 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
1523 window_copy_cursor_end_of_line(wp
);
1528 window_copy_cursor_down(struct window_pane
*wp
, int scroll_only
)
1530 struct window_copy_mode_data
*data
= wp
->modedata
;
1531 struct screen
*s
= &data
->screen
;
1532 u_int ox
, oy
, px
, py
;
1534 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1535 ox
= window_copy_find_length(wp
, oy
);
1537 data
->lastcx
= data
->cx
;
1541 data
->cx
= data
->lastcx
;
1542 if (scroll_only
|| data
->cy
== screen_size_y(s
) - 1) {
1543 window_copy_scroll_up(wp
, 1);
1544 if (scroll_only
&& data
->cy
> 0)
1545 window_copy_redraw_lines(wp
, data
->cy
- 1, 2);
1547 window_copy_update_cursor(wp
, data
->cx
, data
->cy
+ 1);
1548 if (window_copy_update_selection(wp
))
1549 window_copy_redraw_lines(wp
, data
->cy
- 1, 2);
1552 if (!data
->screen
.sel
.flag
|| !data
->rectflag
) {
1553 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1554 px
= window_copy_find_length(wp
, py
);
1555 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
1557 window_copy_cursor_end_of_line(wp
);
1562 window_copy_cursor_jump(struct window_pane
*wp
)
1564 struct window_copy_mode_data
*data
= wp
->modedata
;
1565 struct screen
*back_s
= data
->backing
;
1566 const struct grid_cell
*gc
;
1570 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1571 xx
= window_copy_find_length(wp
, py
);
1574 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1575 if ((gc
->flags
& (GRID_FLAG_PADDING
|GRID_FLAG_UTF8
)) == 0
1576 && gc
->data
== data
->jumpchar
) {
1578 window_copy_update_cursor(wp
, px
, data
->cy
);
1579 if (window_copy_update_selection(wp
))
1580 window_copy_redraw_lines(wp
, data
->cy
, 1);
1588 window_copy_cursor_jump_back(struct window_pane
*wp
)
1590 struct window_copy_mode_data
*data
= wp
->modedata
;
1591 struct screen
*back_s
= data
->backing
;
1592 const struct grid_cell
*gc
;
1596 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1602 gc
= grid_peek_cell(back_s
->grid
, px
, py
);
1603 if ((gc
->flags
& (GRID_FLAG_PADDING
|GRID_FLAG_UTF8
)) == 0
1604 && gc
->data
== data
->jumpchar
) {
1606 window_copy_update_cursor(wp
, px
, data
->cy
);
1607 if (window_copy_update_selection(wp
))
1608 window_copy_redraw_lines(wp
, data
->cy
, 1);
1618 window_copy_cursor_next_word(struct window_pane
*wp
, const char *separators
)
1620 struct window_copy_mode_data
*data
= wp
->modedata
;
1621 struct screen
*back_s
= data
->backing
;
1622 u_int px
, py
, xx
, yy
;
1626 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1627 xx
= window_copy_find_length(wp
, py
);
1628 yy
= screen_hsize(back_s
) + screen_size_y(back_s
) - 1;
1631 * First skip past any nonword characters and then any word characters.
1633 * expected is initially set to 0 for the former and then 1 for the
1638 window_copy_in_set(wp
, px
, py
, separators
) == expected
) {
1639 /* Move down if we're past the end of the line. */
1643 window_copy_cursor_down(wp
, 0);
1646 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1647 xx
= window_copy_find_length(wp
, py
);
1651 expected
= !expected
;
1652 } while (expected
== 1);
1654 window_copy_update_cursor(wp
, px
, data
->cy
);
1655 if (window_copy_update_selection(wp
))
1656 window_copy_redraw_lines(wp
, data
->cy
, 1);
1660 window_copy_cursor_next_word_end(struct window_pane
*wp
, const char *separators
)
1662 struct window_copy_mode_data
*data
= wp
->modedata
;
1663 struct screen
*back_s
= data
->backing
;
1664 u_int px
, py
, xx
, yy
;
1668 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1669 xx
= window_copy_find_length(wp
, py
);
1670 yy
= screen_hsize(back_s
) + screen_size_y(back_s
) - 1;
1673 * First skip past any word characters, then any nonword characters.
1675 * expected is initially set to 1 for the former and then 0 for the
1680 window_copy_in_set(wp
, px
, py
, separators
) == expected
) {
1681 /* Move down if we're past the end of the line. */
1685 window_copy_cursor_down(wp
, 0);
1688 py
= screen_hsize(back_s
) + data
->cy
- data
->oy
;
1689 xx
= window_copy_find_length(wp
, py
);
1693 expected
= !expected
;
1694 } while (expected
== 0);
1696 window_copy_update_cursor(wp
, px
, data
->cy
);
1697 if (window_copy_update_selection(wp
))
1698 window_copy_redraw_lines(wp
, data
->cy
, 1);
1701 /* Move to the previous place where a word begins. */
1703 window_copy_cursor_previous_word(struct window_pane
*wp
, const char *separators
)
1705 struct window_copy_mode_data
*data
= wp
->modedata
;
1709 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1711 /* Move back to the previous word character. */
1715 if (!window_copy_in_set(wp
, px
, py
, separators
))
1718 if (data
->cy
== 0 &&
1719 (screen_hsize(data
->backing
) == 0 ||
1720 data
->oy
>= screen_hsize(data
->backing
) - 1))
1722 window_copy_cursor_up(wp
, 0);
1724 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1725 px
= window_copy_find_length(wp
, py
);
1729 /* Move back to the beginning of this word. */
1730 while (px
> 0 && !window_copy_in_set(wp
, px
- 1, py
, separators
))
1734 window_copy_update_cursor(wp
, px
, data
->cy
);
1735 if (window_copy_update_selection(wp
))
1736 window_copy_redraw_lines(wp
, data
->cy
, 1);
1740 window_copy_scroll_up(struct window_pane
*wp
, u_int ny
)
1742 struct window_copy_mode_data
*data
= wp
->modedata
;
1743 struct screen
*s
= &data
->screen
;
1744 struct screen_write_ctx ctx
;
1752 screen_write_start(&ctx
, wp
, NULL
);
1753 screen_write_cursormove(&ctx
, 0, 0);
1754 screen_write_deleteline(&ctx
, ny
);
1755 window_copy_write_lines(wp
, &ctx
, screen_size_y(s
) - ny
, ny
);
1756 window_copy_write_line(wp
, &ctx
, 0);
1757 if (screen_size_y(s
) > 1)
1758 window_copy_write_line(wp
, &ctx
, 1);
1759 if (screen_size_y(s
) > 3)
1760 window_copy_write_line(wp
, &ctx
, screen_size_y(s
) - 2);
1761 if (s
->sel
.flag
&& screen_size_y(s
) > ny
) {
1762 window_copy_update_selection(wp
);
1763 window_copy_write_line(wp
, &ctx
, screen_size_y(s
) - ny
- 1);
1765 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1766 window_copy_update_selection(wp
);
1767 screen_write_stop(&ctx
);
1771 window_copy_scroll_down(struct window_pane
*wp
, u_int ny
)
1773 struct window_copy_mode_data
*data
= wp
->modedata
;
1774 struct screen
*s
= &data
->screen
;
1775 struct screen_write_ctx ctx
;
1777 if (ny
> screen_hsize(data
->backing
))
1780 if (data
->oy
> screen_hsize(data
->backing
) - ny
)
1781 ny
= screen_hsize(data
->backing
) - data
->oy
;
1786 screen_write_start(&ctx
, wp
, NULL
);
1787 screen_write_cursormove(&ctx
, 0, 0);
1788 screen_write_insertline(&ctx
, ny
);
1789 window_copy_write_lines(wp
, &ctx
, 0, ny
);
1790 if (s
->sel
.flag
&& screen_size_y(s
) > ny
) {
1791 window_copy_update_selection(wp
);
1792 window_copy_write_line(wp
, &ctx
, ny
);
1793 } else if (ny
== 1) /* nuke position */
1794 window_copy_write_line(wp
, &ctx
, 1);
1795 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1796 window_copy_update_selection(wp
);
1797 screen_write_stop(&ctx
);
1801 window_copy_rectangle_toggle(struct window_pane
*wp
)
1803 struct window_copy_mode_data
*data
= wp
->modedata
;
1806 data
->rectflag
= !data
->rectflag
;
1808 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1809 px
= window_copy_find_length(wp
, py
);
1811 window_copy_update_cursor(wp
, px
, data
->cy
);
1813 window_copy_update_selection(wp
);
1814 window_copy_redraw_screen(wp
);