4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
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>
29 struct window_copy_mode_data
;
31 static const char *window_copy_key_table(struct window_mode_entry
*);
32 static void window_copy_command(struct window_mode_entry
*, struct client
*,
33 struct session
*, struct winlink
*, struct args
*,
34 struct mouse_event
*);
35 static struct screen
*window_copy_init(struct window_mode_entry
*,
36 struct cmd_find_state
*, struct args
*);
37 static struct screen
*window_copy_view_init(struct window_mode_entry
*,
38 struct cmd_find_state
*, struct args
*);
39 static void window_copy_free(struct window_mode_entry
*);
40 static void window_copy_resize(struct window_mode_entry
*, u_int
, u_int
);
41 static void window_copy_formats(struct window_mode_entry
*,
42 struct format_tree
*);
43 static void window_copy_pageup1(struct window_mode_entry
*, int);
44 static int window_copy_pagedown(struct window_mode_entry
*, int, int);
45 static void window_copy_next_paragraph(struct window_mode_entry
*);
46 static void window_copy_previous_paragraph(struct window_mode_entry
*);
47 static void window_copy_redraw_selection(struct window_mode_entry
*, u_int
);
48 static void window_copy_redraw_lines(struct window_mode_entry
*, u_int
,
50 static void window_copy_redraw_screen(struct window_mode_entry
*);
51 static void window_copy_write_line(struct window_mode_entry
*,
52 struct screen_write_ctx
*, u_int
);
53 static void window_copy_write_lines(struct window_mode_entry
*,
54 struct screen_write_ctx
*, u_int
, u_int
);
55 static char *window_copy_match_at_cursor(struct window_copy_mode_data
*);
56 static void window_copy_scroll_to(struct window_mode_entry
*, u_int
, u_int
,
58 static int window_copy_search_compare(struct grid
*, u_int
, u_int
,
59 struct grid
*, u_int
, int);
60 static int window_copy_search_lr(struct grid
*, struct grid
*, u_int
*,
61 u_int
, u_int
, u_int
, int);
62 static int window_copy_search_rl(struct grid
*, struct grid
*, u_int
*,
63 u_int
, u_int
, u_int
, int);
64 static int window_copy_last_regex(struct grid
*, u_int
, u_int
, u_int
,
65 u_int
, u_int
*, u_int
*, const char *, const regex_t
*,
67 static int window_copy_search_mark_at(struct window_copy_mode_data
*,
68 u_int
, u_int
, u_int
*);
69 static char *window_copy_stringify(struct grid
*, u_int
, u_int
, u_int
,
71 static void window_copy_cstrtocellpos(struct grid
*, u_int
, u_int
*,
72 u_int
*, const char *);
73 static int window_copy_search_marks(struct window_mode_entry
*,
74 struct screen
*, int, int);
75 static void window_copy_clear_marks(struct window_mode_entry
*);
76 static int window_copy_is_lowercase(const char *);
77 static void window_copy_search_back_overlap(struct grid
*, regex_t
*,
78 u_int
*, u_int
*, u_int
*, u_int
);
79 static int window_copy_search_jump(struct window_mode_entry
*,
80 struct grid
*, struct grid
*, u_int
, u_int
, u_int
, int, int,
82 static int window_copy_search(struct window_mode_entry
*, int, int);
83 static int window_copy_search_up(struct window_mode_entry
*, int);
84 static int window_copy_search_down(struct window_mode_entry
*, int);
85 static void window_copy_goto_line(struct window_mode_entry
*, const char *);
86 static void window_copy_update_cursor(struct window_mode_entry
*, u_int
,
88 static void window_copy_start_selection(struct window_mode_entry
*);
89 static int window_copy_adjust_selection(struct window_mode_entry
*,
91 static int window_copy_set_selection(struct window_mode_entry
*, int, int);
92 static int window_copy_update_selection(struct window_mode_entry
*, int,
94 static void window_copy_synchronize_cursor(struct window_mode_entry
*, int);
95 static void *window_copy_get_selection(struct window_mode_entry
*, size_t *);
96 static void window_copy_copy_buffer(struct window_mode_entry
*,
97 const char *, void *, size_t);
98 static void window_copy_pipe(struct window_mode_entry
*,
99 struct session
*, const char *);
100 static void window_copy_copy_pipe(struct window_mode_entry
*,
101 struct session
*, const char *, const char *);
102 static void window_copy_copy_selection(struct window_mode_entry
*,
104 static void window_copy_append_selection(struct window_mode_entry
*);
105 static void window_copy_clear_selection(struct window_mode_entry
*);
106 static void window_copy_copy_line(struct window_mode_entry
*, char **,
107 size_t *, u_int
, u_int
, u_int
);
108 static int window_copy_in_set(struct window_mode_entry
*, u_int
, u_int
,
110 static u_int
window_copy_find_length(struct window_mode_entry
*, u_int
);
111 static void window_copy_cursor_start_of_line(struct window_mode_entry
*);
112 static void window_copy_cursor_back_to_indentation(
113 struct window_mode_entry
*);
114 static void window_copy_cursor_end_of_line(struct window_mode_entry
*);
115 static void window_copy_other_end(struct window_mode_entry
*);
116 static void window_copy_cursor_left(struct window_mode_entry
*);
117 static void window_copy_cursor_right(struct window_mode_entry
*, int);
118 static void window_copy_cursor_up(struct window_mode_entry
*, int);
119 static void window_copy_cursor_down(struct window_mode_entry
*, int);
120 static void window_copy_cursor_jump(struct window_mode_entry
*);
121 static void window_copy_cursor_jump_back(struct window_mode_entry
*);
122 static void window_copy_cursor_jump_to(struct window_mode_entry
*);
123 static void window_copy_cursor_jump_to_back(struct window_mode_entry
*);
124 static void window_copy_cursor_next_word(struct window_mode_entry
*,
126 static void window_copy_cursor_next_word_end_pos(struct window_mode_entry
*,
127 const char *, u_int
*, u_int
*);
128 static void window_copy_cursor_next_word_end(struct window_mode_entry
*,
130 static void window_copy_cursor_previous_word_pos(struct window_mode_entry
*,
131 const char *, u_int
*, u_int
*);
132 static void window_copy_cursor_previous_word(struct window_mode_entry
*,
134 static void window_copy_scroll_up(struct window_mode_entry
*, u_int
);
135 static void window_copy_scroll_down(struct window_mode_entry
*, u_int
);
136 static void window_copy_rectangle_set(struct window_mode_entry
*, int);
137 static void window_copy_move_mouse(struct mouse_event
*);
138 static void window_copy_drag_update(struct client
*, struct mouse_event
*);
139 static void window_copy_drag_release(struct client
*, struct mouse_event
*);
140 static void window_copy_jump_to_mark(struct window_mode_entry
*);
141 static void window_copy_acquire_cursor_up(struct window_mode_entry
*,
142 u_int
, u_int
, u_int
, u_int
, u_int
);
143 static void window_copy_acquire_cursor_down(struct window_mode_entry
*,
144 u_int
, u_int
, u_int
, u_int
, u_int
, u_int
, int);
146 const struct window_mode window_copy_mode
= {
149 .init
= window_copy_init
,
150 .free
= window_copy_free
,
151 .resize
= window_copy_resize
,
152 .key_table
= window_copy_key_table
,
153 .command
= window_copy_command
,
154 .formats
= window_copy_formats
,
157 const struct window_mode window_view_mode
= {
160 .init
= window_copy_view_init
,
161 .free
= window_copy_free
,
162 .resize
= window_copy_resize
,
163 .key_table
= window_copy_key_table
,
164 .command
= window_copy_command
,
165 .formats
= window_copy_formats
,
170 WINDOW_COPY_SEARCHUP
,
171 WINDOW_COPY_SEARCHDOWN
,
172 WINDOW_COPY_JUMPFORWARD
,
173 WINDOW_COPY_JUMPBACKWARD
,
174 WINDOW_COPY_JUMPTOFORWARD
,
175 WINDOW_COPY_JUMPTOBACKWARD
,
179 WINDOW_COPY_REL_POS_ABOVE
,
180 WINDOW_COPY_REL_POS_ON_SCREEN
,
181 WINDOW_COPY_REL_POS_BELOW
,
184 enum window_copy_cmd_action
{
185 WINDOW_COPY_CMD_NOTHING
,
186 WINDOW_COPY_CMD_REDRAW
,
187 WINDOW_COPY_CMD_CANCEL
,
190 enum window_copy_cmd_clear
{
191 WINDOW_COPY_CMD_CLEAR_ALWAYS
,
192 WINDOW_COPY_CMD_CLEAR_NEVER
,
193 WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
196 struct window_copy_cmd_state
{
197 struct window_mode_entry
*wme
;
199 struct mouse_event
*m
;
207 * Copy mode's visible screen (the "screen" field) is filled from one of two
208 * sources: the original contents of the pane (used when we actually enter via
209 * the "copy-mode" command, to copy the contents of the current pane), or else
210 * a series of lines containing the output from an output-writing tmux command
211 * (such as any of the "show-*" or "list-*" commands).
213 * In either case, the full content of the copy-mode grid is pointed at by the
214 * "backing" field, and is copied into "screen" as needed (that is, when
215 * scrolling occurs). When copy-mode is backed by a pane, backing points
216 * directly at that pane's screen structure (&wp->base); when backed by a list
217 * of output-lines from a command, it points at a newly-allocated screen
218 * structure (which is deallocated when the mode ends).
220 struct window_copy_mode_data
{
221 struct screen screen
;
223 struct screen
*backing
;
224 int backing_written
; /* backing display started */
225 struct screen
*writing
;
226 struct input_ctx
*ictx
;
228 int viewmode
; /* view mode entered */
230 u_int oy
; /* number of lines scrolled up */
232 u_int selx
; /* beginning of selection */
235 u_int endselx
; /* end of selection */
239 CURSORDRAG_NONE
, /* selection is independent of cursor */
240 CURSORDRAG_ENDSEL
, /* end is synchronized with cursor */
241 CURSORDRAG_SEL
, /* start is synchronized with cursor */
249 } lineflag
; /* line selection mode */
250 int rectflag
; /* in rectangle copy mode? */
251 int scroll_exit
; /* exit on scroll to end? */
252 int hide_position
; /* hide position marker */
255 SEL_CHAR
, /* select one char at a time */
256 SEL_WORD
, /* select one word at a time */
257 SEL_LINE
, /* select one line at a time */
260 const char *separators
; /* word separators */
262 u_int dx
; /* drag start position */
265 u_int selrx
; /* selection reset positions */
273 u_int lastcx
; /* position in last line w/ content */
274 u_int lastsx
; /* size of last line w/ content */
276 u_int mx
; /* mark position */
293 int timeout
; /* search has timed out */
294 #define WINDOW_COPY_SEARCH_TIMEOUT 10000
295 #define WINDOW_COPY_SEARCH_ALL_TIMEOUT 200
298 struct utf8_data
*jumpchar
;
300 struct event dragtimer
;
301 #define WINDOW_COPY_DRAG_REPEAT_TIME 50000
305 window_copy_scroll_timer(__unused
int fd
, __unused
short events
, void *arg
)
307 struct window_mode_entry
*wme
= arg
;
308 struct window_pane
*wp
= wme
->wp
;
309 struct window_copy_mode_data
*data
= wme
->data
;
310 struct timeval tv
= {
311 .tv_usec
= WINDOW_COPY_DRAG_REPEAT_TIME
314 evtimer_del(&data
->dragtimer
);
316 if (TAILQ_FIRST(&wp
->modes
) != wme
)
320 evtimer_add(&data
->dragtimer
, &tv
);
321 window_copy_cursor_up(wme
, 1);
322 } else if (data
->cy
== screen_size_y(&data
->screen
) - 1) {
323 evtimer_add(&data
->dragtimer
, &tv
);
324 window_copy_cursor_down(wme
, 1);
328 static struct screen
*
329 window_copy_clone_screen(struct screen
*src
, struct screen
*hint
, u_int
*cx
,
333 const struct grid_line
*gl
;
337 dst
= xcalloc(1, sizeof *dst
);
339 sy
= screen_hsize(src
) + screen_size_y(src
);
341 while (sy
> screen_hsize(src
)) {
342 gl
= grid_peek_line(src
->grid
, sy
- 1);
343 if (gl
->cellused
!= 0)
348 log_debug("%s: target screen is %ux%u, source %ux%u", __func__
,
349 screen_size_x(src
), sy
, screen_size_x(hint
),
350 screen_hsize(src
) + screen_size_y(src
));
351 screen_init(dst
, screen_size_x(src
), sy
, screen_hlimit(src
));
354 * Ensure history is on for the backing grid so lines are not deleted
357 dst
->grid
->flags
|= GRID_HISTORY
;
358 grid_duplicate_lines(dst
->grid
, 0, src
->grid
, 0, sy
);
360 dst
->grid
->sy
= sy
- screen_hsize(src
);
361 dst
->grid
->hsize
= screen_hsize(src
);
362 dst
->grid
->hscrolled
= src
->grid
->hscrolled
;
363 if (src
->cy
> dst
->grid
->sy
- 1) {
365 dst
->cy
= dst
->grid
->sy
- 1;
371 if (cx
!= NULL
&& cy
!= NULL
) {
373 *cy
= screen_hsize(dst
) + dst
->cy
;
374 reflow
= (screen_size_x(hint
) != screen_size_x(dst
));
379 grid_wrap_position(dst
->grid
, *cx
, *cy
, &wx
, &wy
);
380 screen_resize_cursor(dst
, screen_size_x(hint
), screen_size_y(hint
), 1,
383 grid_unwrap_position(dst
->grid
, cx
, cy
, wx
, wy
);
388 static struct window_copy_mode_data
*
389 window_copy_common_init(struct window_mode_entry
*wme
)
391 struct window_pane
*wp
= wme
->wp
;
392 struct window_copy_mode_data
*data
;
393 struct screen
*base
= &wp
->base
;
395 wme
->data
= data
= xcalloc(1, sizeof *data
);
397 data
->cursordrag
= CURSORDRAG_NONE
;
398 data
->lineflag
= LINE_SEL_NONE
;
399 data
->selflag
= SEL_CHAR
;
401 if (wp
->searchstr
!= NULL
) {
402 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
403 data
->searchregex
= wp
->searchregex
;
404 data
->searchstr
= xstrdup(wp
->searchstr
);
406 data
->searchtype
= WINDOW_COPY_OFF
;
407 data
->searchregex
= 0;
408 data
->searchstr
= NULL
;
410 data
->searchx
= data
->searchy
= data
->searcho
= -1;
413 data
->jumptype
= WINDOW_COPY_OFF
;
414 data
->jumpchar
= NULL
;
416 screen_init(&data
->screen
, screen_size_x(base
), screen_size_y(base
), 0);
417 data
->modekeys
= options_get_number(wp
->window
->options
, "mode-keys");
419 evtimer_set(&data
->dragtimer
, window_copy_scroll_timer
, wme
);
424 static struct screen
*
425 window_copy_init(struct window_mode_entry
*wme
,
426 __unused
struct cmd_find_state
*fs
, struct args
*args
)
428 struct window_pane
*wp
= wme
->swp
;
429 struct window_copy_mode_data
*data
;
430 struct screen
*base
= &wp
->base
;
431 struct screen_write_ctx ctx
;
434 data
= window_copy_common_init(wme
);
435 data
->backing
= window_copy_clone_screen(base
, &data
->screen
, &cx
, &cy
,
436 wme
->swp
!= wme
->wp
);
439 if (cy
< screen_hsize(data
->backing
)) {
441 data
->oy
= screen_hsize(data
->backing
) - cy
;
443 data
->cy
= cy
- screen_hsize(data
->backing
);
447 data
->scroll_exit
= args_has(args
, 'e');
448 data
->hide_position
= args_has(args
, 'H');
450 data
->screen
.cx
= data
->cx
;
451 data
->screen
.cy
= data
->cy
;
453 data
->my
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
456 screen_write_start(&ctx
, &data
->screen
);
457 for (i
= 0; i
< screen_size_y(&data
->screen
); i
++)
458 window_copy_write_line(wme
, &ctx
, i
);
459 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
460 screen_write_stop(&ctx
);
462 return (&data
->screen
);
465 static struct screen
*
466 window_copy_view_init(struct window_mode_entry
*wme
,
467 __unused
struct cmd_find_state
*fs
, __unused
struct args
*args
)
469 struct window_pane
*wp
= wme
->wp
;
470 struct window_copy_mode_data
*data
;
471 struct screen
*base
= &wp
->base
;
472 u_int sx
= screen_size_x(base
);
474 data
= window_copy_common_init(wme
);
477 data
->backing
= xmalloc(sizeof *data
->backing
);
478 screen_init(data
->backing
, sx
, screen_size_y(base
), UINT_MAX
);
479 data
->writing
= xmalloc(sizeof *data
->writing
);
480 screen_init(data
->writing
, sx
, screen_size_y(base
), 0);
481 data
->ictx
= input_init(NULL
, NULL
, NULL
);
483 data
->my
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
486 return (&data
->screen
);
490 window_copy_free(struct window_mode_entry
*wme
)
492 struct window_copy_mode_data
*data
= wme
->data
;
494 evtimer_del(&data
->dragtimer
);
496 free(data
->searchmark
);
497 free(data
->searchstr
);
498 free(data
->jumpchar
);
500 if (data
->writing
!= NULL
) {
501 screen_free(data
->writing
);
504 if (data
->ictx
!= NULL
)
505 input_free(data
->ictx
);
506 screen_free(data
->backing
);
509 screen_free(&data
->screen
);
514 window_copy_add(struct window_pane
*wp
, int parse
, const char *fmt
, ...)
519 window_copy_vadd(wp
, parse
, fmt
, ap
);
524 window_copy_init_ctx_cb(__unused
struct screen_write_ctx
*ctx
,
525 struct tty_ctx
*ttyctx
)
527 memcpy(&ttyctx
->defaults
, &grid_default_cell
, sizeof ttyctx
->defaults
);
528 ttyctx
->palette
= NULL
;
529 ttyctx
->redraw_cb
= NULL
;
530 ttyctx
->set_client_cb
= NULL
;
535 window_copy_vadd(struct window_pane
*wp
, int parse
, const char *fmt
, va_list ap
)
537 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
538 struct window_copy_mode_data
*data
= wme
->data
;
539 struct screen
*backing
= data
->backing
;
540 struct screen
*writing
= data
->writing
;
541 struct screen_write_ctx writing_ctx
, backing_ctx
, ctx
;
543 u_int old_hsize
, old_cy
;
544 u_int sx
= screen_size_x(backing
);
548 vasprintf(&text
, fmt
, ap
);
549 screen_write_start(&writing_ctx
, writing
);
550 screen_write_reset(&writing_ctx
);
551 input_parse_screen(data
->ictx
, writing
, window_copy_init_ctx_cb
,
552 data
, text
, strlen(text
));
556 old_hsize
= screen_hsize(data
->backing
);
557 screen_write_start(&backing_ctx
, backing
);
558 if (data
->backing_written
) {
560 * On the second or later line, do a CRLF before writing
561 * (so it's on a new line).
563 screen_write_carriagereturn(&backing_ctx
);
564 screen_write_linefeed(&backing_ctx
, 0, 8);
566 data
->backing_written
= 1;
567 old_cy
= backing
->cy
;
569 screen_write_fast_copy(&backing_ctx
, writing
, 0, 0, sx
, 1);
571 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
572 screen_write_vnputs(&backing_ctx
, 0, &gc
, fmt
, ap
);
574 screen_write_stop(&backing_ctx
);
576 data
->oy
+= screen_hsize(data
->backing
) - old_hsize
;
578 screen_write_start_pane(&ctx
, wp
, &data
->screen
);
581 * If the history has changed, draw the top line.
582 * (If there's any history at all, it has changed.)
584 if (screen_hsize(data
->backing
))
585 window_copy_redraw_lines(wme
, 0, 1);
587 /* Write the new lines. */
588 window_copy_redraw_lines(wme
, old_cy
, backing
->cy
- old_cy
+ 1);
590 screen_write_stop(&ctx
);
594 window_copy_pageup(struct window_pane
*wp
, int half_page
)
596 window_copy_pageup1(TAILQ_FIRST(&wp
->modes
), half_page
);
600 window_copy_pageup1(struct window_mode_entry
*wme
, int half_page
)
602 struct window_copy_mode_data
*data
= wme
->data
;
603 struct screen
*s
= &data
->screen
;
604 u_int n
, ox
, oy
, px
, py
;
606 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
607 ox
= window_copy_find_length(wme
, oy
);
609 if (data
->cx
!= ox
) {
610 data
->lastcx
= data
->cx
;
613 data
->cx
= data
->lastcx
;
616 if (screen_size_y(s
) > 2) {
618 n
= screen_size_y(s
) / 2;
620 n
= screen_size_y(s
) - 2;
623 if (data
->oy
+ n
> screen_hsize(data
->backing
)) {
624 data
->oy
= screen_hsize(data
->backing
);
632 if (data
->screen
.sel
== NULL
|| !data
->rectflag
) {
633 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
634 px
= window_copy_find_length(wme
, py
);
635 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
637 window_copy_cursor_end_of_line(wme
);
640 if (data
->searchmark
!= NULL
&& !data
->timeout
)
641 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
642 window_copy_update_selection(wme
, 1, 0);
643 window_copy_redraw_screen(wme
);
647 window_copy_pagedown(struct window_mode_entry
*wme
, int half_page
,
650 struct window_copy_mode_data
*data
= wme
->data
;
651 struct screen
*s
= &data
->screen
;
652 u_int n
, ox
, oy
, px
, py
;
654 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
655 ox
= window_copy_find_length(wme
, oy
);
657 if (data
->cx
!= ox
) {
658 data
->lastcx
= data
->cx
;
661 data
->cx
= data
->lastcx
;
664 if (screen_size_y(s
) > 2) {
666 n
= screen_size_y(s
) / 2;
668 n
= screen_size_y(s
) - 2;
673 if (data
->cy
+ (n
- data
->oy
) >= screen_size_y(data
->backing
))
674 data
->cy
= screen_size_y(data
->backing
) - 1;
676 data
->cy
+= n
- data
->oy
;
680 if (data
->screen
.sel
== NULL
|| !data
->rectflag
) {
681 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
682 px
= window_copy_find_length(wme
, py
);
683 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
685 window_copy_cursor_end_of_line(wme
);
688 if (scroll_exit
&& data
->oy
== 0)
690 if (data
->searchmark
!= NULL
&& !data
->timeout
)
691 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
692 window_copy_update_selection(wme
, 1, 0);
693 window_copy_redraw_screen(wme
);
698 window_copy_previous_paragraph(struct window_mode_entry
*wme
)
700 struct window_copy_mode_data
*data
= wme
->data
;
703 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
705 while (oy
> 0 && window_copy_find_length(wme
, oy
) == 0)
708 while (oy
> 0 && window_copy_find_length(wme
, oy
) > 0)
711 window_copy_scroll_to(wme
, 0, oy
, 0);
715 window_copy_next_paragraph(struct window_mode_entry
*wme
)
717 struct window_copy_mode_data
*data
= wme
->data
;
718 struct screen
*s
= &data
->screen
;
721 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
722 maxy
= screen_hsize(data
->backing
) + screen_size_y(s
) - 1;
724 while (oy
< maxy
&& window_copy_find_length(wme
, oy
) == 0)
727 while (oy
< maxy
&& window_copy_find_length(wme
, oy
) > 0)
730 ox
= window_copy_find_length(wme
, oy
);
731 window_copy_scroll_to(wme
, ox
, oy
, 0);
735 window_copy_get_word(struct window_pane
*wp
, u_int x
, u_int y
)
737 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
738 struct window_copy_mode_data
*data
= wme
->data
;
739 struct grid
*gd
= data
->screen
.grid
;
741 return (format_grid_word(gd
, x
, gd
->hsize
+ y
));
745 window_copy_get_line(struct window_pane
*wp
, u_int y
)
747 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
748 struct window_copy_mode_data
*data
= wme
->data
;
749 struct grid
*gd
= data
->screen
.grid
;
751 return (format_grid_line(gd
, gd
->hsize
+ y
));
755 window_copy_cursor_word_cb(struct format_tree
*ft
)
757 struct window_pane
*wp
= format_get_pane(ft
);
758 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
759 struct window_copy_mode_data
*data
= wme
->data
;
761 return (window_copy_get_word(wp
, data
->cx
, data
->cy
));
765 window_copy_cursor_line_cb(struct format_tree
*ft
)
767 struct window_pane
*wp
= format_get_pane(ft
);
768 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
769 struct window_copy_mode_data
*data
= wme
->data
;
771 return (window_copy_get_line(wp
, data
->cy
));
775 window_copy_search_match_cb(struct format_tree
*ft
)
777 struct window_pane
*wp
= format_get_pane(ft
);
778 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
779 struct window_copy_mode_data
*data
= wme
->data
;
781 return (window_copy_match_at_cursor(data
));
785 window_copy_formats(struct window_mode_entry
*wme
, struct format_tree
*ft
)
787 struct window_copy_mode_data
*data
= wme
->data
;
789 format_add(ft
, "scroll_position", "%d", data
->oy
);
790 format_add(ft
, "rectangle_toggle", "%d", data
->rectflag
);
792 format_add(ft
, "copy_cursor_x", "%d", data
->cx
);
793 format_add(ft
, "copy_cursor_y", "%d", data
->cy
);
795 format_add(ft
, "selection_present", "%d", data
->screen
.sel
!= NULL
);
796 if (data
->screen
.sel
!= NULL
) {
797 format_add(ft
, "selection_start_x", "%d", data
->selx
);
798 format_add(ft
, "selection_start_y", "%d", data
->sely
);
799 format_add(ft
, "selection_end_x", "%d", data
->endselx
);
800 format_add(ft
, "selection_end_y", "%d", data
->endsely
);
801 format_add(ft
, "selection_active", "%d",
802 data
->cursordrag
!= CURSORDRAG_NONE
);
804 format_add(ft
, "selection_active", "%d", 0);
806 format_add(ft
, "search_present", "%d", data
->searchmark
!= NULL
);
807 format_add_cb(ft
, "search_match", window_copy_search_match_cb
);
809 format_add_cb(ft
, "copy_cursor_word", window_copy_cursor_word_cb
);
810 format_add_cb(ft
, "copy_cursor_line", window_copy_cursor_line_cb
);
814 window_copy_size_changed(struct window_mode_entry
*wme
)
816 struct window_copy_mode_data
*data
= wme
->data
;
817 struct screen
*s
= &data
->screen
;
818 struct screen_write_ctx ctx
;
819 int search
= (data
->searchmark
!= NULL
);
821 window_copy_clear_selection(wme
);
822 window_copy_clear_marks(wme
);
824 screen_write_start(&ctx
, s
);
825 window_copy_write_lines(wme
, &ctx
, 0, screen_size_y(s
));
826 screen_write_stop(&ctx
);
828 if (search
&& !data
->timeout
)
829 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 0);
830 data
->searchx
= data
->cx
;
831 data
->searchy
= data
->cy
;
832 data
->searcho
= data
->oy
;
836 window_copy_resize(struct window_mode_entry
*wme
, u_int sx
, u_int sy
)
838 struct window_copy_mode_data
*data
= wme
->data
;
839 struct screen
*s
= &data
->screen
;
840 struct grid
*gd
= data
->backing
->grid
;
841 u_int cx
, cy
, wx
, wy
;
844 screen_resize(s
, sx
, sy
, 0);
846 cy
= gd
->hsize
+ data
->cy
- data
->oy
;
847 reflow
= (gd
->sx
!= sx
);
849 grid_wrap_position(gd
, cx
, cy
, &wx
, &wy
);
850 screen_resize_cursor(data
->backing
, sx
, sy
, 1, 0, 0);
852 grid_unwrap_position(gd
, &cx
, &cy
, wx
, wy
);
855 if (cy
< gd
->hsize
) {
857 data
->oy
= gd
->hsize
- cy
;
859 data
->cy
= cy
- gd
->hsize
;
863 window_copy_size_changed(wme
);
864 window_copy_redraw_screen(wme
);
868 window_copy_key_table(struct window_mode_entry
*wme
)
870 struct window_pane
*wp
= wme
->wp
;
872 if (options_get_number(wp
->window
->options
, "mode-keys") == MODEKEY_VI
)
873 return ("copy-mode-vi");
874 return ("copy-mode");
878 window_copy_expand_search_string(struct window_copy_cmd_state
*cs
)
880 struct window_mode_entry
*wme
= cs
->wme
;
881 struct window_copy_mode_data
*data
= wme
->data
;
882 const char *ss
= args_string(cs
->args
, 1);
885 if (ss
== NULL
|| *ss
== '\0')
888 if (args_has(cs
->args
, 'F')) {
889 expanded
= format_single(NULL
, ss
, NULL
, NULL
, NULL
, wme
->wp
);
890 if (*expanded
== '\0') {
894 free(data
->searchstr
);
895 data
->searchstr
= expanded
;
897 free(data
->searchstr
);
898 data
->searchstr
= xstrdup(ss
);
903 static enum window_copy_cmd_action
904 window_copy_cmd_append_selection(struct window_copy_cmd_state
*cs
)
906 struct window_mode_entry
*wme
= cs
->wme
;
907 struct session
*s
= cs
->s
;
910 window_copy_append_selection(wme
);
911 window_copy_clear_selection(wme
);
912 return (WINDOW_COPY_CMD_REDRAW
);
915 static enum window_copy_cmd_action
916 window_copy_cmd_append_selection_and_cancel(struct window_copy_cmd_state
*cs
)
918 struct window_mode_entry
*wme
= cs
->wme
;
919 struct session
*s
= cs
->s
;
922 window_copy_append_selection(wme
);
923 window_copy_clear_selection(wme
);
924 return (WINDOW_COPY_CMD_CANCEL
);
927 static enum window_copy_cmd_action
928 window_copy_cmd_back_to_indentation(struct window_copy_cmd_state
*cs
)
930 struct window_mode_entry
*wme
= cs
->wme
;
932 window_copy_cursor_back_to_indentation(wme
);
933 return (WINDOW_COPY_CMD_NOTHING
);
936 static enum window_copy_cmd_action
937 window_copy_cmd_begin_selection(struct window_copy_cmd_state
*cs
)
939 struct window_mode_entry
*wme
= cs
->wme
;
940 struct client
*c
= cs
->c
;
941 struct mouse_event
*m
= cs
->m
;
942 struct window_copy_mode_data
*data
= wme
->data
;
945 window_copy_start_drag(c
, m
);
946 return (WINDOW_COPY_CMD_NOTHING
);
949 data
->lineflag
= LINE_SEL_NONE
;
950 data
->selflag
= SEL_CHAR
;
951 window_copy_start_selection(wme
);
952 return (WINDOW_COPY_CMD_REDRAW
);
955 static enum window_copy_cmd_action
956 window_copy_cmd_stop_selection(struct window_copy_cmd_state
*cs
)
958 struct window_mode_entry
*wme
= cs
->wme
;
959 struct window_copy_mode_data
*data
= wme
->data
;
961 data
->cursordrag
= CURSORDRAG_NONE
;
962 data
->lineflag
= LINE_SEL_NONE
;
963 data
->selflag
= SEL_CHAR
;
964 return (WINDOW_COPY_CMD_NOTHING
);
967 static enum window_copy_cmd_action
968 window_copy_cmd_bottom_line(struct window_copy_cmd_state
*cs
)
970 struct window_mode_entry
*wme
= cs
->wme
;
971 struct window_copy_mode_data
*data
= wme
->data
;
974 data
->cy
= screen_size_y(&data
->screen
) - 1;
976 window_copy_update_selection(wme
, 1, 0);
977 return (WINDOW_COPY_CMD_REDRAW
);
980 static enum window_copy_cmd_action
981 window_copy_cmd_cancel(__unused
struct window_copy_cmd_state
*cs
)
983 return (WINDOW_COPY_CMD_CANCEL
);
986 static enum window_copy_cmd_action
987 window_copy_cmd_clear_selection(struct window_copy_cmd_state
*cs
)
989 struct window_mode_entry
*wme
= cs
->wme
;
991 window_copy_clear_selection(wme
);
992 return (WINDOW_COPY_CMD_REDRAW
);
995 static enum window_copy_cmd_action
996 window_copy_do_copy_end_of_line(struct window_copy_cmd_state
*cs
, int pipe
,
999 struct window_mode_entry
*wme
= cs
->wme
;
1000 struct client
*c
= cs
->c
;
1001 struct session
*s
= cs
->s
;
1002 struct winlink
*wl
= cs
->wl
;
1003 struct window_pane
*wp
= wme
->wp
;
1004 u_int count
= args_count(cs
->args
);
1005 u_int np
= wme
->prefix
, ocx
, ocy
, ooy
;
1006 struct window_copy_mode_data
*data
= wme
->data
;
1007 char *prefix
= NULL
, *command
= NULL
;
1008 const char *arg1
= args_string(cs
->args
, 1);
1009 const char *arg2
= args_string(cs
->args
, 2);
1013 prefix
= format_single(NULL
, arg2
, c
, s
, wl
, wp
);
1014 if (s
!= NULL
&& count
> 1 && *arg1
!= '\0')
1015 command
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1018 prefix
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1025 window_copy_start_selection(wme
);
1026 for (; np
> 1; np
--)
1027 window_copy_cursor_down(wme
, 0);
1028 window_copy_cursor_end_of_line(wme
);
1032 window_copy_copy_pipe(wme
, s
, prefix
, command
);
1034 window_copy_copy_selection(wme
, prefix
);
1039 return (WINDOW_COPY_CMD_CANCEL
);
1042 window_copy_clear_selection(wme
);
1050 return (WINDOW_COPY_CMD_REDRAW
);
1053 static enum window_copy_cmd_action
1054 window_copy_cmd_copy_end_of_line(struct window_copy_cmd_state
*cs
)
1056 return (window_copy_do_copy_end_of_line(cs
, 0, 0));
1059 static enum window_copy_cmd_action
1060 window_copy_cmd_copy_end_of_line_and_cancel(struct window_copy_cmd_state
*cs
)
1062 return (window_copy_do_copy_end_of_line(cs
, 0, 1));
1065 static enum window_copy_cmd_action
1066 window_copy_cmd_copy_pipe_end_of_line(struct window_copy_cmd_state
*cs
)
1068 return (window_copy_do_copy_end_of_line(cs
, 1, 0));
1071 static enum window_copy_cmd_action
1072 window_copy_cmd_copy_pipe_end_of_line_and_cancel(
1073 struct window_copy_cmd_state
*cs
)
1075 return (window_copy_do_copy_end_of_line(cs
, 1, 1));
1078 static enum window_copy_cmd_action
1079 window_copy_do_copy_line(struct window_copy_cmd_state
*cs
, int pipe
, int cancel
)
1081 struct window_mode_entry
*wme
= cs
->wme
;
1082 struct client
*c
= cs
->c
;
1083 struct session
*s
= cs
->s
;
1084 struct winlink
*wl
= cs
->wl
;
1085 struct window_pane
*wp
= wme
->wp
;
1086 struct window_copy_mode_data
*data
= wme
->data
;
1087 u_int count
= args_count(cs
->args
);
1088 u_int np
= wme
->prefix
, ocx
, ocy
, ooy
;
1089 char *prefix
= NULL
, *command
= NULL
;
1090 const char *arg1
= args_string(cs
->args
, 1);
1091 const char *arg2
= args_string(cs
->args
, 2);
1095 prefix
= format_single(NULL
, arg2
, c
, s
, wl
, wp
);
1096 if (s
!= NULL
&& count
> 1 && *arg1
!= '\0')
1097 command
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1100 prefix
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1107 data
->selflag
= SEL_CHAR
;
1108 window_copy_cursor_start_of_line(wme
);
1109 window_copy_start_selection(wme
);
1110 for (; np
> 1; np
--)
1111 window_copy_cursor_down(wme
, 0);
1112 window_copy_cursor_end_of_line(wme
);
1116 window_copy_copy_pipe(wme
, s
, prefix
, command
);
1118 window_copy_copy_selection(wme
, prefix
);
1123 return (WINDOW_COPY_CMD_CANCEL
);
1126 window_copy_clear_selection(wme
);
1134 return (WINDOW_COPY_CMD_REDRAW
);
1137 static enum window_copy_cmd_action
1138 window_copy_cmd_copy_line(struct window_copy_cmd_state
*cs
)
1140 return (window_copy_do_copy_line(cs
, 0, 0));
1143 static enum window_copy_cmd_action
1144 window_copy_cmd_copy_line_and_cancel(struct window_copy_cmd_state
*cs
)
1146 return (window_copy_do_copy_line(cs
, 0, 1));
1149 static enum window_copy_cmd_action
1150 window_copy_cmd_copy_pipe_line(struct window_copy_cmd_state
*cs
)
1152 return (window_copy_do_copy_line(cs
, 1, 0));
1155 static enum window_copy_cmd_action
1156 window_copy_cmd_copy_pipe_line_and_cancel(struct window_copy_cmd_state
*cs
)
1158 return (window_copy_do_copy_line(cs
, 1, 1));
1161 static enum window_copy_cmd_action
1162 window_copy_cmd_copy_selection_no_clear(struct window_copy_cmd_state
*cs
)
1164 struct window_mode_entry
*wme
= cs
->wme
;
1165 struct client
*c
= cs
->c
;
1166 struct session
*s
= cs
->s
;
1167 struct winlink
*wl
= cs
->wl
;
1168 struct window_pane
*wp
= wme
->wp
;
1169 char *prefix
= NULL
;
1170 const char *arg1
= args_string(cs
->args
, 1);
1173 prefix
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1176 window_copy_copy_selection(wme
, prefix
);
1179 return (WINDOW_COPY_CMD_NOTHING
);
1182 static enum window_copy_cmd_action
1183 window_copy_cmd_copy_selection(struct window_copy_cmd_state
*cs
)
1185 struct window_mode_entry
*wme
= cs
->wme
;
1187 window_copy_cmd_copy_selection_no_clear(cs
);
1188 window_copy_clear_selection(wme
);
1189 return (WINDOW_COPY_CMD_REDRAW
);
1192 static enum window_copy_cmd_action
1193 window_copy_cmd_copy_selection_and_cancel(struct window_copy_cmd_state
*cs
)
1195 struct window_mode_entry
*wme
= cs
->wme
;
1197 window_copy_cmd_copy_selection_no_clear(cs
);
1198 window_copy_clear_selection(wme
);
1199 return (WINDOW_COPY_CMD_CANCEL
);
1202 static enum window_copy_cmd_action
1203 window_copy_cmd_cursor_down(struct window_copy_cmd_state
*cs
)
1205 struct window_mode_entry
*wme
= cs
->wme
;
1206 u_int np
= wme
->prefix
;
1208 for (; np
!= 0; np
--)
1209 window_copy_cursor_down(wme
, 0);
1210 return (WINDOW_COPY_CMD_NOTHING
);
1213 static enum window_copy_cmd_action
1214 window_copy_cmd_cursor_down_and_cancel(struct window_copy_cmd_state
*cs
)
1216 struct window_mode_entry
*wme
= cs
->wme
;
1217 struct window_copy_mode_data
*data
= wme
->data
;
1218 u_int np
= wme
->prefix
, cy
;
1221 for (; np
!= 0; np
--)
1222 window_copy_cursor_down(wme
, 0);
1223 if (cy
== data
->cy
&& data
->oy
== 0)
1224 return (WINDOW_COPY_CMD_CANCEL
);
1225 return (WINDOW_COPY_CMD_NOTHING
);
1228 static enum window_copy_cmd_action
1229 window_copy_cmd_cursor_left(struct window_copy_cmd_state
*cs
)
1231 struct window_mode_entry
*wme
= cs
->wme
;
1232 u_int np
= wme
->prefix
;
1234 for (; np
!= 0; np
--)
1235 window_copy_cursor_left(wme
);
1236 return (WINDOW_COPY_CMD_NOTHING
);
1239 static enum window_copy_cmd_action
1240 window_copy_cmd_cursor_right(struct window_copy_cmd_state
*cs
)
1242 struct window_mode_entry
*wme
= cs
->wme
;
1243 struct window_copy_mode_data
*data
= wme
->data
;
1244 u_int np
= wme
->prefix
;
1246 for (; np
!= 0; np
--) {
1247 window_copy_cursor_right(wme
, data
->screen
.sel
!= NULL
&&
1250 return (WINDOW_COPY_CMD_NOTHING
);
1253 static enum window_copy_cmd_action
1254 window_copy_cmd_cursor_up(struct window_copy_cmd_state
*cs
)
1256 struct window_mode_entry
*wme
= cs
->wme
;
1257 u_int np
= wme
->prefix
;
1259 for (; np
!= 0; np
--)
1260 window_copy_cursor_up(wme
, 0);
1261 return (WINDOW_COPY_CMD_NOTHING
);
1264 static enum window_copy_cmd_action
1265 window_copy_cmd_end_of_line(struct window_copy_cmd_state
*cs
)
1267 struct window_mode_entry
*wme
= cs
->wme
;
1269 window_copy_cursor_end_of_line(wme
);
1270 return (WINDOW_COPY_CMD_NOTHING
);
1273 static enum window_copy_cmd_action
1274 window_copy_cmd_halfpage_down(struct window_copy_cmd_state
*cs
)
1276 struct window_mode_entry
*wme
= cs
->wme
;
1277 struct window_copy_mode_data
*data
= wme
->data
;
1278 u_int np
= wme
->prefix
;
1280 for (; np
!= 0; np
--) {
1281 if (window_copy_pagedown(wme
, 1, data
->scroll_exit
))
1282 return (WINDOW_COPY_CMD_CANCEL
);
1284 return (WINDOW_COPY_CMD_NOTHING
);
1287 static enum window_copy_cmd_action
1288 window_copy_cmd_halfpage_down_and_cancel(struct window_copy_cmd_state
*cs
)
1291 struct window_mode_entry
*wme
= cs
->wme
;
1292 u_int np
= wme
->prefix
;
1294 for (; np
!= 0; np
--) {
1295 if (window_copy_pagedown(wme
, 1, 1))
1296 return (WINDOW_COPY_CMD_CANCEL
);
1298 return (WINDOW_COPY_CMD_NOTHING
);
1301 static enum window_copy_cmd_action
1302 window_copy_cmd_halfpage_up(struct window_copy_cmd_state
*cs
)
1304 struct window_mode_entry
*wme
= cs
->wme
;
1305 u_int np
= wme
->prefix
;
1307 for (; np
!= 0; np
--)
1308 window_copy_pageup1(wme
, 1);
1309 return (WINDOW_COPY_CMD_NOTHING
);
1312 static enum window_copy_cmd_action
1313 window_copy_cmd_toggle_position(struct window_copy_cmd_state
*cs
)
1315 struct window_mode_entry
*wme
= cs
->wme
;
1316 struct window_copy_mode_data
*data
= wme
->data
;
1318 data
->hide_position
= !data
->hide_position
;
1319 return (WINDOW_COPY_CMD_REDRAW
);
1322 static enum window_copy_cmd_action
1323 window_copy_cmd_history_bottom(struct window_copy_cmd_state
*cs
)
1325 struct window_mode_entry
*wme
= cs
->wme
;
1326 struct window_copy_mode_data
*data
= wme
->data
;
1327 struct screen
*s
= data
->backing
;
1330 oy
= screen_hsize(s
) + data
->cy
- data
->oy
;
1331 if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
&& oy
== data
->endsely
)
1332 window_copy_other_end(wme
);
1334 data
->cy
= screen_size_y(&data
->screen
) - 1;
1335 data
->cx
= window_copy_find_length(wme
, screen_hsize(s
) + data
->cy
);
1338 if (data
->searchmark
!= NULL
&& !data
->timeout
)
1339 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
1340 window_copy_update_selection(wme
, 1, 0);
1341 return (WINDOW_COPY_CMD_REDRAW
);
1344 static enum window_copy_cmd_action
1345 window_copy_cmd_history_top(struct window_copy_cmd_state
*cs
)
1347 struct window_mode_entry
*wme
= cs
->wme
;
1348 struct window_copy_mode_data
*data
= wme
->data
;
1351 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1352 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
&& oy
== data
->sely
)
1353 window_copy_other_end(wme
);
1357 data
->oy
= screen_hsize(data
->backing
);
1359 if (data
->searchmark
!= NULL
&& !data
->timeout
)
1360 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
1361 window_copy_update_selection(wme
, 1, 0);
1362 return (WINDOW_COPY_CMD_REDRAW
);
1365 static enum window_copy_cmd_action
1366 window_copy_cmd_jump_again(struct window_copy_cmd_state
*cs
)
1368 struct window_mode_entry
*wme
= cs
->wme
;
1369 struct window_copy_mode_data
*data
= wme
->data
;
1370 u_int np
= wme
->prefix
;
1372 switch (data
->jumptype
) {
1373 case WINDOW_COPY_JUMPFORWARD
:
1374 for (; np
!= 0; np
--)
1375 window_copy_cursor_jump(wme
);
1377 case WINDOW_COPY_JUMPBACKWARD
:
1378 for (; np
!= 0; np
--)
1379 window_copy_cursor_jump_back(wme
);
1381 case WINDOW_COPY_JUMPTOFORWARD
:
1382 for (; np
!= 0; np
--)
1383 window_copy_cursor_jump_to(wme
);
1385 case WINDOW_COPY_JUMPTOBACKWARD
:
1386 for (; np
!= 0; np
--)
1387 window_copy_cursor_jump_to_back(wme
);
1390 return (WINDOW_COPY_CMD_NOTHING
);
1393 static enum window_copy_cmd_action
1394 window_copy_cmd_jump_reverse(struct window_copy_cmd_state
*cs
)
1396 struct window_mode_entry
*wme
= cs
->wme
;
1397 struct window_copy_mode_data
*data
= wme
->data
;
1398 u_int np
= wme
->prefix
;
1400 switch (data
->jumptype
) {
1401 case WINDOW_COPY_JUMPFORWARD
:
1402 for (; np
!= 0; np
--)
1403 window_copy_cursor_jump_back(wme
);
1405 case WINDOW_COPY_JUMPBACKWARD
:
1406 for (; np
!= 0; np
--)
1407 window_copy_cursor_jump(wme
);
1409 case WINDOW_COPY_JUMPTOFORWARD
:
1410 for (; np
!= 0; np
--)
1411 window_copy_cursor_jump_to_back(wme
);
1413 case WINDOW_COPY_JUMPTOBACKWARD
:
1414 for (; np
!= 0; np
--)
1415 window_copy_cursor_jump_to(wme
);
1418 return (WINDOW_COPY_CMD_NOTHING
);
1421 static enum window_copy_cmd_action
1422 window_copy_cmd_middle_line(struct window_copy_cmd_state
*cs
)
1424 struct window_mode_entry
*wme
= cs
->wme
;
1425 struct window_copy_mode_data
*data
= wme
->data
;
1428 data
->cy
= (screen_size_y(&data
->screen
) - 1) / 2;
1430 window_copy_update_selection(wme
, 1, 0);
1431 return (WINDOW_COPY_CMD_REDRAW
);
1434 static enum window_copy_cmd_action
1435 window_copy_cmd_previous_matching_bracket(struct window_copy_cmd_state
*cs
)
1437 struct window_mode_entry
*wme
= cs
->wme
;
1438 u_int np
= wme
->prefix
;
1439 struct window_copy_mode_data
*data
= wme
->data
;
1440 struct screen
*s
= data
->backing
;
1441 char open
[] = "{[(", close
[] = "}])";
1442 char tried
, found
, start
, *cp
;
1443 u_int px
, py
, xx
, n
;
1444 struct grid_cell gc
;
1447 for (; np
!= 0; np
--) {
1448 /* Get cursor position and line length. */
1450 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1451 xx
= window_copy_find_length(wme
, py
);
1456 * Get the current character. If not on a bracket, try the
1457 * previous. If still not, then behave like previous-word.
1461 grid_get_cell(s
->grid
, px
, py
, &gc
);
1462 if (gc
.data
.size
!= 1 || (gc
.flags
& GRID_FLAG_PADDING
))
1465 found
= *gc
.data
.data
;
1466 cp
= strchr(close
, found
);
1469 if (data
->modekeys
== MODEKEY_EMACS
) {
1470 if (!tried
&& px
> 0) {
1475 window_copy_cursor_previous_word(wme
, close
, 1);
1479 start
= open
[cp
- close
];
1481 /* Walk backward until the matching bracket is reached. */
1492 xx
= window_copy_find_length(wme
, py
);
1493 } while (xx
== 0 && py
> 0);
1494 if (xx
== 0 && py
== 0) {
1502 grid_get_cell(s
->grid
, px
, py
, &gc
);
1503 if (gc
.data
.size
== 1 &&
1504 (~gc
.flags
& GRID_FLAG_PADDING
)) {
1505 if (*gc
.data
.data
== found
)
1507 else if (*gc
.data
.data
== start
)
1512 /* Move the cursor to the found location if any. */
1514 window_copy_scroll_to(wme
, px
, py
, 0);
1517 return (WINDOW_COPY_CMD_NOTHING
);
1520 static enum window_copy_cmd_action
1521 window_copy_cmd_next_matching_bracket(struct window_copy_cmd_state
*cs
)
1523 struct window_mode_entry
*wme
= cs
->wme
;
1524 u_int np
= wme
->prefix
;
1525 struct window_copy_mode_data
*data
= wme
->data
;
1526 struct screen
*s
= data
->backing
;
1527 char open
[] = "{[(", close
[] = "}])";
1528 char tried
, found
, end
, *cp
;
1529 u_int px
, py
, xx
, yy
, sx
, sy
, n
;
1530 struct grid_cell gc
;
1532 struct grid_line
*gl
;
1534 for (; np
!= 0; np
--) {
1535 /* Get cursor position and line length. */
1537 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1538 xx
= window_copy_find_length(wme
, py
);
1539 yy
= screen_hsize(s
) + screen_size_y(s
) - 1;
1544 * Get the current character. If not on a bracket, try the
1545 * next. If still not, then behave like next-word.
1549 grid_get_cell(s
->grid
, px
, py
, &gc
);
1550 if (gc
.data
.size
!= 1 || (gc
.flags
& GRID_FLAG_PADDING
))
1553 found
= *gc
.data
.data
;
1556 * In vi mode, attempt to move to previous bracket if a
1557 * closing bracket is found first. If this fails,
1558 * return to the original cursor position.
1560 cp
= strchr(close
, found
);
1561 if (cp
!= NULL
&& data
->modekeys
== MODEKEY_VI
) {
1563 sy
= screen_hsize(s
) + data
->cy
- data
->oy
;
1565 window_copy_scroll_to(wme
, px
, py
, 0);
1566 window_copy_cmd_previous_matching_bracket(cs
);
1569 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1570 grid_get_cell(s
->grid
, px
, py
, &gc
);
1571 if (gc
.data
.size
== 1 &&
1572 (~gc
.flags
& GRID_FLAG_PADDING
) &&
1573 strchr(close
, *gc
.data
.data
) != NULL
)
1574 window_copy_scroll_to(wme
, sx
, sy
, 0);
1578 cp
= strchr(open
, found
);
1581 if (data
->modekeys
== MODEKEY_EMACS
) {
1582 if (!tried
&& px
<= xx
) {
1587 window_copy_cursor_next_word_end(wme
, open
, 0);
1590 /* For vi, continue searching for bracket until EOL. */
1594 gl
= grid_get_line(s
->grid
, py
);
1595 if (~gl
->flags
& GRID_LINE_WRAPPED
)
1597 if (gl
->cellsize
> s
->grid
->sx
)
1601 xx
= window_copy_find_length(wme
, py
);
1606 end
= close
[cp
- open
];
1608 /* Walk forward until the matching bracket is reached. */
1619 xx
= window_copy_find_length(wme
, py
);
1623 grid_get_cell(s
->grid
, px
, py
, &gc
);
1624 if (gc
.data
.size
== 1 &&
1625 (~gc
.flags
& GRID_FLAG_PADDING
)) {
1626 if (*gc
.data
.data
== found
)
1628 else if (*gc
.data
.data
== end
)
1633 /* Move the cursor to the found location if any. */
1635 window_copy_scroll_to(wme
, px
, py
, 0);
1638 return (WINDOW_COPY_CMD_NOTHING
);
1641 static enum window_copy_cmd_action
1642 window_copy_cmd_next_paragraph(struct window_copy_cmd_state
*cs
)
1644 struct window_mode_entry
*wme
= cs
->wme
;
1645 u_int np
= wme
->prefix
;
1647 for (; np
!= 0; np
--)
1648 window_copy_next_paragraph(wme
);
1649 return (WINDOW_COPY_CMD_NOTHING
);
1652 static enum window_copy_cmd_action
1653 window_copy_cmd_next_space(struct window_copy_cmd_state
*cs
)
1655 struct window_mode_entry
*wme
= cs
->wme
;
1656 u_int np
= wme
->prefix
;
1658 for (; np
!= 0; np
--)
1659 window_copy_cursor_next_word(wme
, "");
1660 return (WINDOW_COPY_CMD_NOTHING
);
1663 static enum window_copy_cmd_action
1664 window_copy_cmd_next_space_end(struct window_copy_cmd_state
*cs
)
1666 struct window_mode_entry
*wme
= cs
->wme
;
1667 u_int np
= wme
->prefix
;
1669 for (; np
!= 0; np
--)
1670 window_copy_cursor_next_word_end(wme
, "", 0);
1671 return (WINDOW_COPY_CMD_NOTHING
);
1674 static enum window_copy_cmd_action
1675 window_copy_cmd_next_word(struct window_copy_cmd_state
*cs
)
1677 struct window_mode_entry
*wme
= cs
->wme
;
1678 u_int np
= wme
->prefix
;
1679 const char *separators
;
1681 separators
= options_get_string(cs
->s
->options
, "word-separators");
1683 for (; np
!= 0; np
--)
1684 window_copy_cursor_next_word(wme
, separators
);
1685 return (WINDOW_COPY_CMD_NOTHING
);
1688 static enum window_copy_cmd_action
1689 window_copy_cmd_next_word_end(struct window_copy_cmd_state
*cs
)
1691 struct window_mode_entry
*wme
= cs
->wme
;
1692 u_int np
= wme
->prefix
;
1693 const char *separators
;
1695 separators
= options_get_string(cs
->s
->options
, "word-separators");
1697 for (; np
!= 0; np
--)
1698 window_copy_cursor_next_word_end(wme
, separators
, 0);
1699 return (WINDOW_COPY_CMD_NOTHING
);
1702 static enum window_copy_cmd_action
1703 window_copy_cmd_other_end(struct window_copy_cmd_state
*cs
)
1705 struct window_mode_entry
*wme
= cs
->wme
;
1706 u_int np
= wme
->prefix
;
1707 struct window_copy_mode_data
*data
= wme
->data
;
1709 data
->selflag
= SEL_CHAR
;
1711 window_copy_other_end(wme
);
1712 return (WINDOW_COPY_CMD_NOTHING
);
1715 static enum window_copy_cmd_action
1716 window_copy_cmd_page_down(struct window_copy_cmd_state
*cs
)
1718 struct window_mode_entry
*wme
= cs
->wme
;
1719 struct window_copy_mode_data
*data
= wme
->data
;
1720 u_int np
= wme
->prefix
;
1722 for (; np
!= 0; np
--) {
1723 if (window_copy_pagedown(wme
, 0, data
->scroll_exit
))
1724 return (WINDOW_COPY_CMD_CANCEL
);
1726 return (WINDOW_COPY_CMD_NOTHING
);
1729 static enum window_copy_cmd_action
1730 window_copy_cmd_page_down_and_cancel(struct window_copy_cmd_state
*cs
)
1732 struct window_mode_entry
*wme
= cs
->wme
;
1733 u_int np
= wme
->prefix
;
1735 for (; np
!= 0; np
--) {
1736 if (window_copy_pagedown(wme
, 0, 1))
1737 return (WINDOW_COPY_CMD_CANCEL
);
1739 return (WINDOW_COPY_CMD_NOTHING
);
1742 static enum window_copy_cmd_action
1743 window_copy_cmd_page_up(struct window_copy_cmd_state
*cs
)
1745 struct window_mode_entry
*wme
= cs
->wme
;
1746 u_int np
= wme
->prefix
;
1748 for (; np
!= 0; np
--)
1749 window_copy_pageup1(wme
, 0);
1750 return (WINDOW_COPY_CMD_NOTHING
);
1753 static enum window_copy_cmd_action
1754 window_copy_cmd_previous_paragraph(struct window_copy_cmd_state
*cs
)
1756 struct window_mode_entry
*wme
= cs
->wme
;
1757 u_int np
= wme
->prefix
;
1759 for (; np
!= 0; np
--)
1760 window_copy_previous_paragraph(wme
);
1761 return (WINDOW_COPY_CMD_NOTHING
);
1764 static enum window_copy_cmd_action
1765 window_copy_cmd_previous_space(struct window_copy_cmd_state
*cs
)
1767 struct window_mode_entry
*wme
= cs
->wme
;
1768 u_int np
= wme
->prefix
;
1770 for (; np
!= 0; np
--)
1771 window_copy_cursor_previous_word(wme
, "", 1);
1772 return (WINDOW_COPY_CMD_NOTHING
);
1775 static enum window_copy_cmd_action
1776 window_copy_cmd_previous_word(struct window_copy_cmd_state
*cs
)
1778 struct window_mode_entry
*wme
= cs
->wme
;
1779 u_int np
= wme
->prefix
;
1780 const char *separators
;
1782 separators
= options_get_string(cs
->s
->options
, "word-separators");
1784 for (; np
!= 0; np
--)
1785 window_copy_cursor_previous_word(wme
, separators
, 1);
1786 return (WINDOW_COPY_CMD_NOTHING
);
1789 static enum window_copy_cmd_action
1790 window_copy_cmd_rectangle_on(struct window_copy_cmd_state
*cs
)
1792 struct window_mode_entry
*wme
= cs
->wme
;
1793 struct window_copy_mode_data
*data
= wme
->data
;
1795 data
->lineflag
= LINE_SEL_NONE
;
1796 window_copy_rectangle_set(wme
, 1);
1798 return (WINDOW_COPY_CMD_NOTHING
);
1801 static enum window_copy_cmd_action
1802 window_copy_cmd_rectangle_off(struct window_copy_cmd_state
*cs
)
1804 struct window_mode_entry
*wme
= cs
->wme
;
1805 struct window_copy_mode_data
*data
= wme
->data
;
1807 data
->lineflag
= LINE_SEL_NONE
;
1808 window_copy_rectangle_set(wme
, 0);
1810 return (WINDOW_COPY_CMD_NOTHING
);
1813 static enum window_copy_cmd_action
1814 window_copy_cmd_rectangle_toggle(struct window_copy_cmd_state
*cs
)
1816 struct window_mode_entry
*wme
= cs
->wme
;
1817 struct window_copy_mode_data
*data
= wme
->data
;
1819 data
->lineflag
= LINE_SEL_NONE
;
1820 window_copy_rectangle_set(wme
, !data
->rectflag
);
1822 return (WINDOW_COPY_CMD_NOTHING
);
1825 static enum window_copy_cmd_action
1826 window_copy_cmd_scroll_down(struct window_copy_cmd_state
*cs
)
1828 struct window_mode_entry
*wme
= cs
->wme
;
1829 struct window_copy_mode_data
*data
= wme
->data
;
1830 u_int np
= wme
->prefix
;
1832 for (; np
!= 0; np
--)
1833 window_copy_cursor_down(wme
, 1);
1834 if (data
->scroll_exit
&& data
->oy
== 0)
1835 return (WINDOW_COPY_CMD_CANCEL
);
1836 return (WINDOW_COPY_CMD_NOTHING
);
1839 static enum window_copy_cmd_action
1840 window_copy_cmd_scroll_down_and_cancel(struct window_copy_cmd_state
*cs
)
1842 struct window_mode_entry
*wme
= cs
->wme
;
1843 struct window_copy_mode_data
*data
= wme
->data
;
1844 u_int np
= wme
->prefix
;
1846 for (; np
!= 0; np
--)
1847 window_copy_cursor_down(wme
, 1);
1849 return (WINDOW_COPY_CMD_CANCEL
);
1850 return (WINDOW_COPY_CMD_NOTHING
);
1853 static enum window_copy_cmd_action
1854 window_copy_cmd_scroll_up(struct window_copy_cmd_state
*cs
)
1856 struct window_mode_entry
*wme
= cs
->wme
;
1857 u_int np
= wme
->prefix
;
1859 for (; np
!= 0; np
--)
1860 window_copy_cursor_up(wme
, 1);
1861 return (WINDOW_COPY_CMD_NOTHING
);
1864 static enum window_copy_cmd_action
1865 window_copy_cmd_search_again(struct window_copy_cmd_state
*cs
)
1867 struct window_mode_entry
*wme
= cs
->wme
;
1868 struct window_copy_mode_data
*data
= wme
->data
;
1869 u_int np
= wme
->prefix
;
1871 if (data
->searchtype
== WINDOW_COPY_SEARCHUP
) {
1872 for (; np
!= 0; np
--)
1873 window_copy_search_up(wme
, data
->searchregex
);
1874 } else if (data
->searchtype
== WINDOW_COPY_SEARCHDOWN
) {
1875 for (; np
!= 0; np
--)
1876 window_copy_search_down(wme
, data
->searchregex
);
1878 return (WINDOW_COPY_CMD_NOTHING
);
1881 static enum window_copy_cmd_action
1882 window_copy_cmd_search_reverse(struct window_copy_cmd_state
*cs
)
1884 struct window_mode_entry
*wme
= cs
->wme
;
1885 struct window_copy_mode_data
*data
= wme
->data
;
1886 u_int np
= wme
->prefix
;
1888 if (data
->searchtype
== WINDOW_COPY_SEARCHUP
) {
1889 for (; np
!= 0; np
--)
1890 window_copy_search_down(wme
, data
->searchregex
);
1891 } else if (data
->searchtype
== WINDOW_COPY_SEARCHDOWN
) {
1892 for (; np
!= 0; np
--)
1893 window_copy_search_up(wme
, data
->searchregex
);
1895 return (WINDOW_COPY_CMD_NOTHING
);
1898 static enum window_copy_cmd_action
1899 window_copy_cmd_select_line(struct window_copy_cmd_state
*cs
)
1901 struct window_mode_entry
*wme
= cs
->wme
;
1902 struct window_copy_mode_data
*data
= wme
->data
;
1903 u_int np
= wme
->prefix
;
1905 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
1907 data
->selflag
= SEL_LINE
;
1908 data
->dx
= data
->cx
;
1909 data
->dy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1911 window_copy_cursor_start_of_line(wme
);
1912 data
->selrx
= data
->cx
;
1913 data
->selry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1914 data
->endselry
= data
->selry
;
1915 window_copy_start_selection(wme
);
1916 window_copy_cursor_end_of_line(wme
);
1917 data
->endselry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1918 data
->endselrx
= window_copy_find_length(wme
, data
->endselry
);
1919 for (; np
> 1; np
--) {
1920 window_copy_cursor_down(wme
, 0);
1921 window_copy_cursor_end_of_line(wme
);
1924 return (WINDOW_COPY_CMD_REDRAW
);
1927 static enum window_copy_cmd_action
1928 window_copy_cmd_select_word(struct window_copy_cmd_state
*cs
)
1930 struct window_mode_entry
*wme
= cs
->wme
;
1931 struct options
*session_options
= cs
->s
->options
;
1932 struct window_copy_mode_data
*data
= wme
->data
;
1933 u_int px
, py
, nextx
, nexty
;
1935 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
1937 data
->selflag
= SEL_WORD
;
1938 data
->dx
= data
->cx
;
1939 data
->dy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1941 data
->separators
= options_get_string(session_options
,
1943 window_copy_cursor_previous_word(wme
, data
->separators
, 0);
1945 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1948 window_copy_start_selection(wme
);
1950 /* Handle single character words. */
1953 if (grid_get_line(data
->backing
->grid
, nexty
)->flags
&
1954 GRID_LINE_WRAPPED
&& nextx
> screen_size_x(data
->backing
) - 1) {
1958 if (px
>= window_copy_find_length(wme
, py
) ||
1959 !window_copy_in_set(wme
, nextx
, nexty
, WHITESPACE
))
1960 window_copy_cursor_next_word_end(wme
, data
->separators
, 1);
1962 window_copy_update_cursor(wme
, px
, data
->cy
);
1963 if (window_copy_update_selection(wme
, 1, 1))
1964 window_copy_redraw_lines(wme
, data
->cy
, 1);
1966 data
->endselrx
= data
->cx
;
1967 data
->endselry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1968 if (data
->dy
> data
->endselry
) {
1969 data
->dy
= data
->endselry
;
1970 data
->dx
= data
->endselrx
;
1971 } else if (data
->dx
> data
->endselrx
)
1972 data
->dx
= data
->endselrx
;
1974 return (WINDOW_COPY_CMD_REDRAW
);
1977 static enum window_copy_cmd_action
1978 window_copy_cmd_set_mark(struct window_copy_cmd_state
*cs
)
1980 struct window_copy_mode_data
*data
= cs
->wme
->data
;
1982 data
->mx
= data
->cx
;
1983 data
->my
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1985 return (WINDOW_COPY_CMD_REDRAW
);
1988 static enum window_copy_cmd_action
1989 window_copy_cmd_start_of_line(struct window_copy_cmd_state
*cs
)
1991 struct window_mode_entry
*wme
= cs
->wme
;
1993 window_copy_cursor_start_of_line(wme
);
1994 return (WINDOW_COPY_CMD_NOTHING
);
1997 static enum window_copy_cmd_action
1998 window_copy_cmd_top_line(struct window_copy_cmd_state
*cs
)
2000 struct window_mode_entry
*wme
= cs
->wme
;
2001 struct window_copy_mode_data
*data
= wme
->data
;
2006 window_copy_update_selection(wme
, 1, 0);
2007 return (WINDOW_COPY_CMD_REDRAW
);
2010 static enum window_copy_cmd_action
2011 window_copy_cmd_copy_pipe_no_clear(struct window_copy_cmd_state
*cs
)
2013 struct window_mode_entry
*wme
= cs
->wme
;
2014 struct client
*c
= cs
->c
;
2015 struct session
*s
= cs
->s
;
2016 struct winlink
*wl
= cs
->wl
;
2017 struct window_pane
*wp
= wme
->wp
;
2018 char *command
= NULL
, *prefix
= NULL
;
2019 const char *arg1
= args_string(cs
->args
, 1);
2020 const char *arg2
= args_string(cs
->args
, 2);
2023 prefix
= format_single(NULL
, arg2
, c
, s
, wl
, wp
);
2025 if (s
!= NULL
&& arg1
!= NULL
&& *arg1
!= '\0')
2026 command
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
2027 window_copy_copy_pipe(wme
, s
, prefix
, command
);
2031 return (WINDOW_COPY_CMD_NOTHING
);
2034 static enum window_copy_cmd_action
2035 window_copy_cmd_copy_pipe(struct window_copy_cmd_state
*cs
)
2037 struct window_mode_entry
*wme
= cs
->wme
;
2039 window_copy_cmd_copy_pipe_no_clear(cs
);
2040 window_copy_clear_selection(wme
);
2041 return (WINDOW_COPY_CMD_REDRAW
);
2044 static enum window_copy_cmd_action
2045 window_copy_cmd_copy_pipe_and_cancel(struct window_copy_cmd_state
*cs
)
2047 struct window_mode_entry
*wme
= cs
->wme
;
2049 window_copy_cmd_copy_pipe_no_clear(cs
);
2050 window_copy_clear_selection(wme
);
2051 return (WINDOW_COPY_CMD_CANCEL
);
2054 static enum window_copy_cmd_action
2055 window_copy_cmd_pipe_no_clear(struct window_copy_cmd_state
*cs
)
2057 struct window_mode_entry
*wme
= cs
->wme
;
2058 struct client
*c
= cs
->c
;
2059 struct session
*s
= cs
->s
;
2060 struct winlink
*wl
= cs
->wl
;
2061 struct window_pane
*wp
= wme
->wp
;
2062 char *command
= NULL
;
2063 const char *arg1
= args_string(cs
->args
, 1);
2065 if (s
!= NULL
&& arg1
!= NULL
&& *arg1
!= '\0')
2066 command
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
2067 window_copy_pipe(wme
, s
, command
);
2070 return (WINDOW_COPY_CMD_NOTHING
);
2073 static enum window_copy_cmd_action
2074 window_copy_cmd_pipe(struct window_copy_cmd_state
*cs
)
2076 struct window_mode_entry
*wme
= cs
->wme
;
2078 window_copy_cmd_pipe_no_clear(cs
);
2079 window_copy_clear_selection(wme
);
2080 return (WINDOW_COPY_CMD_REDRAW
);
2083 static enum window_copy_cmd_action
2084 window_copy_cmd_pipe_and_cancel(struct window_copy_cmd_state
*cs
)
2086 struct window_mode_entry
*wme
= cs
->wme
;
2088 window_copy_cmd_pipe_no_clear(cs
);
2089 window_copy_clear_selection(wme
);
2090 return (WINDOW_COPY_CMD_CANCEL
);
2093 static enum window_copy_cmd_action
2094 window_copy_cmd_goto_line(struct window_copy_cmd_state
*cs
)
2096 struct window_mode_entry
*wme
= cs
->wme
;
2097 const char *arg1
= args_string(cs
->args
, 1);
2100 window_copy_goto_line(wme
, arg1
);
2101 return (WINDOW_COPY_CMD_NOTHING
);
2104 static enum window_copy_cmd_action
2105 window_copy_cmd_jump_backward(struct window_copy_cmd_state
*cs
)
2107 struct window_mode_entry
*wme
= cs
->wme
;
2108 struct window_copy_mode_data
*data
= wme
->data
;
2109 u_int np
= wme
->prefix
;
2110 const char *arg1
= args_string(cs
->args
, 1);
2112 if (*arg1
!= '\0') {
2113 data
->jumptype
= WINDOW_COPY_JUMPBACKWARD
;
2114 free(data
->jumpchar
);
2115 data
->jumpchar
= utf8_fromcstr(arg1
);
2116 for (; np
!= 0; np
--)
2117 window_copy_cursor_jump_back(wme
);
2119 return (WINDOW_COPY_CMD_NOTHING
);
2122 static enum window_copy_cmd_action
2123 window_copy_cmd_jump_forward(struct window_copy_cmd_state
*cs
)
2125 struct window_mode_entry
*wme
= cs
->wme
;
2126 struct window_copy_mode_data
*data
= wme
->data
;
2127 u_int np
= wme
->prefix
;
2128 const char *arg1
= args_string(cs
->args
, 1);
2130 if (*arg1
!= '\0') {
2131 data
->jumptype
= WINDOW_COPY_JUMPFORWARD
;
2132 free(data
->jumpchar
);
2133 data
->jumpchar
= utf8_fromcstr(arg1
);
2134 for (; np
!= 0; np
--)
2135 window_copy_cursor_jump(wme
);
2137 return (WINDOW_COPY_CMD_NOTHING
);
2140 static enum window_copy_cmd_action
2141 window_copy_cmd_jump_to_backward(struct window_copy_cmd_state
*cs
)
2143 struct window_mode_entry
*wme
= cs
->wme
;
2144 struct window_copy_mode_data
*data
= wme
->data
;
2145 u_int np
= wme
->prefix
;
2146 const char *arg1
= args_string(cs
->args
, 1);
2148 if (*arg1
!= '\0') {
2149 data
->jumptype
= WINDOW_COPY_JUMPTOBACKWARD
;
2150 free(data
->jumpchar
);
2151 data
->jumpchar
= utf8_fromcstr(arg1
);
2152 for (; np
!= 0; np
--)
2153 window_copy_cursor_jump_to_back(wme
);
2155 return (WINDOW_COPY_CMD_NOTHING
);
2158 static enum window_copy_cmd_action
2159 window_copy_cmd_jump_to_forward(struct window_copy_cmd_state
*cs
)
2161 struct window_mode_entry
*wme
= cs
->wme
;
2162 struct window_copy_mode_data
*data
= wme
->data
;
2163 u_int np
= wme
->prefix
;
2164 const char *arg1
= args_string(cs
->args
, 1);
2166 if (*arg1
!= '\0') {
2167 data
->jumptype
= WINDOW_COPY_JUMPTOFORWARD
;
2168 free(data
->jumpchar
);
2169 data
->jumpchar
= utf8_fromcstr(arg1
);
2170 for (; np
!= 0; np
--)
2171 window_copy_cursor_jump_to(wme
);
2173 return (WINDOW_COPY_CMD_NOTHING
);
2176 static enum window_copy_cmd_action
2177 window_copy_cmd_jump_to_mark(struct window_copy_cmd_state
*cs
)
2179 struct window_mode_entry
*wme
= cs
->wme
;
2181 window_copy_jump_to_mark(wme
);
2182 return (WINDOW_COPY_CMD_NOTHING
);
2185 static enum window_copy_cmd_action
2186 window_copy_cmd_search_backward(struct window_copy_cmd_state
*cs
)
2188 struct window_mode_entry
*wme
= cs
->wme
;
2189 struct window_copy_mode_data
*data
= wme
->data
;
2190 u_int np
= wme
->prefix
;
2192 if (!window_copy_expand_search_string(cs
))
2193 return (WINDOW_COPY_CMD_NOTHING
);
2195 if (data
->searchstr
!= NULL
) {
2196 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2197 data
->searchregex
= 1;
2199 for (; np
!= 0; np
--)
2200 window_copy_search_up(wme
, 1);
2202 return (WINDOW_COPY_CMD_NOTHING
);
2205 static enum window_copy_cmd_action
2206 window_copy_cmd_search_backward_text(struct window_copy_cmd_state
*cs
)
2208 struct window_mode_entry
*wme
= cs
->wme
;
2209 struct window_copy_mode_data
*data
= wme
->data
;
2210 u_int np
= wme
->prefix
;
2212 if (!window_copy_expand_search_string(cs
))
2213 return (WINDOW_COPY_CMD_NOTHING
);
2215 if (data
->searchstr
!= NULL
) {
2216 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2217 data
->searchregex
= 0;
2219 for (; np
!= 0; np
--)
2220 window_copy_search_up(wme
, 0);
2222 return (WINDOW_COPY_CMD_NOTHING
);
2225 static enum window_copy_cmd_action
2226 window_copy_cmd_search_forward(struct window_copy_cmd_state
*cs
)
2228 struct window_mode_entry
*wme
= cs
->wme
;
2229 struct window_copy_mode_data
*data
= wme
->data
;
2230 u_int np
= wme
->prefix
;
2232 if (!window_copy_expand_search_string(cs
))
2233 return (WINDOW_COPY_CMD_NOTHING
);
2235 if (data
->searchstr
!= NULL
) {
2236 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2237 data
->searchregex
= 1;
2239 for (; np
!= 0; np
--)
2240 window_copy_search_down(wme
, 1);
2242 return (WINDOW_COPY_CMD_NOTHING
);
2245 static enum window_copy_cmd_action
2246 window_copy_cmd_search_forward_text(struct window_copy_cmd_state
*cs
)
2248 struct window_mode_entry
*wme
= cs
->wme
;
2249 struct window_copy_mode_data
*data
= wme
->data
;
2250 u_int np
= wme
->prefix
;
2252 if (!window_copy_expand_search_string(cs
))
2253 return (WINDOW_COPY_CMD_NOTHING
);
2255 if (data
->searchstr
!= NULL
) {
2256 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2257 data
->searchregex
= 0;
2259 for (; np
!= 0; np
--)
2260 window_copy_search_down(wme
, 0);
2262 return (WINDOW_COPY_CMD_NOTHING
);
2265 static enum window_copy_cmd_action
2266 window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state
*cs
)
2268 struct window_mode_entry
*wme
= cs
->wme
;
2269 struct window_copy_mode_data
*data
= wme
->data
;
2270 const char *arg1
= args_string(cs
->args
, 1);
2271 const char *ss
= data
->searchstr
;
2273 enum window_copy_cmd_action action
= WINDOW_COPY_CMD_NOTHING
;
2277 log_debug("%s: %s", __func__
, arg1
);
2280 if (data
->searchx
== -1 || data
->searchy
== -1) {
2281 data
->searchx
= data
->cx
;
2282 data
->searchy
= data
->cy
;
2283 data
->searcho
= data
->oy
;
2284 } else if (ss
!= NULL
&& strcmp(arg1
, ss
) != 0) {
2285 data
->cx
= data
->searchx
;
2286 data
->cy
= data
->searchy
;
2287 data
->oy
= data
->searcho
;
2288 action
= WINDOW_COPY_CMD_REDRAW
;
2290 if (*arg1
== '\0') {
2291 window_copy_clear_marks(wme
);
2292 return (WINDOW_COPY_CMD_REDRAW
);
2297 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2298 data
->searchregex
= 0;
2299 free(data
->searchstr
);
2300 data
->searchstr
= xstrdup(arg1
);
2301 if (!window_copy_search_up(wme
, 0)) {
2302 window_copy_clear_marks(wme
);
2303 return (WINDOW_COPY_CMD_REDRAW
);
2307 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2308 data
->searchregex
= 0;
2309 free(data
->searchstr
);
2310 data
->searchstr
= xstrdup(arg1
);
2311 if (!window_copy_search_down(wme
, 0)) {
2312 window_copy_clear_marks(wme
);
2313 return (WINDOW_COPY_CMD_REDRAW
);
2320 static enum window_copy_cmd_action
2321 window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state
*cs
)
2323 struct window_mode_entry
*wme
= cs
->wme
;
2324 struct window_copy_mode_data
*data
= wme
->data
;
2325 const char *arg1
= args_string(cs
->args
, 1);
2326 const char *ss
= data
->searchstr
;
2328 enum window_copy_cmd_action action
= WINDOW_COPY_CMD_NOTHING
;
2332 log_debug("%s: %s", __func__
, arg1
);
2335 if (data
->searchx
== -1 || data
->searchy
== -1) {
2336 data
->searchx
= data
->cx
;
2337 data
->searchy
= data
->cy
;
2338 data
->searcho
= data
->oy
;
2339 } else if (ss
!= NULL
&& strcmp(arg1
, ss
) != 0) {
2340 data
->cx
= data
->searchx
;
2341 data
->cy
= data
->searchy
;
2342 data
->oy
= data
->searcho
;
2343 action
= WINDOW_COPY_CMD_REDRAW
;
2345 if (*arg1
== '\0') {
2346 window_copy_clear_marks(wme
);
2347 return (WINDOW_COPY_CMD_REDRAW
);
2352 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2353 data
->searchregex
= 0;
2354 free(data
->searchstr
);
2355 data
->searchstr
= xstrdup(arg1
);
2356 if (!window_copy_search_down(wme
, 0)) {
2357 window_copy_clear_marks(wme
);
2358 return (WINDOW_COPY_CMD_REDRAW
);
2362 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2363 data
->searchregex
= 0;
2364 free(data
->searchstr
);
2365 data
->searchstr
= xstrdup(arg1
);
2366 if (!window_copy_search_up(wme
, 0)) {
2367 window_copy_clear_marks(wme
);
2368 return (WINDOW_COPY_CMD_REDRAW
);
2374 static enum window_copy_cmd_action
2375 window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state
*cs
)
2377 struct window_mode_entry
*wme
= cs
->wme
;
2378 struct window_pane
*wp
= wme
->swp
;
2379 struct window_copy_mode_data
*data
= wme
->data
;
2382 return (WINDOW_COPY_CMD_NOTHING
);
2384 screen_free(data
->backing
);
2385 free(data
->backing
);
2386 data
->backing
= window_copy_clone_screen(&wp
->base
, &data
->screen
, NULL
, NULL
, wme
->swp
!= wme
->wp
);
2388 window_copy_size_changed(wme
);
2389 return (WINDOW_COPY_CMD_REDRAW
);
2392 static const struct {
2393 const char *command
;
2396 enum window_copy_cmd_clear clear
;
2397 enum window_copy_cmd_action (*f
)(struct window_copy_cmd_state
*);
2398 } window_copy_cmd_table
[] = {
2399 { .command
= "append-selection",
2402 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2403 .f
= window_copy_cmd_append_selection
2405 { .command
= "append-selection-and-cancel",
2408 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2409 .f
= window_copy_cmd_append_selection_and_cancel
2411 { .command
= "back-to-indentation",
2414 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2415 .f
= window_copy_cmd_back_to_indentation
2417 { .command
= "begin-selection",
2420 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2421 .f
= window_copy_cmd_begin_selection
2423 { .command
= "bottom-line",
2426 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2427 .f
= window_copy_cmd_bottom_line
2429 { .command
= "cancel",
2432 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2433 .f
= window_copy_cmd_cancel
2435 { .command
= "clear-selection",
2438 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2439 .f
= window_copy_cmd_clear_selection
2441 { .command
= "copy-end-of-line",
2444 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2445 .f
= window_copy_cmd_copy_end_of_line
2447 { .command
= "copy-end-of-line-and-cancel",
2450 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2451 .f
= window_copy_cmd_copy_end_of_line_and_cancel
2453 { .command
= "copy-pipe-end-of-line",
2456 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2457 .f
= window_copy_cmd_copy_pipe_end_of_line
2459 { .command
= "copy-pipe-end-of-line-and-cancel",
2462 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2463 .f
= window_copy_cmd_copy_pipe_end_of_line_and_cancel
2465 { .command
= "copy-line",
2468 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2469 .f
= window_copy_cmd_copy_line
2471 { .command
= "copy-line-and-cancel",
2474 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2475 .f
= window_copy_cmd_copy_line_and_cancel
2477 { .command
= "copy-pipe-line",
2480 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2481 .f
= window_copy_cmd_copy_pipe_line
2483 { .command
= "copy-pipe-line-and-cancel",
2486 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2487 .f
= window_copy_cmd_copy_pipe_line_and_cancel
2489 { .command
= "copy-pipe-no-clear",
2492 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2493 .f
= window_copy_cmd_copy_pipe_no_clear
2495 { .command
= "copy-pipe",
2498 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2499 .f
= window_copy_cmd_copy_pipe
2501 { .command
= "copy-pipe-and-cancel",
2504 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2505 .f
= window_copy_cmd_copy_pipe_and_cancel
2507 { .command
= "copy-selection-no-clear",
2510 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2511 .f
= window_copy_cmd_copy_selection_no_clear
2513 { .command
= "copy-selection",
2516 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2517 .f
= window_copy_cmd_copy_selection
2519 { .command
= "copy-selection-and-cancel",
2522 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2523 .f
= window_copy_cmd_copy_selection_and_cancel
2525 { .command
= "cursor-down",
2528 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2529 .f
= window_copy_cmd_cursor_down
2531 { .command
= "cursor-down-and-cancel",
2534 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2535 .f
= window_copy_cmd_cursor_down_and_cancel
2537 { .command
= "cursor-left",
2540 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2541 .f
= window_copy_cmd_cursor_left
2543 { .command
= "cursor-right",
2546 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2547 .f
= window_copy_cmd_cursor_right
2549 { .command
= "cursor-up",
2552 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2553 .f
= window_copy_cmd_cursor_up
2555 { .command
= "end-of-line",
2558 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2559 .f
= window_copy_cmd_end_of_line
2561 { .command
= "goto-line",
2564 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2565 .f
= window_copy_cmd_goto_line
2567 { .command
= "halfpage-down",
2570 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2571 .f
= window_copy_cmd_halfpage_down
2573 { .command
= "halfpage-down-and-cancel",
2576 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2577 .f
= window_copy_cmd_halfpage_down_and_cancel
2579 { .command
= "halfpage-up",
2582 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2583 .f
= window_copy_cmd_halfpage_up
2585 { .command
= "history-bottom",
2588 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2589 .f
= window_copy_cmd_history_bottom
2591 { .command
= "history-top",
2594 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2595 .f
= window_copy_cmd_history_top
2597 { .command
= "jump-again",
2600 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2601 .f
= window_copy_cmd_jump_again
2603 { .command
= "jump-backward",
2606 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2607 .f
= window_copy_cmd_jump_backward
2609 { .command
= "jump-forward",
2612 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2613 .f
= window_copy_cmd_jump_forward
2615 { .command
= "jump-reverse",
2618 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2619 .f
= window_copy_cmd_jump_reverse
2621 { .command
= "jump-to-backward",
2624 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2625 .f
= window_copy_cmd_jump_to_backward
2627 { .command
= "jump-to-forward",
2630 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2631 .f
= window_copy_cmd_jump_to_forward
2633 { .command
= "jump-to-mark",
2636 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2637 .f
= window_copy_cmd_jump_to_mark
2639 { .command
= "middle-line",
2642 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2643 .f
= window_copy_cmd_middle_line
2645 { .command
= "next-matching-bracket",
2648 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2649 .f
= window_copy_cmd_next_matching_bracket
2651 { .command
= "next-paragraph",
2654 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2655 .f
= window_copy_cmd_next_paragraph
2657 { .command
= "next-space",
2660 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2661 .f
= window_copy_cmd_next_space
2663 { .command
= "next-space-end",
2666 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2667 .f
= window_copy_cmd_next_space_end
2669 { .command
= "next-word",
2672 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2673 .f
= window_copy_cmd_next_word
2675 { .command
= "next-word-end",
2678 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2679 .f
= window_copy_cmd_next_word_end
2681 { .command
= "other-end",
2684 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2685 .f
= window_copy_cmd_other_end
2687 { .command
= "page-down",
2690 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2691 .f
= window_copy_cmd_page_down
2693 { .command
= "page-down-and-cancel",
2696 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2697 .f
= window_copy_cmd_page_down_and_cancel
2699 { .command
= "page-up",
2702 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2703 .f
= window_copy_cmd_page_up
2705 { .command
= "pipe-no-clear",
2708 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2709 .f
= window_copy_cmd_pipe_no_clear
2711 { .command
= "pipe",
2714 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2715 .f
= window_copy_cmd_pipe
2717 { .command
= "pipe-and-cancel",
2720 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2721 .f
= window_copy_cmd_pipe_and_cancel
2723 { .command
= "previous-matching-bracket",
2726 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2727 .f
= window_copy_cmd_previous_matching_bracket
2729 { .command
= "previous-paragraph",
2732 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2733 .f
= window_copy_cmd_previous_paragraph
2735 { .command
= "previous-space",
2738 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2739 .f
= window_copy_cmd_previous_space
2741 { .command
= "previous-word",
2744 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2745 .f
= window_copy_cmd_previous_word
2747 { .command
= "rectangle-on",
2750 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2751 .f
= window_copy_cmd_rectangle_on
2753 { .command
= "rectangle-off",
2756 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2757 .f
= window_copy_cmd_rectangle_off
2759 { .command
= "rectangle-toggle",
2762 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2763 .f
= window_copy_cmd_rectangle_toggle
2765 { .command
= "refresh-from-pane",
2768 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2769 .f
= window_copy_cmd_refresh_from_pane
2771 { .command
= "scroll-down",
2774 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2775 .f
= window_copy_cmd_scroll_down
2777 { .command
= "scroll-down-and-cancel",
2780 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2781 .f
= window_copy_cmd_scroll_down_and_cancel
2783 { .command
= "scroll-up",
2786 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2787 .f
= window_copy_cmd_scroll_up
2789 { .command
= "search-again",
2792 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2793 .f
= window_copy_cmd_search_again
2795 { .command
= "search-backward",
2798 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2799 .f
= window_copy_cmd_search_backward
2801 { .command
= "search-backward-text",
2804 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2805 .f
= window_copy_cmd_search_backward_text
2807 { .command
= "search-backward-incremental",
2810 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2811 .f
= window_copy_cmd_search_backward_incremental
2813 { .command
= "search-forward",
2816 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2817 .f
= window_copy_cmd_search_forward
2819 { .command
= "search-forward-text",
2822 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2823 .f
= window_copy_cmd_search_forward_text
2825 { .command
= "search-forward-incremental",
2828 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2829 .f
= window_copy_cmd_search_forward_incremental
2831 { .command
= "search-reverse",
2834 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2835 .f
= window_copy_cmd_search_reverse
2837 { .command
= "select-line",
2840 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2841 .f
= window_copy_cmd_select_line
2843 { .command
= "select-word",
2846 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2847 .f
= window_copy_cmd_select_word
2849 { .command
= "set-mark",
2852 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2853 .f
= window_copy_cmd_set_mark
2855 { .command
= "start-of-line",
2858 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2859 .f
= window_copy_cmd_start_of_line
2861 { .command
= "stop-selection",
2864 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2865 .f
= window_copy_cmd_stop_selection
2867 { .command
= "toggle-position",
2870 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2871 .f
= window_copy_cmd_toggle_position
2873 { .command
= "top-line",
2876 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2877 .f
= window_copy_cmd_top_line
2882 window_copy_command(struct window_mode_entry
*wme
, struct client
*c
,
2883 struct session
*s
, struct winlink
*wl
, struct args
*args
,
2884 struct mouse_event
*m
)
2886 struct window_copy_mode_data
*data
= wme
->data
;
2887 struct window_copy_cmd_state cs
;
2888 enum window_copy_cmd_action action
;
2889 enum window_copy_cmd_clear clear
= WINDOW_COPY_CMD_CLEAR_NEVER
;
2890 const char *command
;
2891 u_int i
, count
= args_count(args
);
2896 command
= args_string(args
, 0);
2898 if (m
!= NULL
&& m
->valid
&& !MOUSE_WHEEL(m
->b
))
2899 window_copy_move_mouse(m
);
2909 action
= WINDOW_COPY_CMD_NOTHING
;
2910 for (i
= 0; i
< nitems(window_copy_cmd_table
); i
++) {
2911 if (strcmp(window_copy_cmd_table
[i
].command
, command
) == 0) {
2912 if (count
- 1 < window_copy_cmd_table
[i
].minargs
||
2913 count
- 1 > window_copy_cmd_table
[i
].maxargs
)
2915 clear
= window_copy_cmd_table
[i
].clear
;
2916 action
= window_copy_cmd_table
[i
].f(&cs
);
2921 if (strncmp(command
, "search-", 7) != 0 && data
->searchmark
!= NULL
) {
2922 keys
= options_get_number(wme
->wp
->window
->options
, "mode-keys");
2923 if (clear
== WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
&&
2925 clear
= WINDOW_COPY_CMD_CLEAR_NEVER
;
2926 if (clear
!= WINDOW_COPY_CMD_CLEAR_NEVER
) {
2927 window_copy_clear_marks(wme
);
2928 data
->searchx
= data
->searchy
= -1;
2930 if (action
== WINDOW_COPY_CMD_NOTHING
)
2931 action
= WINDOW_COPY_CMD_REDRAW
;
2935 if (action
== WINDOW_COPY_CMD_CANCEL
)
2936 window_pane_reset_mode(wme
->wp
);
2937 else if (action
== WINDOW_COPY_CMD_REDRAW
)
2938 window_copy_redraw_screen(wme
);
2942 window_copy_scroll_to(struct window_mode_entry
*wme
, u_int px
, u_int py
,
2945 struct window_copy_mode_data
*data
= wme
->data
;
2946 struct grid
*gd
= data
->backing
->grid
;
2951 if (py
>= gd
->hsize
- data
->oy
&& py
< gd
->hsize
- data
->oy
+ gd
->sy
)
2952 data
->cy
= py
- (gd
->hsize
- data
->oy
);
2958 } else if (py
> gd
->hsize
+ gd
->sy
- gap
) {
2960 data
->cy
= py
- gd
->hsize
;
2962 offset
= py
+ gap
- gd
->sy
;
2963 data
->cy
= py
- offset
;
2965 data
->oy
= gd
->hsize
- offset
;
2968 if (!no_redraw
&& data
->searchmark
!= NULL
&& !data
->timeout
)
2969 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
2970 window_copy_update_selection(wme
, 1, 0);
2972 window_copy_redraw_screen(wme
);
2976 window_copy_search_compare(struct grid
*gd
, u_int px
, u_int py
,
2977 struct grid
*sgd
, u_int spx
, int cis
)
2979 struct grid_cell gc
, sgc
;
2980 const struct utf8_data
*ud
, *sud
;
2982 grid_get_cell(gd
, px
, py
, &gc
);
2984 grid_get_cell(sgd
, spx
, 0, &sgc
);
2987 if (ud
->size
!= sud
->size
|| ud
->width
!= sud
->width
)
2990 if (cis
&& ud
->size
== 1)
2991 return (tolower(ud
->data
[0]) == sud
->data
[0]);
2993 return (memcmp(ud
->data
, sud
->data
, ud
->size
) == 0);
2997 window_copy_search_lr(struct grid
*gd
, struct grid
*sgd
, u_int
*ppx
, u_int py
,
2998 u_int first
, u_int last
, int cis
)
3000 u_int ax
, bx
, px
, pywrap
, endline
;
3002 struct grid_line
*gl
;
3004 endline
= gd
->hsize
+ gd
->sy
- 1;
3005 for (ax
= first
; ax
< last
; ax
++) {
3006 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
3010 while (px
>= gd
->sx
&& pywrap
< endline
) {
3011 gl
= grid_get_line(gd
, pywrap
);
3012 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3017 /* We have run off the end of the grid. */
3020 matched
= window_copy_search_compare(gd
, px
, pywrap
,
3025 if (bx
== sgd
->sx
) {
3034 window_copy_search_rl(struct grid
*gd
,
3035 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
, int cis
)
3037 u_int ax
, bx
, px
, pywrap
, endline
;
3039 struct grid_line
*gl
;
3041 endline
= gd
->hsize
+ gd
->sy
- 1;
3042 for (ax
= last
; ax
> first
; ax
--) {
3043 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
3047 while (px
>= gd
->sx
&& pywrap
< endline
) {
3048 gl
= grid_get_line(gd
, pywrap
);
3049 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3054 /* We have run off the end of the grid. */
3057 matched
= window_copy_search_compare(gd
, px
, pywrap
,
3062 if (bx
== sgd
->sx
) {
3071 window_copy_search_lr_regex(struct grid
*gd
, u_int
*ppx
, u_int
*psx
, u_int py
,
3072 u_int first
, u_int last
, regex_t
*reg
)
3075 u_int endline
, foundx
, foundy
, len
, pywrap
, size
= 1;
3077 regmatch_t regmatch
;
3078 struct grid_line
*gl
;
3081 * This can happen during search if the last match was the last
3082 * character on a line.
3087 /* Set flags for regex search. */
3089 eflags
|= REG_NOTBOL
;
3091 /* Need to look at the entire string. */
3092 buf
= xmalloc(size
);
3094 buf
= window_copy_stringify(gd
, py
, first
, gd
->sx
, buf
, &size
);
3095 len
= gd
->sx
- first
;
3096 endline
= gd
->hsize
+ gd
->sy
- 1;
3098 while (buf
!= NULL
&& pywrap
<= endline
) {
3099 gl
= grid_get_line(gd
, pywrap
);
3100 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3103 buf
= window_copy_stringify(gd
, pywrap
, 0, gd
->sx
, buf
, &size
);
3107 if (regexec(reg
, buf
, 1, ®match
, eflags
) == 0 &&
3108 regmatch
.rm_so
!= regmatch
.rm_eo
) {
3111 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3112 buf
+ regmatch
.rm_so
);
3113 if (foundy
== py
&& foundx
< last
) {
3115 len
-= foundx
- first
;
3116 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3117 buf
+ regmatch
.rm_eo
);
3119 while (foundy
> py
) {
3136 window_copy_search_rl_regex(struct grid
*gd
, u_int
*ppx
, u_int
*psx
, u_int py
,
3137 u_int first
, u_int last
, regex_t
*reg
)
3140 u_int endline
, len
, pywrap
, size
= 1;
3142 struct grid_line
*gl
;
3144 /* Set flags for regex search. */
3146 eflags
|= REG_NOTBOL
;
3148 /* Need to look at the entire string. */
3149 buf
= xmalloc(size
);
3151 buf
= window_copy_stringify(gd
, py
, first
, gd
->sx
, buf
, &size
);
3152 len
= gd
->sx
- first
;
3153 endline
= gd
->hsize
+ gd
->sy
- 1;
3155 while (buf
!= NULL
&& (pywrap
<= endline
)) {
3156 gl
= grid_get_line(gd
, pywrap
);
3157 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3160 buf
= window_copy_stringify(gd
, pywrap
, 0, gd
->sx
, buf
, &size
);
3164 if (window_copy_last_regex(gd
, py
, first
, last
, len
, ppx
, psx
, buf
,
3178 window_copy_cellstring(const struct grid_line
*gl
, u_int px
, size_t *size
,
3181 static struct utf8_data ud
;
3182 struct grid_cell_entry
*gce
;
3185 if (px
>= gl
->cellsize
) {
3191 gce
= &gl
->celldata
[px
];
3192 if (gce
->flags
& GRID_FLAG_PADDING
) {
3197 if (~gce
->flags
& GRID_FLAG_EXTENDED
) {
3200 return (&gce
->data
.data
);
3203 utf8_to_data(gl
->extddata
[gce
->offset
].data
, &ud
);
3212 copy
= xmalloc(ud
.size
);
3213 memcpy(copy
, ud
.data
, ud
.size
);
3217 /* Find last match in given range. */
3219 window_copy_last_regex(struct grid
*gd
, u_int py
, u_int first
, u_int last
,
3220 u_int len
, u_int
*ppx
, u_int
*psx
, const char *buf
, const regex_t
*preg
,
3223 u_int foundx
, foundy
, oldx
, px
= 0, savepx
, savesx
= 0;
3224 regmatch_t regmatch
;
3229 while (regexec(preg
, buf
+ px
, 1, ®match
, eflags
) == 0) {
3230 if (regmatch
.rm_so
== regmatch
.rm_eo
)
3232 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3233 buf
+ px
+ regmatch
.rm_so
);
3234 if (foundy
> py
|| foundx
>= last
)
3236 len
-= foundx
- oldx
;
3238 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3239 buf
+ px
+ regmatch
.rm_eo
);
3240 if (foundy
> py
|| foundx
>= last
) {
3243 while (foundy
> py
) {
3250 savesx
= foundx
- savepx
;
3254 px
+= regmatch
.rm_eo
;
3268 /* Stringify line and append to input buffer. Caller frees. */
3270 window_copy_stringify(struct grid
*gd
, u_int py
, u_int first
, u_int last
,
3271 char *buf
, u_int
*size
)
3273 u_int ax
, bx
, newsize
= *size
;
3274 const struct grid_line
*gl
;
3276 size_t bufsize
= 1024, dlen
;
3279 while (bufsize
< newsize
)
3281 buf
= xrealloc(buf
, bufsize
);
3283 gl
= grid_peek_line(gd
, py
);
3285 for (ax
= first
; ax
< last
; ax
++) {
3286 d
= window_copy_cellstring(gl
, ax
, &dlen
, &allocated
);
3288 while (bufsize
< newsize
) {
3290 buf
= xrealloc(buf
, bufsize
);
3295 memcpy(buf
+ bx
, d
, dlen
);
3301 buf
[newsize
- 1] = '\0';
3307 /* Map start of C string containing UTF-8 data to grid cell position. */
3309 window_copy_cstrtocellpos(struct grid
*gd
, u_int ncells
, u_int
*ppx
, u_int
*ppy
,
3312 u_int cell
, ccell
, px
, pywrap
, pos
, len
;
3314 const struct grid_line
*gl
;
3323 /* Populate the array of cell data. */
3324 cells
= xreallocarray(NULL
, ncells
, sizeof cells
[0]);
3328 gl
= grid_peek_line(gd
, pywrap
);
3329 while (cell
< ncells
) {
3330 cells
[cell
].d
= window_copy_cellstring(gl
, px
,
3331 &cells
[cell
].dlen
, &cells
[cell
].allocated
);
3337 gl
= grid_peek_line(gd
, pywrap
);
3341 /* Locate starting cell. */
3344 while (cell
< ncells
) {
3348 while (ccell
< ncells
) {
3349 if (str
[pos
] == '\0') {
3354 dlen
= cells
[ccell
].dlen
;
3356 if (str
[pos
] != *d
) {
3362 if (dlen
> len
- pos
)
3364 if (memcmp(str
+ pos
, d
, dlen
) != 0) {
3377 /* If not found this will be one past the end. */
3380 while (px
>= gd
->sx
) {
3388 /* Free cell data. */
3389 for (cell
= 0; cell
< ncells
; cell
++) {
3390 if (cells
[cell
].allocated
)
3391 free((void *)cells
[cell
].d
);
3397 window_copy_move_left(struct screen
*s
, u_int
*fx
, u_int
*fy
, int wrapflag
)
3399 if (*fx
== 0) { /* left */
3400 if (*fy
== 0) { /* top */
3402 *fx
= screen_size_x(s
) - 1;
3403 *fy
= screen_hsize(s
) + screen_size_y(s
) - 1;
3407 *fx
= screen_size_x(s
) - 1;
3414 window_copy_move_right(struct screen
*s
, u_int
*fx
, u_int
*fy
, int wrapflag
)
3416 if (*fx
== screen_size_x(s
) - 1) { /* right */
3417 if (*fy
== screen_hsize(s
) + screen_size_y(s
) - 1) { /* bottom */
3431 window_copy_is_lowercase(const char *ptr
)
3433 while (*ptr
!= '\0') {
3434 if (*ptr
!= tolower((u_char
)*ptr
))
3442 * Handle backward wrapped regex searches with overlapping matches. In this case
3443 * find the longest overlapping match from previous wrapped lines.
3446 window_copy_search_back_overlap(struct grid
*gd
, regex_t
*preg
, u_int
*ppx
,
3447 u_int
*psx
, u_int
*ppy
, u_int endline
)
3449 u_int endx
, endy
, oldendx
, oldendy
, px
, py
, sx
;
3452 oldendx
= *ppx
+ *psx
;
3454 while (oldendx
> gd
->sx
- 1) {
3462 while (found
&& px
== 0 && py
- 1 > endline
&&
3463 grid_get_line(gd
, py
- 2)->flags
& GRID_LINE_WRAPPED
&&
3464 endx
== oldendx
&& endy
== oldendy
) {
3466 found
= window_copy_search_rl_regex(gd
, &px
, &sx
, py
- 1, 0,
3471 while (endx
> gd
->sx
- 1) {
3475 if (endx
== oldendx
&& endy
== oldendy
) {
3484 * Search for text stored in sgd starting from position fx,fy up to endline. If
3485 * found, jump to it. If cis then ignore case. The direction is 0 for searching
3486 * up, down otherwise. If wrap then go to begin/end of grid and try again if
3490 window_copy_search_jump(struct window_mode_entry
*wme
, struct grid
*gd
,
3491 struct grid
*sgd
, u_int fx
, u_int fy
, u_int endline
, int cis
, int wrap
,
3492 int direction
, int regex
)
3494 u_int i
, px
, sx
, ssize
= 1;
3495 int found
= 0, cflags
= REG_EXTENDED
;
3500 sbuf
= xmalloc(ssize
);
3502 sbuf
= window_copy_stringify(sgd
, 0, 0, sgd
->sx
, sbuf
, &ssize
);
3504 cflags
|= REG_ICASE
;
3505 if (regcomp(®
, sbuf
, cflags
) != 0) {
3513 for (i
= fy
; i
<= endline
; i
++) {
3515 found
= window_copy_search_lr_regex(gd
,
3516 &px
, &sx
, i
, fx
, gd
->sx
, ®
);
3518 found
= window_copy_search_lr(gd
, sgd
,
3519 &px
, i
, fx
, gd
->sx
, cis
);
3526 for (i
= fy
+ 1; endline
< i
; i
--) {
3528 found
= window_copy_search_rl_regex(gd
,
3529 &px
, &sx
, i
- 1, 0, fx
+ 1, ®
);
3531 window_copy_search_back_overlap(gd
,
3532 ®
, &px
, &sx
, &i
, endline
);
3535 found
= window_copy_search_rl(gd
, sgd
,
3536 &px
, i
- 1, 0, fx
+ 1, cis
);
3549 window_copy_scroll_to(wme
, px
, i
, 1);
3553 return (window_copy_search_jump(wme
, gd
, sgd
,
3554 direction
? 0 : gd
->sx
- 1,
3555 direction
? 0 : gd
->hsize
+ gd
->sy
- 1, fy
, cis
, 0,
3562 window_copy_move_after_search_mark(struct window_copy_mode_data
*data
,
3563 u_int
*fx
, u_int
*fy
, int wrapflag
)
3565 struct screen
*s
= data
->backing
;
3568 if (window_copy_search_mark_at(data
, *fx
, *fy
, &start
) == 0 &&
3569 data
->searchmark
[start
] != 0) {
3570 while (window_copy_search_mark_at(data
, *fx
, *fy
, &at
) == 0) {
3571 if (data
->searchmark
[at
] != data
->searchmark
[start
])
3573 /* Stop if not wrapping and at the end of the grid. */
3575 *fx
== screen_size_x(s
) - 1 &&
3576 *fy
== screen_hsize(s
) + screen_size_y(s
) - 1)
3579 window_copy_move_right(s
, fx
, fy
, wrapflag
);
3585 * Search in for text searchstr. If direction is 0 then search up, otherwise
3589 window_copy_search(struct window_mode_entry
*wme
, int direction
, int regex
)
3591 struct window_pane
*wp
= wme
->wp
;
3592 struct window_copy_mode_data
*data
= wme
->data
;
3593 struct screen
*s
= data
->backing
, ss
;
3594 struct screen_write_ctx ctx
;
3595 struct grid
*gd
= s
->grid
;
3596 const char *str
= data
->searchstr
;
3597 u_int at
, endline
, fx
, fy
, start
;
3598 int cis
, found
, keys
, visible_only
;
3601 if (regex
&& str
[strcspn(str
, "^$*+()?[].\\")] == '\0')
3604 data
->searchdirection
= direction
;
3609 if (data
->searchall
|| wp
->searchstr
== NULL
||
3610 wp
->searchregex
!= regex
) {
3612 data
->searchall
= 0;
3614 visible_only
= (strcmp(wp
->searchstr
, str
) == 0);
3615 free(wp
->searchstr
);
3616 wp
->searchstr
= xstrdup(str
);
3617 wp
->searchregex
= regex
;
3620 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3622 screen_init(&ss
, screen_write_strlen("%s", str
), 1, 0);
3623 screen_write_start(&ctx
, &ss
);
3624 screen_write_nputs(&ctx
, -1, &grid_default_cell
, "%s", str
);
3625 screen_write_stop(&ctx
);
3627 wrapflag
= options_get_number(wp
->window
->options
, "wrap-search");
3628 cis
= window_copy_is_lowercase(str
);
3630 keys
= options_get_number(wp
->window
->options
, "mode-keys");
3634 * Behave according to mode-keys. If it is emacs, search forward
3635 * leaves the cursor after the match. If it is vi, the cursor
3636 * remains at the beginning of the match, regardless of
3637 * direction, which means that we need to start the next search
3638 * after the term the cursor is currently on when searching
3641 if (keys
== MODEKEY_VI
) {
3642 if (data
->searchmark
!= NULL
)
3643 window_copy_move_after_search_mark(data
, &fx
,
3647 * When there are no search marks, start the
3648 * search after the current cursor position.
3650 window_copy_move_right(s
, &fx
, &fy
, wrapflag
);
3653 endline
= gd
->hsize
+ gd
->sy
- 1;
3656 window_copy_move_left(s
, &fx
, &fy
, wrapflag
);
3660 found
= window_copy_search_jump(wme
, gd
, ss
.grid
, fx
, fy
, endline
, cis
,
3661 wrapflag
, direction
, regex
);
3663 window_copy_search_marks(wme
, &ss
, regex
, visible_only
);
3665 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3668 * When searching forward, if the cursor is not at the beginning
3669 * of the mark, search again.
3672 window_copy_search_mark_at(data
, fx
, fy
, &at
) == 0 &&
3674 data
->searchmark
[at
] == data
->searchmark
[at
- 1]) {
3675 window_copy_move_after_search_mark(data
, &fx
, &fy
,
3677 window_copy_search_jump(wme
, gd
, ss
.grid
, fx
,
3678 fy
, endline
, cis
, wrapflag
, direction
,
3681 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3686 * When in Emacs mode, position the cursor just after
3689 if (keys
== MODEKEY_EMACS
) {
3690 window_copy_move_after_search_mark(data
, &fx
,
3693 data
->cy
= fy
- screen_hsize(data
->backing
) +
3699 * When searching backward, position the cursor at the
3700 * beginning of the mark.
3702 if (window_copy_search_mark_at(data
, fx
, fy
,
3704 while (window_copy_search_mark_at(data
, fx
, fy
,
3706 data
->searchmark
[at
] ==
3707 data
->searchmark
[start
]) {
3710 screen_hsize(data
->backing
) +
3715 window_copy_move_left(s
, &fx
, &fy
, 0);
3720 window_copy_redraw_screen(wme
);
3727 window_copy_visible_lines(struct window_copy_mode_data
*data
, u_int
*start
,
3730 struct grid
*gd
= data
->backing
->grid
;
3731 const struct grid_line
*gl
;
3733 for (*start
= gd
->hsize
- data
->oy
; *start
> 0; (*start
)--) {
3734 gl
= grid_peek_line(gd
, (*start
) - 1);
3735 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3738 *end
= gd
->hsize
- data
->oy
+ gd
->sy
;
3742 window_copy_search_mark_at(struct window_copy_mode_data
*data
, u_int px
,
3743 u_int py
, u_int
*at
)
3745 struct screen
*s
= data
->backing
;
3746 struct grid
*gd
= s
->grid
;
3748 if (py
< gd
->hsize
- data
->oy
)
3750 if (py
> gd
->hsize
- data
->oy
+ gd
->sy
- 1)
3752 *at
= ((py
- (gd
->hsize
- data
->oy
)) * gd
->sx
) + px
;
3757 window_copy_search_marks(struct window_mode_entry
*wme
, struct screen
*ssp
,
3758 int regex
, int visible_only
)
3760 struct window_copy_mode_data
*data
= wme
->data
;
3761 struct screen
*s
= data
->backing
, ss
;
3762 struct screen_write_ctx ctx
;
3763 struct grid
*gd
= s
->grid
;
3764 int found
, cis
, stopped
= 0;
3765 int cflags
= REG_EXTENDED
;
3766 u_int px
, py
, i
, b
, nfound
= 0, width
;
3767 u_int ssize
= 1, start
, end
;
3770 uint64_t stop
= 0, tstart
, t
;
3773 width
= screen_write_strlen("%s", data
->searchstr
);
3774 screen_init(&ss
, width
, 1, 0);
3775 screen_write_start(&ctx
, &ss
);
3776 screen_write_nputs(&ctx
, -1, &grid_default_cell
, "%s",
3778 screen_write_stop(&ctx
);
3781 width
= screen_size_x(ssp
);
3783 cis
= window_copy_is_lowercase(data
->searchstr
);
3786 sbuf
= xmalloc(ssize
);
3788 sbuf
= window_copy_stringify(ssp
->grid
, 0, 0, ssp
->grid
->sx
,
3791 cflags
|= REG_ICASE
;
3792 if (regcomp(®
, sbuf
, cflags
) != 0) {
3798 tstart
= get_timer();
3801 window_copy_visible_lines(data
, &start
, &end
);
3804 end
= gd
->hsize
+ gd
->sy
;
3805 stop
= get_timer() + WINDOW_COPY_SEARCH_ALL_TIMEOUT
;
3809 free(data
->searchmark
);
3810 data
->searchmark
= xcalloc(gd
->sx
, gd
->sy
);
3811 data
->searchgen
= 1;
3813 for (py
= start
; py
< end
; py
++) {
3817 found
= window_copy_search_lr_regex(gd
,
3818 &px
, &width
, py
, px
, gd
->sx
, ®
);
3822 found
= window_copy_search_lr(gd
, ssp
->grid
,
3823 &px
, py
, px
, gd
->sx
, cis
);
3829 if (window_copy_search_mark_at(data
, px
, py
, &b
) == 0) {
3830 if (b
+ width
> gd
->sx
* gd
->sy
)
3831 width
= (gd
->sx
* gd
->sy
) - b
;
3832 for (i
= b
; i
< b
+ width
; i
++) {
3833 if (data
->searchmark
[i
] != 0)
3835 data
->searchmark
[i
] = data
->searchgen
;
3837 if (data
->searchgen
== UCHAR_MAX
)
3838 data
->searchgen
= 1;
3846 if (t
- tstart
> WINDOW_COPY_SEARCH_TIMEOUT
) {
3850 if (stop
!= 0 && t
> stop
) {
3855 if (data
->timeout
) {
3856 window_copy_clear_marks(wme
);
3860 if (stopped
&& stop
!= 0) {
3861 /* Try again but just the visible context. */
3862 window_copy_visible_lines(data
, &start
, &end
);
3867 if (!visible_only
) {
3870 data
->searchcount
= 1000;
3871 else if (nfound
> 100)
3872 data
->searchcount
= 100;
3873 else if (nfound
> 10)
3874 data
->searchcount
= 10;
3876 data
->searchcount
= -1;
3877 data
->searchmore
= 1;
3879 data
->searchcount
= nfound
;
3880 data
->searchmore
= 0;
3893 window_copy_clear_marks(struct window_mode_entry
*wme
)
3895 struct window_copy_mode_data
*data
= wme
->data
;
3897 free(data
->searchmark
);
3898 data
->searchmark
= NULL
;
3902 window_copy_search_up(struct window_mode_entry
*wme
, int regex
)
3904 return (window_copy_search(wme
, 0, regex
));
3908 window_copy_search_down(struct window_mode_entry
*wme
, int regex
)
3910 return (window_copy_search(wme
, 1, regex
));
3914 window_copy_goto_line(struct window_mode_entry
*wme
, const char *linestr
)
3916 struct window_copy_mode_data
*data
= wme
->data
;
3920 lineno
= strtonum(linestr
, -1, INT_MAX
, &errstr
);
3923 if (lineno
< 0 || (u_int
)lineno
> screen_hsize(data
->backing
))
3924 lineno
= screen_hsize(data
->backing
);
3927 window_copy_update_selection(wme
, 1, 0);
3928 window_copy_redraw_screen(wme
);
3932 window_copy_match_start_end(struct window_copy_mode_data
*data
, u_int at
,
3933 u_int
*start
, u_int
*end
)
3935 struct grid
*gd
= data
->backing
->grid
;
3936 u_int last
= (gd
->sy
* gd
->sx
) - 1;
3937 u_char mark
= data
->searchmark
[at
];
3940 while (*start
!= 0 && data
->searchmark
[*start
] == mark
)
3942 if (data
->searchmark
[*start
] != mark
)
3944 while (*end
!= last
&& data
->searchmark
[*end
] == mark
)
3946 if (data
->searchmark
[*end
] != mark
)
3951 window_copy_match_at_cursor(struct window_copy_mode_data
*data
)
3953 struct grid
*gd
= data
->backing
->grid
;
3954 struct grid_cell gc
;
3955 u_int at
, start
, end
, cy
, px
, py
;
3956 u_int sx
= screen_size_x(data
->backing
);
3960 if (data
->searchmark
== NULL
)
3963 cy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3964 if (window_copy_search_mark_at(data
, data
->cx
, cy
, &at
) != 0)
3966 if (data
->searchmark
[at
] == 0) {
3967 /* Allow one position after the match. */
3968 if (at
== 0 || data
->searchmark
[--at
] == 0)
3971 window_copy_match_start_end(data
, at
, &start
, &end
);
3974 * Cells will not be set in the marked array unless they are valid text
3975 * and wrapping will be taken care of, so we can just copy.
3977 for (at
= start
; at
<= end
; at
++) {
3979 px
= at
- (py
* sx
);
3981 grid_get_cell(gd
, px
, gd
->hsize
+ py
- data
->oy
, &gc
);
3982 buf
= xrealloc(buf
, len
+ gc
.data
.size
+ 1);
3983 memcpy(buf
+ len
, gc
.data
.data
, gc
.data
.size
);
3984 len
+= gc
.data
.size
;
3992 window_copy_update_style(struct window_mode_entry
*wme
, u_int fx
, u_int fy
,
3993 struct grid_cell
*gc
, const struct grid_cell
*mgc
,
3994 const struct grid_cell
*cgc
, const struct grid_cell
*mkgc
)
3996 struct window_pane
*wp
= wme
->wp
;
3997 struct window_copy_mode_data
*data
= wme
->data
;
3998 u_int mark
, start
, end
, cy
, cursor
, current
;
3999 int inv
= 0, found
= 0;
4002 if (data
->showmark
&& fy
== data
->my
) {
4003 gc
->attr
= mkgc
->attr
;
4016 if (data
->searchmark
== NULL
)
4019 if (window_copy_search_mark_at(data
, fx
, fy
, ¤t
) != 0)
4021 mark
= data
->searchmark
[current
];
4025 cy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
4026 if (window_copy_search_mark_at(data
, data
->cx
, cy
, &cursor
) == 0) {
4027 keys
= options_get_number(wp
->window
->options
, "mode-keys");
4029 keys
== MODEKEY_EMACS
&&
4030 data
->searchdirection
) {
4031 if (data
->searchmark
[cursor
- 1] == mark
) {
4035 } else if (data
->searchmark
[cursor
] == mark
)
4038 window_copy_match_start_end(data
, cursor
, &start
, &end
);
4039 if (current
>= start
&& current
<= end
) {
4040 gc
->attr
= cgc
->attr
;
4054 gc
->attr
= mgc
->attr
;
4066 window_copy_write_one(struct window_mode_entry
*wme
,
4067 struct screen_write_ctx
*ctx
, u_int py
, u_int fy
, u_int nx
,
4068 const struct grid_cell
*mgc
, const struct grid_cell
*cgc
,
4069 const struct grid_cell
*mkgc
)
4071 struct window_copy_mode_data
*data
= wme
->data
;
4072 struct grid
*gd
= data
->backing
->grid
;
4073 struct grid_cell gc
;
4076 screen_write_cursormove(ctx
, 0, py
, 0);
4077 for (fx
= 0; fx
< nx
; fx
++) {
4078 grid_get_cell(gd
, fx
, fy
, &gc
);
4079 if (fx
+ gc
.data
.width
<= nx
) {
4080 window_copy_update_style(wme
, fx
, fy
, &gc
, mgc
, cgc
,
4082 screen_write_cell(ctx
, &gc
);
4088 window_copy_write_line(struct window_mode_entry
*wme
,
4089 struct screen_write_ctx
*ctx
, u_int py
)
4091 struct window_pane
*wp
= wme
->wp
;
4092 struct window_copy_mode_data
*data
= wme
->data
;
4093 struct screen
*s
= &data
->screen
;
4094 struct options
*oo
= wp
->window
->options
;
4095 struct grid_line
*gl
;
4096 struct grid_cell gc
, mgc
, cgc
, mkgc
;
4097 char hdr
[512], tmp
[256], *t
;
4099 u_int hsize
= screen_hsize(data
->backing
);
4101 style_apply(&gc
, oo
, "mode-style", NULL
);
4102 gc
.flags
|= GRID_FLAG_NOPALETTE
;
4103 style_apply(&mgc
, oo
, "copy-mode-match-style", NULL
);
4104 mgc
.flags
|= GRID_FLAG_NOPALETTE
;
4105 style_apply(&cgc
, oo
, "copy-mode-current-match-style", NULL
);
4106 cgc
.flags
|= GRID_FLAG_NOPALETTE
;
4107 style_apply(&mkgc
, oo
, "copy-mode-mark-style", NULL
);
4108 mkgc
.flags
|= GRID_FLAG_NOPALETTE
;
4110 if (py
== 0 && s
->rupper
< s
->rlower
&& !data
->hide_position
) {
4111 gl
= grid_get_line(data
->backing
->grid
, hsize
- data
->oy
);
4113 xsnprintf(tmp
, sizeof tmp
, "[%u/%u]", data
->oy
, hsize
);
4115 t
= format_pretty_time(gl
->time
, 1);
4116 xsnprintf(tmp
, sizeof tmp
, "%s [%u/%u]", t
, data
->oy
,
4121 if (data
->searchmark
== NULL
) {
4122 if (data
->timeout
) {
4123 size
= xsnprintf(hdr
, sizeof hdr
,
4124 "(timed out) %s", tmp
);
4126 size
= xsnprintf(hdr
, sizeof hdr
, "%s", tmp
);
4128 if (data
->searchcount
== -1)
4129 size
= xsnprintf(hdr
, sizeof hdr
, "%s", tmp
);
4131 size
= xsnprintf(hdr
, sizeof hdr
,
4132 "(%d%s results) %s", data
->searchcount
,
4133 data
->searchmore
? "+" : "", tmp
);
4136 if (size
> screen_size_x(s
))
4137 size
= screen_size_x(s
);
4138 screen_write_cursormove(ctx
, screen_size_x(s
) - size
, 0, 0);
4139 screen_write_puts(ctx
, &gc
, "%s", hdr
);
4143 if (size
< screen_size_x(s
)) {
4144 window_copy_write_one(wme
, ctx
, py
, hsize
- data
->oy
+ py
,
4145 screen_size_x(s
) - size
, &mgc
, &cgc
, &mkgc
);
4148 if (py
== data
->cy
&& data
->cx
== screen_size_x(s
)) {
4149 screen_write_cursormove(ctx
, screen_size_x(s
) - 1, py
, 0);
4150 screen_write_putc(ctx
, &grid_default_cell
, '$');
4155 window_copy_write_lines(struct window_mode_entry
*wme
,
4156 struct screen_write_ctx
*ctx
, u_int py
, u_int ny
)
4160 for (yy
= py
; yy
< py
+ ny
; yy
++)
4161 window_copy_write_line(wme
, ctx
, py
);
4165 window_copy_redraw_selection(struct window_mode_entry
*wme
, u_int old_y
)
4167 struct window_copy_mode_data
*data
= wme
->data
;
4168 struct grid
*gd
= data
->backing
->grid
;
4169 u_int new_y
, start
, end
;
4172 if (old_y
<= new_y
) {
4181 * In word selection mode the first word on the line below the cursor
4182 * might be selected, so add this line to the redraw area.
4184 if (data
->selflag
== SEL_WORD
) {
4185 /* Last grid line in data coordinates. */
4186 if (end
< gd
->sy
+ data
->oy
- 1)
4189 window_copy_redraw_lines(wme
, start
, end
- start
+ 1);
4193 window_copy_redraw_lines(struct window_mode_entry
*wme
, u_int py
, u_int ny
)
4195 struct window_pane
*wp
= wme
->wp
;
4196 struct window_copy_mode_data
*data
= wme
->data
;
4197 struct screen_write_ctx ctx
;
4200 screen_write_start_pane(&ctx
, wp
, NULL
);
4201 for (i
= py
; i
< py
+ ny
; i
++)
4202 window_copy_write_line(wme
, &ctx
, i
);
4203 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
4204 screen_write_stop(&ctx
);
4208 window_copy_redraw_screen(struct window_mode_entry
*wme
)
4210 struct window_copy_mode_data
*data
= wme
->data
;
4212 window_copy_redraw_lines(wme
, 0, screen_size_y(&data
->screen
));
4216 window_copy_synchronize_cursor_end(struct window_mode_entry
*wme
, int begin
,
4219 struct window_copy_mode_data
*data
= wme
->data
;
4223 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4224 switch (data
->selflag
) {
4229 if (data
->dy
> yy
|| (data
->dy
== yy
&& data
->dx
> xx
)) {
4230 /* Right to left selection. */
4231 window_copy_cursor_previous_word_pos(wme
,
4232 data
->separators
, &xx
, &yy
);
4235 /* Reset the end. */
4236 data
->endselx
= data
->endselrx
;
4237 data
->endsely
= data
->endselry
;
4239 /* Left to right selection. */
4240 if (xx
>= window_copy_find_length(wme
, yy
) ||
4241 !window_copy_in_set(wme
, xx
+ 1, yy
, WHITESPACE
)) {
4242 window_copy_cursor_next_word_end_pos(wme
,
4243 data
->separators
, &xx
, &yy
);
4246 /* Reset the start. */
4247 data
->selx
= data
->selrx
;
4248 data
->sely
= data
->selry
;
4255 if (data
->dy
> yy
) {
4256 /* Right to left selection. */
4260 /* Reset the end. */
4261 data
->endselx
= data
->endselrx
;
4262 data
->endsely
= data
->endselry
;
4264 /* Left to right selection. */
4265 if (yy
< data
->endselry
)
4266 yy
= data
->endselry
;
4267 xx
= window_copy_find_length(wme
, yy
);
4269 /* Reset the start. */
4270 data
->selx
= data
->selrx
;
4271 data
->sely
= data
->selry
;
4287 window_copy_synchronize_cursor(struct window_mode_entry
*wme
, int no_reset
)
4289 struct window_copy_mode_data
*data
= wme
->data
;
4291 switch (data
->cursordrag
) {
4292 case CURSORDRAG_ENDSEL
:
4293 window_copy_synchronize_cursor_end(wme
, 0, no_reset
);
4295 case CURSORDRAG_SEL
:
4296 window_copy_synchronize_cursor_end(wme
, 1, no_reset
);
4298 case CURSORDRAG_NONE
:
4304 window_copy_update_cursor(struct window_mode_entry
*wme
, u_int cx
, u_int cy
)
4306 struct window_pane
*wp
= wme
->wp
;
4307 struct window_copy_mode_data
*data
= wme
->data
;
4308 struct screen
*s
= &data
->screen
;
4309 struct screen_write_ctx ctx
;
4310 u_int old_cx
, old_cy
;
4312 old_cx
= data
->cx
; old_cy
= data
->cy
;
4313 data
->cx
= cx
; data
->cy
= cy
;
4314 if (old_cx
== screen_size_x(s
))
4315 window_copy_redraw_lines(wme
, old_cy
, 1);
4316 if (data
->cx
== screen_size_x(s
))
4317 window_copy_redraw_lines(wme
, data
->cy
, 1);
4319 screen_write_start_pane(&ctx
, wp
, NULL
);
4320 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
4321 screen_write_stop(&ctx
);
4326 window_copy_start_selection(struct window_mode_entry
*wme
)
4328 struct window_copy_mode_data
*data
= wme
->data
;
4330 data
->selx
= data
->cx
;
4331 data
->sely
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4333 data
->endselx
= data
->selx
;
4334 data
->endsely
= data
->sely
;
4336 data
->cursordrag
= CURSORDRAG_ENDSEL
;
4338 window_copy_set_selection(wme
, 1, 0);
4342 window_copy_adjust_selection(struct window_mode_entry
*wme
, u_int
*selx
,
4345 struct window_copy_mode_data
*data
= wme
->data
;
4346 struct screen
*s
= &data
->screen
;
4353 ty
= screen_hsize(data
->backing
) - data
->oy
;
4355 relpos
= WINDOW_COPY_REL_POS_ABOVE
;
4356 if (!data
->rectflag
)
4359 } else if (sy
> ty
+ screen_size_y(s
) - 1) {
4360 relpos
= WINDOW_COPY_REL_POS_BELOW
;
4361 if (!data
->rectflag
)
4362 sx
= screen_size_x(s
) - 1;
4363 sy
= screen_size_y(s
) - 1;
4365 relpos
= WINDOW_COPY_REL_POS_ON_SCREEN
;
4375 window_copy_update_selection(struct window_mode_entry
*wme
, int may_redraw
,
4378 struct window_copy_mode_data
*data
= wme
->data
;
4379 struct screen
*s
= &data
->screen
;
4381 if (s
->sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
)
4383 return (window_copy_set_selection(wme
, may_redraw
, no_reset
));
4387 window_copy_set_selection(struct window_mode_entry
*wme
, int may_redraw
,
4390 struct window_pane
*wp
= wme
->wp
;
4391 struct window_copy_mode_data
*data
= wme
->data
;
4392 struct screen
*s
= &data
->screen
;
4393 struct options
*oo
= wp
->window
->options
;
4394 struct grid_cell gc
;
4395 u_int sx
, sy
, cy
, endsx
, endsy
;
4396 int startrelpos
, endrelpos
;
4398 window_copy_synchronize_cursor(wme
, no_reset
);
4400 /* Adjust the selection. */
4403 startrelpos
= window_copy_adjust_selection(wme
, &sx
, &sy
);
4405 /* Adjust the end of selection. */
4406 endsx
= data
->endselx
;
4407 endsy
= data
->endsely
;
4408 endrelpos
= window_copy_adjust_selection(wme
, &endsx
, &endsy
);
4410 /* Selection is outside of the current screen */
4411 if (startrelpos
== endrelpos
&&
4412 startrelpos
!= WINDOW_COPY_REL_POS_ON_SCREEN
) {
4413 screen_hide_selection(s
);
4417 /* Set colours and selection. */
4418 style_apply(&gc
, oo
, "mode-style", NULL
);
4419 gc
.flags
|= GRID_FLAG_NOPALETTE
;
4420 screen_set_selection(s
, sx
, sy
, endsx
, endsy
, data
->rectflag
,
4421 data
->modekeys
, &gc
);
4423 if (data
->rectflag
&& may_redraw
) {
4425 * Can't rely on the caller to redraw the right lines for
4426 * rectangle selection - find the highest line and the number
4427 * of lines, and redraw just past that in both directions
4430 if (data
->cursordrag
== CURSORDRAG_ENDSEL
) {
4432 window_copy_redraw_lines(wme
, sy
, cy
- sy
+ 1);
4434 window_copy_redraw_lines(wme
, cy
, sy
- cy
+ 1);
4437 window_copy_redraw_lines(wme
, endsy
,
4440 window_copy_redraw_lines(wme
, cy
,
4450 window_copy_get_selection(struct window_mode_entry
*wme
, size_t *len
)
4452 struct window_pane
*wp
= wme
->wp
;
4453 struct window_copy_mode_data
*data
= wme
->data
;
4454 struct screen
*s
= &data
->screen
;
4457 u_int i
, xx
, yy
, sx
, sy
, ex
, ey
, ey_last
;
4458 u_int firstsx
, lastex
, restex
, restsx
, selx
;
4461 if (data
->screen
.sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
) {
4462 buf
= window_copy_match_at_cursor(data
);
4476 * The selection extends from selx,sely to (adjusted) cx,cy on
4480 /* Find start and end. */
4483 if (yy
< data
->sely
|| (yy
== data
->sely
&& xx
< data
->selx
)) {
4485 ex
= data
->selx
; ey
= data
->sely
;
4487 sx
= data
->selx
; sy
= data
->sely
;
4491 /* Trim ex to end of line. */
4492 ey_last
= window_copy_find_length(wme
, ey
);
4497 * Deal with rectangle-copy if necessary; four situations: start of
4498 * first line (firstsx), end of last line (lastex), start (restsx) and
4499 * end (restex) of all other lines.
4501 xx
= screen_size_x(s
);
4504 * Behave according to mode-keys. If it is emacs, copy like emacs,
4505 * keeping the top-left-most character, and dropping the
4506 * bottom-right-most, regardless of copy direction. If it is vi, also
4507 * keep bottom-right-most character.
4509 keys
= options_get_number(wp
->window
->options
, "mode-keys");
4510 if (data
->rectflag
) {
4512 * Need to ignore the column with the cursor in it, which for
4513 * rectangular copy means knowing which side the cursor is on.
4515 if (data
->cursordrag
== CURSORDRAG_ENDSEL
)
4518 selx
= data
->endselx
;
4519 if (selx
< data
->cx
) {
4520 /* Selection start is on the left. */
4521 if (keys
== MODEKEY_EMACS
) {
4526 lastex
= data
->cx
+ 1;
4527 restex
= data
->cx
+ 1;
4532 /* Cursor is on the left. */
4539 if (keys
== MODEKEY_EMACS
)
4548 /* Copy the lines. */
4549 for (i
= sy
; i
<= ey
; i
++) {
4550 window_copy_copy_line(wme
, &buf
, &off
, i
,
4551 (i
== sy
? firstsx
: restsx
),
4552 (i
== ey
? lastex
: restex
));
4555 /* Don't bother if no data. */
4561 /* Remove final \n (unless at end in vi mode). */
4562 if (keys
== MODEKEY_EMACS
|| lastex
<= ey_last
) {
4563 if (~grid_get_line(data
->backing
->grid
, ey
)->flags
&
4564 GRID_LINE_WRAPPED
|| lastex
!= ey_last
)
4572 window_copy_copy_buffer(struct window_mode_entry
*wme
, const char *prefix
,
4573 void *buf
, size_t len
)
4575 struct window_pane
*wp
= wme
->wp
;
4576 struct screen_write_ctx ctx
;
4578 if (options_get_number(global_options
, "set-clipboard") != 0) {
4579 screen_write_start_pane(&ctx
, wp
, NULL
);
4580 screen_write_setselection(&ctx
, "", buf
, len
);
4581 screen_write_stop(&ctx
);
4582 notify_pane("pane-set-clipboard", wp
);
4585 paste_add(prefix
, buf
, len
);
4589 window_copy_pipe_run(struct window_mode_entry
*wme
, struct session
*s
,
4590 const char *cmd
, size_t *len
)
4595 buf
= window_copy_get_selection(wme
, len
);
4596 if (cmd
== NULL
|| *cmd
== '\0')
4597 cmd
= options_get_string(global_options
, "copy-command");
4598 if (cmd
!= NULL
&& *cmd
!= '\0') {
4599 job
= job_run(cmd
, 0, NULL
, NULL
, s
, NULL
, NULL
, NULL
, NULL
,
4600 NULL
, JOB_NOWAIT
, -1, -1);
4601 bufferevent_write(job_get_event(job
), buf
, *len
);
4607 window_copy_pipe(struct window_mode_entry
*wme
, struct session
*s
,
4612 window_copy_pipe_run(wme
, s
, cmd
, &len
);
4616 window_copy_copy_pipe(struct window_mode_entry
*wme
, struct session
*s
,
4617 const char *prefix
, const char *cmd
)
4622 buf
= window_copy_pipe_run(wme
, s
, cmd
, &len
);
4624 window_copy_copy_buffer(wme
, prefix
, buf
, len
);
4628 window_copy_copy_selection(struct window_mode_entry
*wme
, const char *prefix
)
4633 buf
= window_copy_get_selection(wme
, &len
);
4635 window_copy_copy_buffer(wme
, prefix
, buf
, len
);
4639 window_copy_append_selection(struct window_mode_entry
*wme
)
4641 struct window_pane
*wp
= wme
->wp
;
4643 struct paste_buffer
*pb
;
4644 const char *bufdata
, *bufname
= NULL
;
4645 size_t len
, bufsize
;
4646 struct screen_write_ctx ctx
;
4648 buf
= window_copy_get_selection(wme
, &len
);
4652 if (options_get_number(global_options
, "set-clipboard") != 0) {
4653 screen_write_start_pane(&ctx
, wp
, NULL
);
4654 screen_write_setselection(&ctx
, "", buf
, len
);
4655 screen_write_stop(&ctx
);
4656 notify_pane("pane-set-clipboard", wp
);
4659 pb
= paste_get_top(&bufname
);
4661 bufdata
= paste_buffer_data(pb
, &bufsize
);
4662 buf
= xrealloc(buf
, len
+ bufsize
);
4663 memmove(buf
+ bufsize
, buf
, len
);
4664 memcpy(buf
, bufdata
, bufsize
);
4667 if (paste_set(buf
, len
, bufname
, NULL
) != 0)
4672 window_copy_copy_line(struct window_mode_entry
*wme
, char **buf
, size_t *off
,
4673 u_int sy
, u_int sx
, u_int ex
)
4675 struct window_copy_mode_data
*data
= wme
->data
;
4676 struct grid
*gd
= data
->backing
->grid
;
4677 struct grid_cell gc
;
4678 struct grid_line
*gl
;
4679 struct utf8_data ud
;
4680 u_int i
, xx
, wrapped
= 0;
4687 * Work out if the line was wrapped at the screen edge and all of it is
4690 gl
= grid_get_line(gd
, sy
);
4691 if (gl
->flags
& GRID_LINE_WRAPPED
&& gl
->cellsize
<= gd
->sx
)
4694 /* If the line was wrapped, don't strip spaces (use the full length). */
4698 xx
= window_copy_find_length(wme
, sy
);
4705 for (i
= sx
; i
< ex
; i
++) {
4706 grid_get_cell(gd
, i
, sy
, &gc
);
4707 if (gc
.flags
& GRID_FLAG_PADDING
)
4709 utf8_copy(&ud
, &gc
.data
);
4710 if (ud
.size
== 1 && (gc
.attr
& GRID_ATTR_CHARSET
)) {
4711 s
= tty_acs_get(NULL
, ud
.data
[0]);
4712 if (s
!= NULL
&& strlen(s
) <= sizeof ud
.data
) {
4713 ud
.size
= strlen(s
);
4714 memcpy(ud
.data
, s
, ud
.size
);
4718 *buf
= xrealloc(*buf
, (*off
) + ud
.size
);
4719 memcpy(*buf
+ *off
, ud
.data
, ud
.size
);
4724 /* Only add a newline if the line wasn't wrapped. */
4725 if (!wrapped
|| ex
!= xx
) {
4726 *buf
= xrealloc(*buf
, (*off
) + 1);
4727 (*buf
)[(*off
)++] = '\n';
4732 window_copy_clear_selection(struct window_mode_entry
*wme
)
4734 struct window_copy_mode_data
*data
= wme
->data
;
4737 screen_clear_selection(&data
->screen
);
4739 data
->cursordrag
= CURSORDRAG_NONE
;
4740 data
->lineflag
= LINE_SEL_NONE
;
4741 data
->selflag
= SEL_CHAR
;
4743 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4744 px
= window_copy_find_length(wme
, py
);
4746 window_copy_update_cursor(wme
, px
, data
->cy
);
4750 window_copy_in_set(struct window_mode_entry
*wme
, u_int px
, u_int py
,
4753 struct window_copy_mode_data
*data
= wme
->data
;
4754 struct grid_cell gc
;
4756 grid_get_cell(data
->backing
->grid
, px
, py
, &gc
);
4757 if (gc
.flags
& GRID_FLAG_PADDING
)
4759 return (utf8_cstrhas(set
, &gc
.data
));
4763 window_copy_find_length(struct window_mode_entry
*wme
, u_int py
)
4765 struct window_copy_mode_data
*data
= wme
->data
;
4767 return (grid_line_length(data
->backing
->grid
, py
));
4771 window_copy_cursor_start_of_line(struct window_mode_entry
*wme
)
4773 struct window_copy_mode_data
*data
= wme
->data
;
4774 struct screen
*back_s
= data
->backing
;
4775 struct grid_reader gr
;
4776 u_int px
, py
, oldy
, hsize
;
4779 hsize
= screen_hsize(back_s
);
4780 py
= hsize
+ data
->cy
- data
->oy
;
4783 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4784 grid_reader_cursor_start_of_line(&gr
, 1);
4785 grid_reader_get_cursor(&gr
, &px
, &py
);
4786 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
4790 window_copy_cursor_back_to_indentation(struct window_mode_entry
*wme
)
4792 struct window_copy_mode_data
*data
= wme
->data
;
4793 struct screen
*back_s
= data
->backing
;
4794 struct grid_reader gr
;
4795 u_int px
, py
, oldy
, hsize
;
4798 hsize
= screen_hsize(back_s
);
4799 py
= hsize
+ data
->cy
- data
->oy
;
4802 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4803 grid_reader_cursor_back_to_indentation(&gr
);
4804 grid_reader_get_cursor(&gr
, &px
, &py
);
4805 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
4809 window_copy_cursor_end_of_line(struct window_mode_entry
*wme
)
4811 struct window_copy_mode_data
*data
= wme
->data
;
4812 struct screen
*back_s
= data
->backing
;
4813 struct grid_reader gr
;
4814 u_int px
, py
, oldy
, hsize
;
4817 hsize
= screen_hsize(back_s
);
4818 py
= hsize
+ data
->cy
- data
->oy
;
4821 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4822 if (data
->screen
.sel
!= NULL
&& data
->rectflag
)
4823 grid_reader_cursor_end_of_line(&gr
, 1, 1);
4825 grid_reader_cursor_end_of_line(&gr
, 1, 0);
4826 grid_reader_get_cursor(&gr
, &px
, &py
);
4827 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
4828 data
->oy
, oldy
, px
, py
, 0);
4832 window_copy_other_end(struct window_mode_entry
*wme
)
4834 struct window_copy_mode_data
*data
= wme
->data
;
4835 struct screen
*s
= &data
->screen
;
4836 u_int selx
, sely
, cy
, yy
, hsize
;
4838 if (s
->sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
)
4841 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
4842 data
->lineflag
= LINE_SEL_RIGHT_LEFT
;
4843 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
4844 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
4846 switch (data
->cursordrag
) {
4847 case CURSORDRAG_NONE
:
4848 case CURSORDRAG_SEL
:
4849 data
->cursordrag
= CURSORDRAG_ENDSEL
;
4851 case CURSORDRAG_ENDSEL
:
4852 data
->cursordrag
= CURSORDRAG_SEL
;
4856 selx
= data
->endselx
;
4857 sely
= data
->endsely
;
4858 if (data
->cursordrag
== CURSORDRAG_SEL
) {
4864 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4868 hsize
= screen_hsize(data
->backing
);
4869 if (sely
< hsize
- data
->oy
) { /* above */
4870 data
->oy
= hsize
- sely
;
4872 } else if (sely
> hsize
- data
->oy
+ screen_size_y(s
)) { /* below */
4873 data
->oy
= hsize
- sely
+ screen_size_y(s
) - 1;
4874 data
->cy
= screen_size_y(s
) - 1;
4876 data
->cy
= cy
+ sely
- yy
;
4878 window_copy_update_selection(wme
, 1, 1);
4879 window_copy_redraw_screen(wme
);
4883 window_copy_cursor_left(struct window_mode_entry
*wme
)
4885 struct window_copy_mode_data
*data
= wme
->data
;
4886 struct screen
*back_s
= data
->backing
;
4887 struct grid_reader gr
;
4888 u_int px
, py
, oldy
, hsize
;
4891 hsize
= screen_hsize(back_s
);
4892 py
= hsize
+ data
->cy
- data
->oy
;
4895 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4896 grid_reader_cursor_left(&gr
, 1);
4897 grid_reader_get_cursor(&gr
, &px
, &py
);
4898 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
4902 window_copy_cursor_right(struct window_mode_entry
*wme
, int all
)
4904 struct window_copy_mode_data
*data
= wme
->data
;
4905 struct screen
*back_s
= data
->backing
;
4906 struct grid_reader gr
;
4907 u_int px
, py
, oldy
, hsize
;
4910 hsize
= screen_hsize(back_s
);
4911 py
= hsize
+ data
->cy
- data
->oy
;
4914 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4915 grid_reader_cursor_right(&gr
, 1, all
);
4916 grid_reader_get_cursor(&gr
, &px
, &py
);
4917 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
4918 data
->oy
, oldy
, px
, py
, 0);
4922 window_copy_cursor_up(struct window_mode_entry
*wme
, int scroll_only
)
4924 struct window_copy_mode_data
*data
= wme
->data
;
4925 struct screen
*s
= &data
->screen
;
4926 u_int ox
, oy
, px
, py
;
4929 norectsel
= data
->screen
.sel
== NULL
|| !data
->rectflag
;
4930 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4931 ox
= window_copy_find_length(wme
, oy
);
4932 if (norectsel
&& data
->cx
!= ox
) {
4933 data
->lastcx
= data
->cx
;
4937 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
&& oy
== data
->sely
)
4938 window_copy_other_end(wme
);
4940 if (scroll_only
|| data
->cy
== 0) {
4942 data
->cx
= data
->lastcx
;
4943 window_copy_scroll_down(wme
, 1);
4945 if (data
->cy
== screen_size_y(s
) - 1)
4946 window_copy_redraw_lines(wme
, data
->cy
, 1);
4948 window_copy_redraw_lines(wme
, data
->cy
, 2);
4952 window_copy_update_cursor(wme
, data
->lastcx
,
4955 window_copy_update_cursor(wme
, data
->cx
, data
->cy
- 1);
4956 if (window_copy_update_selection(wme
, 1, 0)) {
4957 if (data
->cy
== screen_size_y(s
) - 1)
4958 window_copy_redraw_lines(wme
, data
->cy
, 1);
4960 window_copy_redraw_lines(wme
, data
->cy
, 2);
4965 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4966 px
= window_copy_find_length(wme
, py
);
4967 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
4970 window_copy_update_cursor(wme
, px
, data
->cy
);
4971 if (window_copy_update_selection(wme
, 1, 0))
4972 window_copy_redraw_lines(wme
, data
->cy
, 1);
4976 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
4978 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4980 px
= screen_size_x(data
->backing
);
4982 px
= window_copy_find_length(wme
, py
);
4983 window_copy_update_cursor(wme
, px
, data
->cy
);
4984 if (window_copy_update_selection(wme
, 1, 0))
4985 window_copy_redraw_lines(wme
, data
->cy
, 1);
4987 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
4989 window_copy_update_cursor(wme
, 0, data
->cy
);
4990 if (window_copy_update_selection(wme
, 1, 0))
4991 window_copy_redraw_lines(wme
, data
->cy
, 1);
4996 window_copy_cursor_down(struct window_mode_entry
*wme
, int scroll_only
)
4998 struct window_copy_mode_data
*data
= wme
->data
;
4999 struct screen
*s
= &data
->screen
;
5000 u_int ox
, oy
, px
, py
;
5003 norectsel
= data
->screen
.sel
== NULL
|| !data
->rectflag
;
5004 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5005 ox
= window_copy_find_length(wme
, oy
);
5006 if (norectsel
&& data
->cx
!= ox
) {
5007 data
->lastcx
= data
->cx
;
5011 if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
&& oy
== data
->endsely
)
5012 window_copy_other_end(wme
);
5014 if (scroll_only
|| data
->cy
== screen_size_y(s
) - 1) {
5016 data
->cx
= data
->lastcx
;
5017 window_copy_scroll_up(wme
, 1);
5018 if (scroll_only
&& data
->cy
> 0)
5019 window_copy_redraw_lines(wme
, data
->cy
- 1, 2);
5022 window_copy_update_cursor(wme
, data
->lastcx
,
5025 window_copy_update_cursor(wme
, data
->cx
, data
->cy
+ 1);
5026 if (window_copy_update_selection(wme
, 1, 0))
5027 window_copy_redraw_lines(wme
, data
->cy
- 1, 2);
5031 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5032 px
= window_copy_find_length(wme
, py
);
5033 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
5036 window_copy_update_cursor(wme
, px
, data
->cy
);
5037 if (window_copy_update_selection(wme
, 1, 0))
5038 window_copy_redraw_lines(wme
, data
->cy
, 1);
5042 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
5044 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5046 px
= screen_size_x(data
->backing
);
5048 px
= window_copy_find_length(wme
, py
);
5049 window_copy_update_cursor(wme
, px
, data
->cy
);
5050 if (window_copy_update_selection(wme
, 1, 0))
5051 window_copy_redraw_lines(wme
, data
->cy
, 1);
5053 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
5055 window_copy_update_cursor(wme
, 0, data
->cy
);
5056 if (window_copy_update_selection(wme
, 1, 0))
5057 window_copy_redraw_lines(wme
, data
->cy
, 1);
5062 window_copy_cursor_jump(struct window_mode_entry
*wme
)
5064 struct window_copy_mode_data
*data
= wme
->data
;
5065 struct screen
*back_s
= data
->backing
;
5066 struct grid_reader gr
;
5067 u_int px
, py
, oldy
, hsize
;
5070 hsize
= screen_hsize(back_s
);
5071 py
= hsize
+ data
->cy
- data
->oy
;
5074 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5075 if (grid_reader_cursor_jump(&gr
, data
->jumpchar
)) {
5076 grid_reader_get_cursor(&gr
, &px
, &py
);
5077 window_copy_acquire_cursor_down(wme
, hsize
,
5078 screen_size_y(back_s
), data
->oy
, oldy
, px
, py
, 0);
5083 window_copy_cursor_jump_back(struct window_mode_entry
*wme
)
5085 struct window_copy_mode_data
*data
= wme
->data
;
5086 struct screen
*back_s
= data
->backing
;
5087 struct grid_reader gr
;
5088 u_int px
, py
, oldy
, hsize
;
5091 hsize
= screen_hsize(back_s
);
5092 py
= hsize
+ data
->cy
- data
->oy
;
5095 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5096 grid_reader_cursor_left(&gr
, 0);
5097 if (grid_reader_cursor_jump_back(&gr
, data
->jumpchar
)) {
5098 grid_reader_get_cursor(&gr
, &px
, &py
);
5099 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
,
5105 window_copy_cursor_jump_to(struct window_mode_entry
*wme
)
5107 struct window_copy_mode_data
*data
= wme
->data
;
5108 struct screen
*back_s
= data
->backing
;
5109 struct grid_reader gr
;
5110 u_int px
, py
, oldy
, hsize
;
5113 hsize
= screen_hsize(back_s
);
5114 py
= hsize
+ data
->cy
- data
->oy
;
5117 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5118 if (grid_reader_cursor_jump(&gr
, data
->jumpchar
)) {
5119 grid_reader_cursor_left(&gr
, 1);
5120 grid_reader_get_cursor(&gr
, &px
, &py
);
5121 window_copy_acquire_cursor_down(wme
, hsize
,
5122 screen_size_y(back_s
), data
->oy
, oldy
, px
, py
, 0);
5127 window_copy_cursor_jump_to_back(struct window_mode_entry
*wme
)
5129 struct window_copy_mode_data
*data
= wme
->data
;
5130 struct screen
*back_s
= data
->backing
;
5131 struct grid_reader gr
;
5132 u_int px
, py
, oldy
, hsize
;
5135 hsize
= screen_hsize(back_s
);
5136 py
= hsize
+ data
->cy
- data
->oy
;
5139 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5140 grid_reader_cursor_left(&gr
, 0);
5141 grid_reader_cursor_left(&gr
, 0);
5142 if (grid_reader_cursor_jump_back(&gr
, data
->jumpchar
)) {
5143 grid_reader_cursor_right(&gr
, 1, 0);
5144 grid_reader_get_cursor(&gr
, &px
, &py
);
5145 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
,
5151 window_copy_cursor_next_word(struct window_mode_entry
*wme
,
5152 const char *separators
)
5154 struct window_copy_mode_data
*data
= wme
->data
;
5155 struct screen
*back_s
= data
->backing
;
5156 struct grid_reader gr
;
5157 u_int px
, py
, oldy
, hsize
;
5160 hsize
= screen_hsize(back_s
);
5161 py
= hsize
+ data
->cy
- data
->oy
;
5164 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5165 grid_reader_cursor_next_word(&gr
, separators
);
5166 grid_reader_get_cursor(&gr
, &px
, &py
);
5167 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
5168 data
->oy
, oldy
, px
, py
, 0);
5171 /* Compute the next place where a word ends. */
5173 window_copy_cursor_next_word_end_pos(struct window_mode_entry
*wme
,
5174 const char *separators
, u_int
*ppx
, u_int
*ppy
)
5176 struct window_pane
*wp
= wme
->wp
;
5177 struct window_copy_mode_data
*data
= wme
->data
;
5178 struct options
*oo
= wp
->window
->options
;
5179 struct screen
*back_s
= data
->backing
;
5180 struct grid_reader gr
;
5181 u_int px
, py
, hsize
;
5184 hsize
= screen_hsize(back_s
);
5185 py
= hsize
+ data
->cy
- data
->oy
;
5187 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5188 if (options_get_number(oo
, "mode-keys") == MODEKEY_VI
) {
5189 if (!grid_reader_in_set(&gr
, WHITESPACE
))
5190 grid_reader_cursor_right(&gr
, 0, 0);
5191 grid_reader_cursor_next_word_end(&gr
, separators
);
5192 grid_reader_cursor_left(&gr
, 1);
5194 grid_reader_cursor_next_word_end(&gr
, separators
);
5195 grid_reader_get_cursor(&gr
, &px
, &py
);
5200 /* Move to the next place where a word ends. */
5202 window_copy_cursor_next_word_end(struct window_mode_entry
*wme
,
5203 const char *separators
, int no_reset
)
5205 struct window_pane
*wp
= wme
->wp
;
5206 struct window_copy_mode_data
*data
= wme
->data
;
5207 struct options
*oo
= wp
->window
->options
;
5208 struct screen
*back_s
= data
->backing
;
5209 struct grid_reader gr
;
5210 u_int px
, py
, oldy
, hsize
;
5213 hsize
= screen_hsize(back_s
);
5214 py
= hsize
+ data
->cy
- data
->oy
;
5217 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5218 if (options_get_number(oo
, "mode-keys") == MODEKEY_VI
) {
5219 if (!grid_reader_in_set(&gr
, WHITESPACE
))
5220 grid_reader_cursor_right(&gr
, 0, 0);
5221 grid_reader_cursor_next_word_end(&gr
, separators
);
5222 grid_reader_cursor_left(&gr
, 1);
5224 grid_reader_cursor_next_word_end(&gr
, separators
);
5225 grid_reader_get_cursor(&gr
, &px
, &py
);
5226 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
5227 data
->oy
, oldy
, px
, py
, no_reset
);
5230 /* Compute the previous place where a word begins. */
5232 window_copy_cursor_previous_word_pos(struct window_mode_entry
*wme
,
5233 const char *separators
, u_int
*ppx
, u_int
*ppy
)
5235 struct window_copy_mode_data
*data
= wme
->data
;
5236 struct screen
*back_s
= data
->backing
;
5237 struct grid_reader gr
;
5238 u_int px
, py
, hsize
;
5241 hsize
= screen_hsize(back_s
);
5242 py
= hsize
+ data
->cy
- data
->oy
;
5244 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5245 grid_reader_cursor_previous_word(&gr
, separators
, /* already= */ 0,
5246 /* stop_at_eol= */ 1);
5247 grid_reader_get_cursor(&gr
, &px
, &py
);
5252 /* Move to the previous place where a word begins. */
5254 window_copy_cursor_previous_word(struct window_mode_entry
*wme
,
5255 const char *separators
, int already
)
5257 struct window_copy_mode_data
*data
= wme
->data
;
5258 struct window
*w
= wme
->wp
->window
;
5259 struct screen
*back_s
= data
->backing
;
5260 struct grid_reader gr
;
5261 u_int px
, py
, oldy
, hsize
;
5264 if (options_get_number(w
->options
, "mode-keys") == MODEKEY_EMACS
)
5270 hsize
= screen_hsize(back_s
);
5271 py
= hsize
+ data
->cy
- data
->oy
;
5274 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5275 grid_reader_cursor_previous_word(&gr
, separators
, already
, stop_at_eol
);
5276 grid_reader_get_cursor(&gr
, &px
, &py
);
5277 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
5281 window_copy_scroll_up(struct window_mode_entry
*wme
, u_int ny
)
5283 struct window_pane
*wp
= wme
->wp
;
5284 struct window_copy_mode_data
*data
= wme
->data
;
5285 struct screen
*s
= &data
->screen
;
5286 struct screen_write_ctx ctx
;
5294 if (data
->searchmark
!= NULL
&& !data
->timeout
)
5295 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
5296 window_copy_update_selection(wme
, 0, 0);
5298 screen_write_start_pane(&ctx
, wp
, NULL
);
5299 screen_write_cursormove(&ctx
, 0, 0, 0);
5300 screen_write_deleteline(&ctx
, ny
, 8);
5301 window_copy_write_lines(wme
, &ctx
, screen_size_y(s
) - ny
, ny
);
5302 window_copy_write_line(wme
, &ctx
, 0);
5303 if (screen_size_y(s
) > 1)
5304 window_copy_write_line(wme
, &ctx
, 1);
5305 if (screen_size_y(s
) > 3)
5306 window_copy_write_line(wme
, &ctx
, screen_size_y(s
) - 2);
5307 if (s
->sel
!= NULL
&& screen_size_y(s
) > ny
)
5308 window_copy_write_line(wme
, &ctx
, screen_size_y(s
) - ny
- 1);
5309 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
5310 screen_write_stop(&ctx
);
5314 window_copy_scroll_down(struct window_mode_entry
*wme
, u_int ny
)
5316 struct window_pane
*wp
= wme
->wp
;
5317 struct window_copy_mode_data
*data
= wme
->data
;
5318 struct screen
*s
= &data
->screen
;
5319 struct screen_write_ctx ctx
;
5321 if (ny
> screen_hsize(data
->backing
))
5324 if (data
->oy
> screen_hsize(data
->backing
) - ny
)
5325 ny
= screen_hsize(data
->backing
) - data
->oy
;
5330 if (data
->searchmark
!= NULL
&& !data
->timeout
)
5331 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
5332 window_copy_update_selection(wme
, 0, 0);
5334 screen_write_start_pane(&ctx
, wp
, NULL
);
5335 screen_write_cursormove(&ctx
, 0, 0, 0);
5336 screen_write_insertline(&ctx
, ny
, 8);
5337 window_copy_write_lines(wme
, &ctx
, 0, ny
);
5338 if (s
->sel
!= NULL
&& screen_size_y(s
) > ny
)
5339 window_copy_write_line(wme
, &ctx
, ny
);
5340 else if (ny
== 1) /* nuke position */
5341 window_copy_write_line(wme
, &ctx
, 1);
5342 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
5343 screen_write_stop(&ctx
);
5347 window_copy_rectangle_set(struct window_mode_entry
*wme
, int rectflag
)
5349 struct window_copy_mode_data
*data
= wme
->data
;
5352 data
->rectflag
= rectflag
;
5354 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5355 px
= window_copy_find_length(wme
, py
);
5357 window_copy_update_cursor(wme
, px
, data
->cy
);
5359 window_copy_update_selection(wme
, 1, 0);
5360 window_copy_redraw_screen(wme
);
5364 window_copy_move_mouse(struct mouse_event
*m
)
5366 struct window_pane
*wp
;
5367 struct window_mode_entry
*wme
;
5370 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5373 wme
= TAILQ_FIRST(&wp
->modes
);
5376 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5379 if (cmd_mouse_at(wp
, m
, &x
, &y
, 0) != 0)
5382 window_copy_update_cursor(wme
, x
, y
);
5386 window_copy_start_drag(struct client
*c
, struct mouse_event
*m
)
5388 struct window_pane
*wp
;
5389 struct window_mode_entry
*wme
;
5390 struct window_copy_mode_data
*data
;
5396 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5399 wme
= TAILQ_FIRST(&wp
->modes
);
5402 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5405 if (cmd_mouse_at(wp
, m
, &x
, &y
, 1) != 0)
5408 c
->tty
.mouse_drag_update
= window_copy_drag_update
;
5409 c
->tty
.mouse_drag_release
= window_copy_drag_release
;
5412 yg
= screen_hsize(data
->backing
) + y
- data
->oy
;
5413 if (x
< data
->selrx
|| x
> data
->endselrx
|| yg
!= data
->selry
)
5414 data
->selflag
= SEL_CHAR
;
5415 switch (data
->selflag
) {
5417 if (data
->separators
!= NULL
) {
5418 window_copy_update_cursor(wme
, x
, y
);
5419 window_copy_cursor_previous_word_pos(wme
,
5420 data
->separators
, &x
, &y
);
5421 y
-= screen_hsize(data
->backing
) - data
->oy
;
5423 window_copy_update_cursor(wme
, x
, y
);
5426 window_copy_update_cursor(wme
, 0, y
);
5429 window_copy_update_cursor(wme
, x
, y
);
5430 window_copy_start_selection(wme
);
5434 window_copy_redraw_screen(wme
);
5435 window_copy_drag_update(c
, m
);
5439 window_copy_drag_update(struct client
*c
, struct mouse_event
*m
)
5441 struct window_pane
*wp
;
5442 struct window_mode_entry
*wme
;
5443 struct window_copy_mode_data
*data
;
5444 u_int x
, y
, old_cx
, old_cy
;
5445 struct timeval tv
= {
5446 .tv_usec
= WINDOW_COPY_DRAG_REPEAT_TIME
5452 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5455 wme
= TAILQ_FIRST(&wp
->modes
);
5458 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5462 evtimer_del(&data
->dragtimer
);
5464 if (cmd_mouse_at(wp
, m
, &x
, &y
, 0) != 0)
5469 window_copy_update_cursor(wme
, x
, y
);
5470 if (window_copy_update_selection(wme
, 1, 0))
5471 window_copy_redraw_selection(wme
, old_cy
);
5472 if (old_cy
!= data
->cy
|| old_cx
== data
->cx
) {
5474 evtimer_add(&data
->dragtimer
, &tv
);
5475 window_copy_cursor_up(wme
, 1);
5476 } else if (y
== screen_size_y(&data
->screen
) - 1) {
5477 evtimer_add(&data
->dragtimer
, &tv
);
5478 window_copy_cursor_down(wme
, 1);
5484 window_copy_drag_release(struct client
*c
, struct mouse_event
*m
)
5486 struct window_pane
*wp
;
5487 struct window_mode_entry
*wme
;
5488 struct window_copy_mode_data
*data
;
5493 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5496 wme
= TAILQ_FIRST(&wp
->modes
);
5499 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5503 evtimer_del(&data
->dragtimer
);
5507 window_copy_jump_to_mark(struct window_mode_entry
*wme
)
5509 struct window_copy_mode_data
*data
= wme
->data
;
5513 tmy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5514 data
->cx
= data
->mx
;
5515 if (data
->my
< screen_hsize(data
->backing
)) {
5517 data
->oy
= screen_hsize(data
->backing
) - data
->my
;
5519 data
->cy
= data
->my
- screen_hsize(data
->backing
);
5525 window_copy_update_selection(wme
, 0, 0);
5526 window_copy_redraw_screen(wme
);
5529 /* Scroll up if the cursor went off the visible screen. */
5531 window_copy_acquire_cursor_up(struct window_mode_entry
*wme
, u_int hsize
,
5532 u_int oy
, u_int oldy
, u_int px
, u_int py
)
5534 u_int cy
, yy
, ny
, nd
;
5547 window_copy_cursor_up(wme
, 1);
5550 window_copy_update_cursor(wme
, px
, cy
);
5551 if (window_copy_update_selection(wme
, 1, 0))
5552 window_copy_redraw_lines(wme
, cy
, nd
);
5555 /* Scroll down if the cursor went off the visible screen. */
5557 window_copy_acquire_cursor_down(struct window_mode_entry
*wme
, u_int hsize
,
5558 u_int sy
, u_int oy
, u_int oldy
, u_int px
, u_int py
, int no_reset
)
5560 u_int cy
, yy
, ny
, nd
;
5562 cy
= py
- hsize
+ oy
;
5573 window_copy_cursor_down(wme
, 1);
5577 window_copy_update_cursor(wme
, px
, yy
);
5579 window_copy_update_cursor(wme
, px
, cy
);
5580 if (window_copy_update_selection(wme
, 1, no_reset
))
5581 window_copy_redraw_lines(wme
, oldy
, nd
);