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 /* Scroll line containing the cursor to the given position. */
1254 static enum window_copy_cmd_action
1255 window_copy_cmd_scroll_to(struct window_copy_cmd_state
*cs
, u_int to
)
1257 struct window_mode_entry
*wme
= cs
->wme
;
1258 struct window_copy_mode_data
*data
= wme
->data
;
1260 int scroll_up
; /* >0 up, <0 down */
1262 scroll_up
= data
->cy
- to
;
1263 delta
= abs(scroll_up
);
1264 oy
= screen_hsize(data
->backing
) - data
->oy
;
1267 * oy is the maximum scroll down amount, while data->oy is the maximum
1270 if (scroll_up
> 0 && data
->oy
>= delta
) {
1271 window_copy_scroll_up(wme
, delta
);
1273 } else if (scroll_up
< 0 && oy
>= delta
) {
1274 window_copy_scroll_down(wme
, delta
);
1278 window_copy_update_selection(wme
, 0, 0);
1279 return (WINDOW_COPY_CMD_REDRAW
);
1282 /* Scroll line containing the cursor to the bottom. */
1283 static enum window_copy_cmd_action
1284 window_copy_cmd_scroll_bottom(struct window_copy_cmd_state
*cs
)
1286 struct window_copy_mode_data
*data
= cs
->wme
->data
;
1289 bottom
= screen_size_y(&data
->screen
) - 1;
1290 return (window_copy_cmd_scroll_to(cs
, bottom
));
1293 /* Scroll line containing the cursor to the middle. */
1294 static enum window_copy_cmd_action
1295 window_copy_cmd_scroll_middle(struct window_copy_cmd_state
*cs
)
1297 struct window_copy_mode_data
*data
= cs
->wme
->data
;
1300 mid_value
= (screen_size_y(&data
->screen
) - 1) / 2;
1301 return (window_copy_cmd_scroll_to(cs
, mid_value
));
1304 /* Scroll line containing the cursor to the top. */
1305 static enum window_copy_cmd_action
1306 window_copy_cmd_scroll_top(struct window_copy_cmd_state
*cs
)
1308 return (window_copy_cmd_scroll_to(cs
, 0));
1311 static enum window_copy_cmd_action
1312 window_copy_cmd_cursor_up(struct window_copy_cmd_state
*cs
)
1314 struct window_mode_entry
*wme
= cs
->wme
;
1315 u_int np
= wme
->prefix
;
1317 for (; np
!= 0; np
--)
1318 window_copy_cursor_up(wme
, 0);
1319 return (WINDOW_COPY_CMD_NOTHING
);
1322 static enum window_copy_cmd_action
1323 window_copy_cmd_end_of_line(struct window_copy_cmd_state
*cs
)
1325 struct window_mode_entry
*wme
= cs
->wme
;
1327 window_copy_cursor_end_of_line(wme
);
1328 return (WINDOW_COPY_CMD_NOTHING
);
1331 static enum window_copy_cmd_action
1332 window_copy_cmd_halfpage_down(struct window_copy_cmd_state
*cs
)
1334 struct window_mode_entry
*wme
= cs
->wme
;
1335 struct window_copy_mode_data
*data
= wme
->data
;
1336 u_int np
= wme
->prefix
;
1338 for (; np
!= 0; np
--) {
1339 if (window_copy_pagedown(wme
, 1, data
->scroll_exit
))
1340 return (WINDOW_COPY_CMD_CANCEL
);
1342 return (WINDOW_COPY_CMD_NOTHING
);
1345 static enum window_copy_cmd_action
1346 window_copy_cmd_halfpage_down_and_cancel(struct window_copy_cmd_state
*cs
)
1349 struct window_mode_entry
*wme
= cs
->wme
;
1350 u_int np
= wme
->prefix
;
1352 for (; np
!= 0; np
--) {
1353 if (window_copy_pagedown(wme
, 1, 1))
1354 return (WINDOW_COPY_CMD_CANCEL
);
1356 return (WINDOW_COPY_CMD_NOTHING
);
1359 static enum window_copy_cmd_action
1360 window_copy_cmd_halfpage_up(struct window_copy_cmd_state
*cs
)
1362 struct window_mode_entry
*wme
= cs
->wme
;
1363 u_int np
= wme
->prefix
;
1365 for (; np
!= 0; np
--)
1366 window_copy_pageup1(wme
, 1);
1367 return (WINDOW_COPY_CMD_NOTHING
);
1370 static enum window_copy_cmd_action
1371 window_copy_cmd_toggle_position(struct window_copy_cmd_state
*cs
)
1373 struct window_mode_entry
*wme
= cs
->wme
;
1374 struct window_copy_mode_data
*data
= wme
->data
;
1376 data
->hide_position
= !data
->hide_position
;
1377 return (WINDOW_COPY_CMD_REDRAW
);
1380 static enum window_copy_cmd_action
1381 window_copy_cmd_history_bottom(struct window_copy_cmd_state
*cs
)
1383 struct window_mode_entry
*wme
= cs
->wme
;
1384 struct window_copy_mode_data
*data
= wme
->data
;
1385 struct screen
*s
= data
->backing
;
1388 oy
= screen_hsize(s
) + data
->cy
- data
->oy
;
1389 if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
&& oy
== data
->endsely
)
1390 window_copy_other_end(wme
);
1392 data
->cy
= screen_size_y(&data
->screen
) - 1;
1393 data
->cx
= window_copy_find_length(wme
, screen_hsize(s
) + data
->cy
);
1396 if (data
->searchmark
!= NULL
&& !data
->timeout
)
1397 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
1398 window_copy_update_selection(wme
, 1, 0);
1399 return (WINDOW_COPY_CMD_REDRAW
);
1402 static enum window_copy_cmd_action
1403 window_copy_cmd_history_top(struct window_copy_cmd_state
*cs
)
1405 struct window_mode_entry
*wme
= cs
->wme
;
1406 struct window_copy_mode_data
*data
= wme
->data
;
1409 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1410 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
&& oy
== data
->sely
)
1411 window_copy_other_end(wme
);
1415 data
->oy
= screen_hsize(data
->backing
);
1417 if (data
->searchmark
!= NULL
&& !data
->timeout
)
1418 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
1419 window_copy_update_selection(wme
, 1, 0);
1420 return (WINDOW_COPY_CMD_REDRAW
);
1423 static enum window_copy_cmd_action
1424 window_copy_cmd_jump_again(struct window_copy_cmd_state
*cs
)
1426 struct window_mode_entry
*wme
= cs
->wme
;
1427 struct window_copy_mode_data
*data
= wme
->data
;
1428 u_int np
= wme
->prefix
;
1430 switch (data
->jumptype
) {
1431 case WINDOW_COPY_JUMPFORWARD
:
1432 for (; np
!= 0; np
--)
1433 window_copy_cursor_jump(wme
);
1435 case WINDOW_COPY_JUMPBACKWARD
:
1436 for (; np
!= 0; np
--)
1437 window_copy_cursor_jump_back(wme
);
1439 case WINDOW_COPY_JUMPTOFORWARD
:
1440 for (; np
!= 0; np
--)
1441 window_copy_cursor_jump_to(wme
);
1443 case WINDOW_COPY_JUMPTOBACKWARD
:
1444 for (; np
!= 0; np
--)
1445 window_copy_cursor_jump_to_back(wme
);
1448 return (WINDOW_COPY_CMD_NOTHING
);
1451 static enum window_copy_cmd_action
1452 window_copy_cmd_jump_reverse(struct window_copy_cmd_state
*cs
)
1454 struct window_mode_entry
*wme
= cs
->wme
;
1455 struct window_copy_mode_data
*data
= wme
->data
;
1456 u_int np
= wme
->prefix
;
1458 switch (data
->jumptype
) {
1459 case WINDOW_COPY_JUMPFORWARD
:
1460 for (; np
!= 0; np
--)
1461 window_copy_cursor_jump_back(wme
);
1463 case WINDOW_COPY_JUMPBACKWARD
:
1464 for (; np
!= 0; np
--)
1465 window_copy_cursor_jump(wme
);
1467 case WINDOW_COPY_JUMPTOFORWARD
:
1468 for (; np
!= 0; np
--)
1469 window_copy_cursor_jump_to_back(wme
);
1471 case WINDOW_COPY_JUMPTOBACKWARD
:
1472 for (; np
!= 0; np
--)
1473 window_copy_cursor_jump_to(wme
);
1476 return (WINDOW_COPY_CMD_NOTHING
);
1479 static enum window_copy_cmd_action
1480 window_copy_cmd_middle_line(struct window_copy_cmd_state
*cs
)
1482 struct window_mode_entry
*wme
= cs
->wme
;
1483 struct window_copy_mode_data
*data
= wme
->data
;
1486 data
->cy
= (screen_size_y(&data
->screen
) - 1) / 2;
1488 window_copy_update_selection(wme
, 1, 0);
1489 return (WINDOW_COPY_CMD_REDRAW
);
1492 static enum window_copy_cmd_action
1493 window_copy_cmd_previous_matching_bracket(struct window_copy_cmd_state
*cs
)
1495 struct window_mode_entry
*wme
= cs
->wme
;
1496 u_int np
= wme
->prefix
;
1497 struct window_copy_mode_data
*data
= wme
->data
;
1498 struct screen
*s
= data
->backing
;
1499 char open
[] = "{[(", close
[] = "}])";
1500 char tried
, found
, start
, *cp
;
1501 u_int px
, py
, xx
, n
;
1502 struct grid_cell gc
;
1505 for (; np
!= 0; np
--) {
1506 /* Get cursor position and line length. */
1508 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1509 xx
= window_copy_find_length(wme
, py
);
1514 * Get the current character. If not on a bracket, try the
1515 * previous. If still not, then behave like previous-word.
1519 grid_get_cell(s
->grid
, px
, py
, &gc
);
1520 if (gc
.data
.size
!= 1 || (gc
.flags
& GRID_FLAG_PADDING
))
1523 found
= *gc
.data
.data
;
1524 cp
= strchr(close
, found
);
1527 if (data
->modekeys
== MODEKEY_EMACS
) {
1528 if (!tried
&& px
> 0) {
1533 window_copy_cursor_previous_word(wme
, close
, 1);
1537 start
= open
[cp
- close
];
1539 /* Walk backward until the matching bracket is reached. */
1550 xx
= window_copy_find_length(wme
, py
);
1551 } while (xx
== 0 && py
> 0);
1552 if (xx
== 0 && py
== 0) {
1560 grid_get_cell(s
->grid
, px
, py
, &gc
);
1561 if (gc
.data
.size
== 1 &&
1562 (~gc
.flags
& GRID_FLAG_PADDING
)) {
1563 if (*gc
.data
.data
== found
)
1565 else if (*gc
.data
.data
== start
)
1570 /* Move the cursor to the found location if any. */
1572 window_copy_scroll_to(wme
, px
, py
, 0);
1575 return (WINDOW_COPY_CMD_NOTHING
);
1578 static enum window_copy_cmd_action
1579 window_copy_cmd_next_matching_bracket(struct window_copy_cmd_state
*cs
)
1581 struct window_mode_entry
*wme
= cs
->wme
;
1582 u_int np
= wme
->prefix
;
1583 struct window_copy_mode_data
*data
= wme
->data
;
1584 struct screen
*s
= data
->backing
;
1585 char open
[] = "{[(", close
[] = "}])";
1586 char tried
, found
, end
, *cp
;
1587 u_int px
, py
, xx
, yy
, sx
, sy
, n
;
1588 struct grid_cell gc
;
1590 struct grid_line
*gl
;
1592 for (; np
!= 0; np
--) {
1593 /* Get cursor position and line length. */
1595 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1596 xx
= window_copy_find_length(wme
, py
);
1597 yy
= screen_hsize(s
) + screen_size_y(s
) - 1;
1602 * Get the current character. If not on a bracket, try the
1603 * next. If still not, then behave like next-word.
1607 grid_get_cell(s
->grid
, px
, py
, &gc
);
1608 if (gc
.data
.size
!= 1 || (gc
.flags
& GRID_FLAG_PADDING
))
1611 found
= *gc
.data
.data
;
1614 * In vi mode, attempt to move to previous bracket if a
1615 * closing bracket is found first. If this fails,
1616 * return to the original cursor position.
1618 cp
= strchr(close
, found
);
1619 if (cp
!= NULL
&& data
->modekeys
== MODEKEY_VI
) {
1621 sy
= screen_hsize(s
) + data
->cy
- data
->oy
;
1623 window_copy_scroll_to(wme
, px
, py
, 0);
1624 window_copy_cmd_previous_matching_bracket(cs
);
1627 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1628 grid_get_cell(s
->grid
, px
, py
, &gc
);
1629 if (gc
.data
.size
== 1 &&
1630 (~gc
.flags
& GRID_FLAG_PADDING
) &&
1631 strchr(close
, *gc
.data
.data
) != NULL
)
1632 window_copy_scroll_to(wme
, sx
, sy
, 0);
1636 cp
= strchr(open
, found
);
1639 if (data
->modekeys
== MODEKEY_EMACS
) {
1640 if (!tried
&& px
<= xx
) {
1645 window_copy_cursor_next_word_end(wme
, open
, 0);
1648 /* For vi, continue searching for bracket until EOL. */
1652 gl
= grid_get_line(s
->grid
, py
);
1653 if (~gl
->flags
& GRID_LINE_WRAPPED
)
1655 if (gl
->cellsize
> s
->grid
->sx
)
1659 xx
= window_copy_find_length(wme
, py
);
1664 end
= close
[cp
- open
];
1666 /* Walk forward until the matching bracket is reached. */
1677 xx
= window_copy_find_length(wme
, py
);
1681 grid_get_cell(s
->grid
, px
, py
, &gc
);
1682 if (gc
.data
.size
== 1 &&
1683 (~gc
.flags
& GRID_FLAG_PADDING
)) {
1684 if (*gc
.data
.data
== found
)
1686 else if (*gc
.data
.data
== end
)
1691 /* Move the cursor to the found location if any. */
1693 window_copy_scroll_to(wme
, px
, py
, 0);
1696 return (WINDOW_COPY_CMD_NOTHING
);
1699 static enum window_copy_cmd_action
1700 window_copy_cmd_next_paragraph(struct window_copy_cmd_state
*cs
)
1702 struct window_mode_entry
*wme
= cs
->wme
;
1703 u_int np
= wme
->prefix
;
1705 for (; np
!= 0; np
--)
1706 window_copy_next_paragraph(wme
);
1707 return (WINDOW_COPY_CMD_NOTHING
);
1710 static enum window_copy_cmd_action
1711 window_copy_cmd_next_space(struct window_copy_cmd_state
*cs
)
1713 struct window_mode_entry
*wme
= cs
->wme
;
1714 u_int np
= wme
->prefix
;
1716 for (; np
!= 0; np
--)
1717 window_copy_cursor_next_word(wme
, "");
1718 return (WINDOW_COPY_CMD_NOTHING
);
1721 static enum window_copy_cmd_action
1722 window_copy_cmd_next_space_end(struct window_copy_cmd_state
*cs
)
1724 struct window_mode_entry
*wme
= cs
->wme
;
1725 u_int np
= wme
->prefix
;
1727 for (; np
!= 0; np
--)
1728 window_copy_cursor_next_word_end(wme
, "", 0);
1729 return (WINDOW_COPY_CMD_NOTHING
);
1732 static enum window_copy_cmd_action
1733 window_copy_cmd_next_word(struct window_copy_cmd_state
*cs
)
1735 struct window_mode_entry
*wme
= cs
->wme
;
1736 u_int np
= wme
->prefix
;
1737 const char *separators
;
1739 separators
= options_get_string(cs
->s
->options
, "word-separators");
1741 for (; np
!= 0; np
--)
1742 window_copy_cursor_next_word(wme
, separators
);
1743 return (WINDOW_COPY_CMD_NOTHING
);
1746 static enum window_copy_cmd_action
1747 window_copy_cmd_next_word_end(struct window_copy_cmd_state
*cs
)
1749 struct window_mode_entry
*wme
= cs
->wme
;
1750 u_int np
= wme
->prefix
;
1751 const char *separators
;
1753 separators
= options_get_string(cs
->s
->options
, "word-separators");
1755 for (; np
!= 0; np
--)
1756 window_copy_cursor_next_word_end(wme
, separators
, 0);
1757 return (WINDOW_COPY_CMD_NOTHING
);
1760 static enum window_copy_cmd_action
1761 window_copy_cmd_other_end(struct window_copy_cmd_state
*cs
)
1763 struct window_mode_entry
*wme
= cs
->wme
;
1764 u_int np
= wme
->prefix
;
1765 struct window_copy_mode_data
*data
= wme
->data
;
1767 data
->selflag
= SEL_CHAR
;
1769 window_copy_other_end(wme
);
1770 return (WINDOW_COPY_CMD_NOTHING
);
1773 static enum window_copy_cmd_action
1774 window_copy_cmd_page_down(struct window_copy_cmd_state
*cs
)
1776 struct window_mode_entry
*wme
= cs
->wme
;
1777 struct window_copy_mode_data
*data
= wme
->data
;
1778 u_int np
= wme
->prefix
;
1780 for (; np
!= 0; np
--) {
1781 if (window_copy_pagedown(wme
, 0, data
->scroll_exit
))
1782 return (WINDOW_COPY_CMD_CANCEL
);
1784 return (WINDOW_COPY_CMD_NOTHING
);
1787 static enum window_copy_cmd_action
1788 window_copy_cmd_page_down_and_cancel(struct window_copy_cmd_state
*cs
)
1790 struct window_mode_entry
*wme
= cs
->wme
;
1791 u_int np
= wme
->prefix
;
1793 for (; np
!= 0; np
--) {
1794 if (window_copy_pagedown(wme
, 0, 1))
1795 return (WINDOW_COPY_CMD_CANCEL
);
1797 return (WINDOW_COPY_CMD_NOTHING
);
1800 static enum window_copy_cmd_action
1801 window_copy_cmd_page_up(struct window_copy_cmd_state
*cs
)
1803 struct window_mode_entry
*wme
= cs
->wme
;
1804 u_int np
= wme
->prefix
;
1806 for (; np
!= 0; np
--)
1807 window_copy_pageup1(wme
, 0);
1808 return (WINDOW_COPY_CMD_NOTHING
);
1811 static enum window_copy_cmd_action
1812 window_copy_cmd_previous_paragraph(struct window_copy_cmd_state
*cs
)
1814 struct window_mode_entry
*wme
= cs
->wme
;
1815 u_int np
= wme
->prefix
;
1817 for (; np
!= 0; np
--)
1818 window_copy_previous_paragraph(wme
);
1819 return (WINDOW_COPY_CMD_NOTHING
);
1822 static enum window_copy_cmd_action
1823 window_copy_cmd_previous_space(struct window_copy_cmd_state
*cs
)
1825 struct window_mode_entry
*wme
= cs
->wme
;
1826 u_int np
= wme
->prefix
;
1828 for (; np
!= 0; np
--)
1829 window_copy_cursor_previous_word(wme
, "", 1);
1830 return (WINDOW_COPY_CMD_NOTHING
);
1833 static enum window_copy_cmd_action
1834 window_copy_cmd_previous_word(struct window_copy_cmd_state
*cs
)
1836 struct window_mode_entry
*wme
= cs
->wme
;
1837 u_int np
= wme
->prefix
;
1838 const char *separators
;
1840 separators
= options_get_string(cs
->s
->options
, "word-separators");
1842 for (; np
!= 0; np
--)
1843 window_copy_cursor_previous_word(wme
, separators
, 1);
1844 return (WINDOW_COPY_CMD_NOTHING
);
1847 static enum window_copy_cmd_action
1848 window_copy_cmd_rectangle_on(struct window_copy_cmd_state
*cs
)
1850 struct window_mode_entry
*wme
= cs
->wme
;
1851 struct window_copy_mode_data
*data
= wme
->data
;
1853 data
->lineflag
= LINE_SEL_NONE
;
1854 window_copy_rectangle_set(wme
, 1);
1856 return (WINDOW_COPY_CMD_NOTHING
);
1859 static enum window_copy_cmd_action
1860 window_copy_cmd_rectangle_off(struct window_copy_cmd_state
*cs
)
1862 struct window_mode_entry
*wme
= cs
->wme
;
1863 struct window_copy_mode_data
*data
= wme
->data
;
1865 data
->lineflag
= LINE_SEL_NONE
;
1866 window_copy_rectangle_set(wme
, 0);
1868 return (WINDOW_COPY_CMD_NOTHING
);
1871 static enum window_copy_cmd_action
1872 window_copy_cmd_rectangle_toggle(struct window_copy_cmd_state
*cs
)
1874 struct window_mode_entry
*wme
= cs
->wme
;
1875 struct window_copy_mode_data
*data
= wme
->data
;
1877 data
->lineflag
= LINE_SEL_NONE
;
1878 window_copy_rectangle_set(wme
, !data
->rectflag
);
1880 return (WINDOW_COPY_CMD_NOTHING
);
1883 static enum window_copy_cmd_action
1884 window_copy_cmd_scroll_down(struct window_copy_cmd_state
*cs
)
1886 struct window_mode_entry
*wme
= cs
->wme
;
1887 struct window_copy_mode_data
*data
= wme
->data
;
1888 u_int np
= wme
->prefix
;
1890 for (; np
!= 0; np
--)
1891 window_copy_cursor_down(wme
, 1);
1892 if (data
->scroll_exit
&& data
->oy
== 0)
1893 return (WINDOW_COPY_CMD_CANCEL
);
1894 return (WINDOW_COPY_CMD_NOTHING
);
1897 static enum window_copy_cmd_action
1898 window_copy_cmd_scroll_down_and_cancel(struct window_copy_cmd_state
*cs
)
1900 struct window_mode_entry
*wme
= cs
->wme
;
1901 struct window_copy_mode_data
*data
= wme
->data
;
1902 u_int np
= wme
->prefix
;
1904 for (; np
!= 0; np
--)
1905 window_copy_cursor_down(wme
, 1);
1907 return (WINDOW_COPY_CMD_CANCEL
);
1908 return (WINDOW_COPY_CMD_NOTHING
);
1911 static enum window_copy_cmd_action
1912 window_copy_cmd_scroll_up(struct window_copy_cmd_state
*cs
)
1914 struct window_mode_entry
*wme
= cs
->wme
;
1915 u_int np
= wme
->prefix
;
1917 for (; np
!= 0; np
--)
1918 window_copy_cursor_up(wme
, 1);
1919 return (WINDOW_COPY_CMD_NOTHING
);
1922 static enum window_copy_cmd_action
1923 window_copy_cmd_search_again(struct window_copy_cmd_state
*cs
)
1925 struct window_mode_entry
*wme
= cs
->wme
;
1926 struct window_copy_mode_data
*data
= wme
->data
;
1927 u_int np
= wme
->prefix
;
1929 if (data
->searchtype
== WINDOW_COPY_SEARCHUP
) {
1930 for (; np
!= 0; np
--)
1931 window_copy_search_up(wme
, data
->searchregex
);
1932 } else if (data
->searchtype
== WINDOW_COPY_SEARCHDOWN
) {
1933 for (; np
!= 0; np
--)
1934 window_copy_search_down(wme
, data
->searchregex
);
1936 return (WINDOW_COPY_CMD_NOTHING
);
1939 static enum window_copy_cmd_action
1940 window_copy_cmd_search_reverse(struct window_copy_cmd_state
*cs
)
1942 struct window_mode_entry
*wme
= cs
->wme
;
1943 struct window_copy_mode_data
*data
= wme
->data
;
1944 u_int np
= wme
->prefix
;
1946 if (data
->searchtype
== WINDOW_COPY_SEARCHUP
) {
1947 for (; np
!= 0; np
--)
1948 window_copy_search_down(wme
, data
->searchregex
);
1949 } else if (data
->searchtype
== WINDOW_COPY_SEARCHDOWN
) {
1950 for (; np
!= 0; np
--)
1951 window_copy_search_up(wme
, data
->searchregex
);
1953 return (WINDOW_COPY_CMD_NOTHING
);
1956 static enum window_copy_cmd_action
1957 window_copy_cmd_select_line(struct window_copy_cmd_state
*cs
)
1959 struct window_mode_entry
*wme
= cs
->wme
;
1960 struct window_copy_mode_data
*data
= wme
->data
;
1961 u_int np
= wme
->prefix
;
1963 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
1965 data
->selflag
= SEL_LINE
;
1966 data
->dx
= data
->cx
;
1967 data
->dy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1969 window_copy_cursor_start_of_line(wme
);
1970 data
->selrx
= data
->cx
;
1971 data
->selry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1972 data
->endselry
= data
->selry
;
1973 window_copy_start_selection(wme
);
1974 window_copy_cursor_end_of_line(wme
);
1975 data
->endselry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1976 data
->endselrx
= window_copy_find_length(wme
, data
->endselry
);
1977 for (; np
> 1; np
--) {
1978 window_copy_cursor_down(wme
, 0);
1979 window_copy_cursor_end_of_line(wme
);
1982 return (WINDOW_COPY_CMD_REDRAW
);
1985 static enum window_copy_cmd_action
1986 window_copy_cmd_select_word(struct window_copy_cmd_state
*cs
)
1988 struct window_mode_entry
*wme
= cs
->wme
;
1989 struct options
*session_options
= cs
->s
->options
;
1990 struct window_copy_mode_data
*data
= wme
->data
;
1991 u_int px
, py
, nextx
, nexty
;
1993 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
1995 data
->selflag
= SEL_WORD
;
1996 data
->dx
= data
->cx
;
1997 data
->dy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1999 data
->separators
= options_get_string(session_options
,
2001 window_copy_cursor_previous_word(wme
, data
->separators
, 0);
2003 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2006 window_copy_start_selection(wme
);
2008 /* Handle single character words. */
2011 if (grid_get_line(data
->backing
->grid
, nexty
)->flags
&
2012 GRID_LINE_WRAPPED
&& nextx
> screen_size_x(data
->backing
) - 1) {
2016 if (px
>= window_copy_find_length(wme
, py
) ||
2017 !window_copy_in_set(wme
, nextx
, nexty
, WHITESPACE
))
2018 window_copy_cursor_next_word_end(wme
, data
->separators
, 1);
2020 window_copy_update_cursor(wme
, px
, data
->cy
);
2021 if (window_copy_update_selection(wme
, 1, 1))
2022 window_copy_redraw_lines(wme
, data
->cy
, 1);
2024 data
->endselrx
= data
->cx
;
2025 data
->endselry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2026 if (data
->dy
> data
->endselry
) {
2027 data
->dy
= data
->endselry
;
2028 data
->dx
= data
->endselrx
;
2029 } else if (data
->dx
> data
->endselrx
)
2030 data
->dx
= data
->endselrx
;
2032 return (WINDOW_COPY_CMD_REDRAW
);
2035 static enum window_copy_cmd_action
2036 window_copy_cmd_set_mark(struct window_copy_cmd_state
*cs
)
2038 struct window_copy_mode_data
*data
= cs
->wme
->data
;
2040 data
->mx
= data
->cx
;
2041 data
->my
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2043 return (WINDOW_COPY_CMD_REDRAW
);
2046 static enum window_copy_cmd_action
2047 window_copy_cmd_start_of_line(struct window_copy_cmd_state
*cs
)
2049 struct window_mode_entry
*wme
= cs
->wme
;
2051 window_copy_cursor_start_of_line(wme
);
2052 return (WINDOW_COPY_CMD_NOTHING
);
2055 static enum window_copy_cmd_action
2056 window_copy_cmd_top_line(struct window_copy_cmd_state
*cs
)
2058 struct window_mode_entry
*wme
= cs
->wme
;
2059 struct window_copy_mode_data
*data
= wme
->data
;
2064 window_copy_update_selection(wme
, 1, 0);
2065 return (WINDOW_COPY_CMD_REDRAW
);
2068 static enum window_copy_cmd_action
2069 window_copy_cmd_copy_pipe_no_clear(struct window_copy_cmd_state
*cs
)
2071 struct window_mode_entry
*wme
= cs
->wme
;
2072 struct client
*c
= cs
->c
;
2073 struct session
*s
= cs
->s
;
2074 struct winlink
*wl
= cs
->wl
;
2075 struct window_pane
*wp
= wme
->wp
;
2076 char *command
= NULL
, *prefix
= NULL
;
2077 const char *arg1
= args_string(cs
->args
, 1);
2078 const char *arg2
= args_string(cs
->args
, 2);
2081 prefix
= format_single(NULL
, arg2
, c
, s
, wl
, wp
);
2083 if (s
!= NULL
&& arg1
!= NULL
&& *arg1
!= '\0')
2084 command
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
2085 window_copy_copy_pipe(wme
, s
, prefix
, command
);
2089 return (WINDOW_COPY_CMD_NOTHING
);
2092 static enum window_copy_cmd_action
2093 window_copy_cmd_copy_pipe(struct window_copy_cmd_state
*cs
)
2095 struct window_mode_entry
*wme
= cs
->wme
;
2097 window_copy_cmd_copy_pipe_no_clear(cs
);
2098 window_copy_clear_selection(wme
);
2099 return (WINDOW_COPY_CMD_REDRAW
);
2102 static enum window_copy_cmd_action
2103 window_copy_cmd_copy_pipe_and_cancel(struct window_copy_cmd_state
*cs
)
2105 struct window_mode_entry
*wme
= cs
->wme
;
2107 window_copy_cmd_copy_pipe_no_clear(cs
);
2108 window_copy_clear_selection(wme
);
2109 return (WINDOW_COPY_CMD_CANCEL
);
2112 static enum window_copy_cmd_action
2113 window_copy_cmd_pipe_no_clear(struct window_copy_cmd_state
*cs
)
2115 struct window_mode_entry
*wme
= cs
->wme
;
2116 struct client
*c
= cs
->c
;
2117 struct session
*s
= cs
->s
;
2118 struct winlink
*wl
= cs
->wl
;
2119 struct window_pane
*wp
= wme
->wp
;
2120 char *command
= NULL
;
2121 const char *arg1
= args_string(cs
->args
, 1);
2123 if (s
!= NULL
&& arg1
!= NULL
&& *arg1
!= '\0')
2124 command
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
2125 window_copy_pipe(wme
, s
, command
);
2128 return (WINDOW_COPY_CMD_NOTHING
);
2131 static enum window_copy_cmd_action
2132 window_copy_cmd_pipe(struct window_copy_cmd_state
*cs
)
2134 struct window_mode_entry
*wme
= cs
->wme
;
2136 window_copy_cmd_pipe_no_clear(cs
);
2137 window_copy_clear_selection(wme
);
2138 return (WINDOW_COPY_CMD_REDRAW
);
2141 static enum window_copy_cmd_action
2142 window_copy_cmd_pipe_and_cancel(struct window_copy_cmd_state
*cs
)
2144 struct window_mode_entry
*wme
= cs
->wme
;
2146 window_copy_cmd_pipe_no_clear(cs
);
2147 window_copy_clear_selection(wme
);
2148 return (WINDOW_COPY_CMD_CANCEL
);
2151 static enum window_copy_cmd_action
2152 window_copy_cmd_goto_line(struct window_copy_cmd_state
*cs
)
2154 struct window_mode_entry
*wme
= cs
->wme
;
2155 const char *arg1
= args_string(cs
->args
, 1);
2158 window_copy_goto_line(wme
, arg1
);
2159 return (WINDOW_COPY_CMD_NOTHING
);
2162 static enum window_copy_cmd_action
2163 window_copy_cmd_jump_backward(struct window_copy_cmd_state
*cs
)
2165 struct window_mode_entry
*wme
= cs
->wme
;
2166 struct window_copy_mode_data
*data
= wme
->data
;
2167 u_int np
= wme
->prefix
;
2168 const char *arg1
= args_string(cs
->args
, 1);
2170 if (*arg1
!= '\0') {
2171 data
->jumptype
= WINDOW_COPY_JUMPBACKWARD
;
2172 free(data
->jumpchar
);
2173 data
->jumpchar
= utf8_fromcstr(arg1
);
2174 for (; np
!= 0; np
--)
2175 window_copy_cursor_jump_back(wme
);
2177 return (WINDOW_COPY_CMD_NOTHING
);
2180 static enum window_copy_cmd_action
2181 window_copy_cmd_jump_forward(struct window_copy_cmd_state
*cs
)
2183 struct window_mode_entry
*wme
= cs
->wme
;
2184 struct window_copy_mode_data
*data
= wme
->data
;
2185 u_int np
= wme
->prefix
;
2186 const char *arg1
= args_string(cs
->args
, 1);
2188 if (*arg1
!= '\0') {
2189 data
->jumptype
= WINDOW_COPY_JUMPFORWARD
;
2190 free(data
->jumpchar
);
2191 data
->jumpchar
= utf8_fromcstr(arg1
);
2192 for (; np
!= 0; np
--)
2193 window_copy_cursor_jump(wme
);
2195 return (WINDOW_COPY_CMD_NOTHING
);
2198 static enum window_copy_cmd_action
2199 window_copy_cmd_jump_to_backward(struct window_copy_cmd_state
*cs
)
2201 struct window_mode_entry
*wme
= cs
->wme
;
2202 struct window_copy_mode_data
*data
= wme
->data
;
2203 u_int np
= wme
->prefix
;
2204 const char *arg1
= args_string(cs
->args
, 1);
2206 if (*arg1
!= '\0') {
2207 data
->jumptype
= WINDOW_COPY_JUMPTOBACKWARD
;
2208 free(data
->jumpchar
);
2209 data
->jumpchar
= utf8_fromcstr(arg1
);
2210 for (; np
!= 0; np
--)
2211 window_copy_cursor_jump_to_back(wme
);
2213 return (WINDOW_COPY_CMD_NOTHING
);
2216 static enum window_copy_cmd_action
2217 window_copy_cmd_jump_to_forward(struct window_copy_cmd_state
*cs
)
2219 struct window_mode_entry
*wme
= cs
->wme
;
2220 struct window_copy_mode_data
*data
= wme
->data
;
2221 u_int np
= wme
->prefix
;
2222 const char *arg1
= args_string(cs
->args
, 1);
2224 if (*arg1
!= '\0') {
2225 data
->jumptype
= WINDOW_COPY_JUMPTOFORWARD
;
2226 free(data
->jumpchar
);
2227 data
->jumpchar
= utf8_fromcstr(arg1
);
2228 for (; np
!= 0; np
--)
2229 window_copy_cursor_jump_to(wme
);
2231 return (WINDOW_COPY_CMD_NOTHING
);
2234 static enum window_copy_cmd_action
2235 window_copy_cmd_jump_to_mark(struct window_copy_cmd_state
*cs
)
2237 struct window_mode_entry
*wme
= cs
->wme
;
2239 window_copy_jump_to_mark(wme
);
2240 return (WINDOW_COPY_CMD_NOTHING
);
2243 static enum window_copy_cmd_action
2244 window_copy_cmd_search_backward(struct window_copy_cmd_state
*cs
)
2246 struct window_mode_entry
*wme
= cs
->wme
;
2247 struct window_copy_mode_data
*data
= wme
->data
;
2248 u_int np
= wme
->prefix
;
2250 if (!window_copy_expand_search_string(cs
))
2251 return (WINDOW_COPY_CMD_NOTHING
);
2253 if (data
->searchstr
!= NULL
) {
2254 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2255 data
->searchregex
= 1;
2257 for (; np
!= 0; np
--)
2258 window_copy_search_up(wme
, 1);
2260 return (WINDOW_COPY_CMD_NOTHING
);
2263 static enum window_copy_cmd_action
2264 window_copy_cmd_search_backward_text(struct window_copy_cmd_state
*cs
)
2266 struct window_mode_entry
*wme
= cs
->wme
;
2267 struct window_copy_mode_data
*data
= wme
->data
;
2268 u_int np
= wme
->prefix
;
2270 if (!window_copy_expand_search_string(cs
))
2271 return (WINDOW_COPY_CMD_NOTHING
);
2273 if (data
->searchstr
!= NULL
) {
2274 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2275 data
->searchregex
= 0;
2277 for (; np
!= 0; np
--)
2278 window_copy_search_up(wme
, 0);
2280 return (WINDOW_COPY_CMD_NOTHING
);
2283 static enum window_copy_cmd_action
2284 window_copy_cmd_search_forward(struct window_copy_cmd_state
*cs
)
2286 struct window_mode_entry
*wme
= cs
->wme
;
2287 struct window_copy_mode_data
*data
= wme
->data
;
2288 u_int np
= wme
->prefix
;
2290 if (!window_copy_expand_search_string(cs
))
2291 return (WINDOW_COPY_CMD_NOTHING
);
2293 if (data
->searchstr
!= NULL
) {
2294 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2295 data
->searchregex
= 1;
2297 for (; np
!= 0; np
--)
2298 window_copy_search_down(wme
, 1);
2300 return (WINDOW_COPY_CMD_NOTHING
);
2303 static enum window_copy_cmd_action
2304 window_copy_cmd_search_forward_text(struct window_copy_cmd_state
*cs
)
2306 struct window_mode_entry
*wme
= cs
->wme
;
2307 struct window_copy_mode_data
*data
= wme
->data
;
2308 u_int np
= wme
->prefix
;
2310 if (!window_copy_expand_search_string(cs
))
2311 return (WINDOW_COPY_CMD_NOTHING
);
2313 if (data
->searchstr
!= NULL
) {
2314 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2315 data
->searchregex
= 0;
2317 for (; np
!= 0; np
--)
2318 window_copy_search_down(wme
, 0);
2320 return (WINDOW_COPY_CMD_NOTHING
);
2323 static enum window_copy_cmd_action
2324 window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state
*cs
)
2326 struct window_mode_entry
*wme
= cs
->wme
;
2327 struct window_copy_mode_data
*data
= wme
->data
;
2328 const char *arg1
= args_string(cs
->args
, 1);
2329 const char *ss
= data
->searchstr
;
2331 enum window_copy_cmd_action action
= WINDOW_COPY_CMD_NOTHING
;
2335 log_debug("%s: %s", __func__
, arg1
);
2338 if (data
->searchx
== -1 || data
->searchy
== -1) {
2339 data
->searchx
= data
->cx
;
2340 data
->searchy
= data
->cy
;
2341 data
->searcho
= data
->oy
;
2342 } else if (ss
!= NULL
&& strcmp(arg1
, ss
) != 0) {
2343 data
->cx
= data
->searchx
;
2344 data
->cy
= data
->searchy
;
2345 data
->oy
= data
->searcho
;
2346 action
= WINDOW_COPY_CMD_REDRAW
;
2348 if (*arg1
== '\0') {
2349 window_copy_clear_marks(wme
);
2350 return (WINDOW_COPY_CMD_REDRAW
);
2355 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2356 data
->searchregex
= 0;
2357 free(data
->searchstr
);
2358 data
->searchstr
= xstrdup(arg1
);
2359 if (!window_copy_search_up(wme
, 0)) {
2360 window_copy_clear_marks(wme
);
2361 return (WINDOW_COPY_CMD_REDRAW
);
2365 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2366 data
->searchregex
= 0;
2367 free(data
->searchstr
);
2368 data
->searchstr
= xstrdup(arg1
);
2369 if (!window_copy_search_down(wme
, 0)) {
2370 window_copy_clear_marks(wme
);
2371 return (WINDOW_COPY_CMD_REDRAW
);
2378 static enum window_copy_cmd_action
2379 window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state
*cs
)
2381 struct window_mode_entry
*wme
= cs
->wme
;
2382 struct window_copy_mode_data
*data
= wme
->data
;
2383 const char *arg1
= args_string(cs
->args
, 1);
2384 const char *ss
= data
->searchstr
;
2386 enum window_copy_cmd_action action
= WINDOW_COPY_CMD_NOTHING
;
2390 log_debug("%s: %s", __func__
, arg1
);
2393 if (data
->searchx
== -1 || data
->searchy
== -1) {
2394 data
->searchx
= data
->cx
;
2395 data
->searchy
= data
->cy
;
2396 data
->searcho
= data
->oy
;
2397 } else if (ss
!= NULL
&& strcmp(arg1
, ss
) != 0) {
2398 data
->cx
= data
->searchx
;
2399 data
->cy
= data
->searchy
;
2400 data
->oy
= data
->searcho
;
2401 action
= WINDOW_COPY_CMD_REDRAW
;
2403 if (*arg1
== '\0') {
2404 window_copy_clear_marks(wme
);
2405 return (WINDOW_COPY_CMD_REDRAW
);
2410 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2411 data
->searchregex
= 0;
2412 free(data
->searchstr
);
2413 data
->searchstr
= xstrdup(arg1
);
2414 if (!window_copy_search_down(wme
, 0)) {
2415 window_copy_clear_marks(wme
);
2416 return (WINDOW_COPY_CMD_REDRAW
);
2420 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2421 data
->searchregex
= 0;
2422 free(data
->searchstr
);
2423 data
->searchstr
= xstrdup(arg1
);
2424 if (!window_copy_search_up(wme
, 0)) {
2425 window_copy_clear_marks(wme
);
2426 return (WINDOW_COPY_CMD_REDRAW
);
2432 static enum window_copy_cmd_action
2433 window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state
*cs
)
2435 struct window_mode_entry
*wme
= cs
->wme
;
2436 struct window_pane
*wp
= wme
->swp
;
2437 struct window_copy_mode_data
*data
= wme
->data
;
2440 return (WINDOW_COPY_CMD_NOTHING
);
2442 screen_free(data
->backing
);
2443 free(data
->backing
);
2444 data
->backing
= window_copy_clone_screen(&wp
->base
, &data
->screen
, NULL
, NULL
, wme
->swp
!= wme
->wp
);
2446 window_copy_size_changed(wme
);
2447 return (WINDOW_COPY_CMD_REDRAW
);
2450 static const struct {
2451 const char *command
;
2454 enum window_copy_cmd_clear clear
;
2455 enum window_copy_cmd_action (*f
)(struct window_copy_cmd_state
*);
2456 } window_copy_cmd_table
[] = {
2457 { .command
= "append-selection",
2460 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2461 .f
= window_copy_cmd_append_selection
2463 { .command
= "append-selection-and-cancel",
2466 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2467 .f
= window_copy_cmd_append_selection_and_cancel
2469 { .command
= "back-to-indentation",
2472 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2473 .f
= window_copy_cmd_back_to_indentation
2475 { .command
= "begin-selection",
2478 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2479 .f
= window_copy_cmd_begin_selection
2481 { .command
= "bottom-line",
2484 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2485 .f
= window_copy_cmd_bottom_line
2487 { .command
= "cancel",
2490 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2491 .f
= window_copy_cmd_cancel
2493 { .command
= "clear-selection",
2496 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2497 .f
= window_copy_cmd_clear_selection
2499 { .command
= "copy-end-of-line",
2502 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2503 .f
= window_copy_cmd_copy_end_of_line
2505 { .command
= "copy-end-of-line-and-cancel",
2508 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2509 .f
= window_copy_cmd_copy_end_of_line_and_cancel
2511 { .command
= "copy-pipe-end-of-line",
2514 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2515 .f
= window_copy_cmd_copy_pipe_end_of_line
2517 { .command
= "copy-pipe-end-of-line-and-cancel",
2520 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2521 .f
= window_copy_cmd_copy_pipe_end_of_line_and_cancel
2523 { .command
= "copy-line",
2526 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2527 .f
= window_copy_cmd_copy_line
2529 { .command
= "copy-line-and-cancel",
2532 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2533 .f
= window_copy_cmd_copy_line_and_cancel
2535 { .command
= "copy-pipe-line",
2538 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2539 .f
= window_copy_cmd_copy_pipe_line
2541 { .command
= "copy-pipe-line-and-cancel",
2544 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2545 .f
= window_copy_cmd_copy_pipe_line_and_cancel
2547 { .command
= "copy-pipe-no-clear",
2550 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2551 .f
= window_copy_cmd_copy_pipe_no_clear
2553 { .command
= "copy-pipe",
2556 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2557 .f
= window_copy_cmd_copy_pipe
2559 { .command
= "copy-pipe-and-cancel",
2562 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2563 .f
= window_copy_cmd_copy_pipe_and_cancel
2565 { .command
= "copy-selection-no-clear",
2568 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2569 .f
= window_copy_cmd_copy_selection_no_clear
2571 { .command
= "copy-selection",
2574 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2575 .f
= window_copy_cmd_copy_selection
2577 { .command
= "copy-selection-and-cancel",
2580 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2581 .f
= window_copy_cmd_copy_selection_and_cancel
2583 { .command
= "cursor-down",
2586 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2587 .f
= window_copy_cmd_cursor_down
2589 { .command
= "cursor-down-and-cancel",
2592 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2593 .f
= window_copy_cmd_cursor_down_and_cancel
2595 { .command
= "cursor-left",
2598 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2599 .f
= window_copy_cmd_cursor_left
2601 { .command
= "cursor-right",
2604 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2605 .f
= window_copy_cmd_cursor_right
2607 { .command
= "cursor-up",
2610 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2611 .f
= window_copy_cmd_cursor_up
2613 { .command
= "end-of-line",
2616 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2617 .f
= window_copy_cmd_end_of_line
2619 { .command
= "goto-line",
2622 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2623 .f
= window_copy_cmd_goto_line
2625 { .command
= "halfpage-down",
2628 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2629 .f
= window_copy_cmd_halfpage_down
2631 { .command
= "halfpage-down-and-cancel",
2634 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2635 .f
= window_copy_cmd_halfpage_down_and_cancel
2637 { .command
= "halfpage-up",
2640 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2641 .f
= window_copy_cmd_halfpage_up
2643 { .command
= "history-bottom",
2646 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2647 .f
= window_copy_cmd_history_bottom
2649 { .command
= "history-top",
2652 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2653 .f
= window_copy_cmd_history_top
2655 { .command
= "jump-again",
2658 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2659 .f
= window_copy_cmd_jump_again
2661 { .command
= "jump-backward",
2664 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2665 .f
= window_copy_cmd_jump_backward
2667 { .command
= "jump-forward",
2670 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2671 .f
= window_copy_cmd_jump_forward
2673 { .command
= "jump-reverse",
2676 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2677 .f
= window_copy_cmd_jump_reverse
2679 { .command
= "jump-to-backward",
2682 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2683 .f
= window_copy_cmd_jump_to_backward
2685 { .command
= "jump-to-forward",
2688 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2689 .f
= window_copy_cmd_jump_to_forward
2691 { .command
= "jump-to-mark",
2694 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2695 .f
= window_copy_cmd_jump_to_mark
2697 { .command
= "middle-line",
2700 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2701 .f
= window_copy_cmd_middle_line
2703 { .command
= "next-matching-bracket",
2706 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2707 .f
= window_copy_cmd_next_matching_bracket
2709 { .command
= "next-paragraph",
2712 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2713 .f
= window_copy_cmd_next_paragraph
2715 { .command
= "next-space",
2718 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2719 .f
= window_copy_cmd_next_space
2721 { .command
= "next-space-end",
2724 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2725 .f
= window_copy_cmd_next_space_end
2727 { .command
= "next-word",
2730 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2731 .f
= window_copy_cmd_next_word
2733 { .command
= "next-word-end",
2736 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2737 .f
= window_copy_cmd_next_word_end
2739 { .command
= "other-end",
2742 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2743 .f
= window_copy_cmd_other_end
2745 { .command
= "page-down",
2748 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2749 .f
= window_copy_cmd_page_down
2751 { .command
= "page-down-and-cancel",
2754 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2755 .f
= window_copy_cmd_page_down_and_cancel
2757 { .command
= "page-up",
2760 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2761 .f
= window_copy_cmd_page_up
2763 { .command
= "pipe-no-clear",
2766 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2767 .f
= window_copy_cmd_pipe_no_clear
2769 { .command
= "pipe",
2772 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2773 .f
= window_copy_cmd_pipe
2775 { .command
= "pipe-and-cancel",
2778 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2779 .f
= window_copy_cmd_pipe_and_cancel
2781 { .command
= "previous-matching-bracket",
2784 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2785 .f
= window_copy_cmd_previous_matching_bracket
2787 { .command
= "previous-paragraph",
2790 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2791 .f
= window_copy_cmd_previous_paragraph
2793 { .command
= "previous-space",
2796 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2797 .f
= window_copy_cmd_previous_space
2799 { .command
= "previous-word",
2802 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2803 .f
= window_copy_cmd_previous_word
2805 { .command
= "rectangle-on",
2808 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2809 .f
= window_copy_cmd_rectangle_on
2811 { .command
= "rectangle-off",
2814 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2815 .f
= window_copy_cmd_rectangle_off
2817 { .command
= "rectangle-toggle",
2820 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2821 .f
= window_copy_cmd_rectangle_toggle
2823 { .command
= "refresh-from-pane",
2826 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2827 .f
= window_copy_cmd_refresh_from_pane
2829 { .command
= "scroll-bottom",
2832 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2833 .f
= window_copy_cmd_scroll_bottom
2835 { .command
= "scroll-down",
2838 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2839 .f
= window_copy_cmd_scroll_down
2841 { .command
= "scroll-down-and-cancel",
2844 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2845 .f
= window_copy_cmd_scroll_down_and_cancel
2847 { .command
= "scroll-middle",
2850 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2851 .f
= window_copy_cmd_scroll_middle
2853 { .command
= "scroll-top",
2856 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2857 .f
= window_copy_cmd_scroll_top
2859 { .command
= "scroll-up",
2862 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2863 .f
= window_copy_cmd_scroll_up
2865 { .command
= "search-again",
2868 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2869 .f
= window_copy_cmd_search_again
2871 { .command
= "search-backward",
2874 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2875 .f
= window_copy_cmd_search_backward
2877 { .command
= "search-backward-text",
2880 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2881 .f
= window_copy_cmd_search_backward_text
2883 { .command
= "search-backward-incremental",
2886 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2887 .f
= window_copy_cmd_search_backward_incremental
2889 { .command
= "search-forward",
2892 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2893 .f
= window_copy_cmd_search_forward
2895 { .command
= "search-forward-text",
2898 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2899 .f
= window_copy_cmd_search_forward_text
2901 { .command
= "search-forward-incremental",
2904 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2905 .f
= window_copy_cmd_search_forward_incremental
2907 { .command
= "search-reverse",
2910 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2911 .f
= window_copy_cmd_search_reverse
2913 { .command
= "select-line",
2916 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2917 .f
= window_copy_cmd_select_line
2919 { .command
= "select-word",
2922 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2923 .f
= window_copy_cmd_select_word
2925 { .command
= "set-mark",
2928 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2929 .f
= window_copy_cmd_set_mark
2931 { .command
= "start-of-line",
2934 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2935 .f
= window_copy_cmd_start_of_line
2937 { .command
= "stop-selection",
2940 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2941 .f
= window_copy_cmd_stop_selection
2943 { .command
= "toggle-position",
2946 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2947 .f
= window_copy_cmd_toggle_position
2949 { .command
= "top-line",
2952 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2953 .f
= window_copy_cmd_top_line
2958 window_copy_command(struct window_mode_entry
*wme
, struct client
*c
,
2959 struct session
*s
, struct winlink
*wl
, struct args
*args
,
2960 struct mouse_event
*m
)
2962 struct window_copy_mode_data
*data
= wme
->data
;
2963 struct window_copy_cmd_state cs
;
2964 enum window_copy_cmd_action action
;
2965 enum window_copy_cmd_clear clear
= WINDOW_COPY_CMD_CLEAR_NEVER
;
2966 const char *command
;
2967 u_int i
, count
= args_count(args
);
2972 command
= args_string(args
, 0);
2974 if (m
!= NULL
&& m
->valid
&& !MOUSE_WHEEL(m
->b
))
2975 window_copy_move_mouse(m
);
2985 action
= WINDOW_COPY_CMD_NOTHING
;
2986 for (i
= 0; i
< nitems(window_copy_cmd_table
); i
++) {
2987 if (strcmp(window_copy_cmd_table
[i
].command
, command
) == 0) {
2988 if (count
- 1 < window_copy_cmd_table
[i
].minargs
||
2989 count
- 1 > window_copy_cmd_table
[i
].maxargs
)
2991 clear
= window_copy_cmd_table
[i
].clear
;
2992 action
= window_copy_cmd_table
[i
].f(&cs
);
2997 if (strncmp(command
, "search-", 7) != 0 && data
->searchmark
!= NULL
) {
2998 keys
= options_get_number(wme
->wp
->window
->options
, "mode-keys");
2999 if (clear
== WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
&&
3001 clear
= WINDOW_COPY_CMD_CLEAR_NEVER
;
3002 if (clear
!= WINDOW_COPY_CMD_CLEAR_NEVER
) {
3003 window_copy_clear_marks(wme
);
3004 data
->searchx
= data
->searchy
= -1;
3006 if (action
== WINDOW_COPY_CMD_NOTHING
)
3007 action
= WINDOW_COPY_CMD_REDRAW
;
3011 if (action
== WINDOW_COPY_CMD_CANCEL
)
3012 window_pane_reset_mode(wme
->wp
);
3013 else if (action
== WINDOW_COPY_CMD_REDRAW
)
3014 window_copy_redraw_screen(wme
);
3018 window_copy_scroll_to(struct window_mode_entry
*wme
, u_int px
, u_int py
,
3021 struct window_copy_mode_data
*data
= wme
->data
;
3022 struct grid
*gd
= data
->backing
->grid
;
3027 if (py
>= gd
->hsize
- data
->oy
&& py
< gd
->hsize
- data
->oy
+ gd
->sy
)
3028 data
->cy
= py
- (gd
->hsize
- data
->oy
);
3034 } else if (py
> gd
->hsize
+ gd
->sy
- gap
) {
3036 data
->cy
= py
- gd
->hsize
;
3038 offset
= py
+ gap
- gd
->sy
;
3039 data
->cy
= py
- offset
;
3041 data
->oy
= gd
->hsize
- offset
;
3044 if (!no_redraw
&& data
->searchmark
!= NULL
&& !data
->timeout
)
3045 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
3046 window_copy_update_selection(wme
, 1, 0);
3048 window_copy_redraw_screen(wme
);
3052 window_copy_search_compare(struct grid
*gd
, u_int px
, u_int py
,
3053 struct grid
*sgd
, u_int spx
, int cis
)
3055 struct grid_cell gc
, sgc
;
3056 const struct utf8_data
*ud
, *sud
;
3058 grid_get_cell(gd
, px
, py
, &gc
);
3060 grid_get_cell(sgd
, spx
, 0, &sgc
);
3063 if (ud
->size
!= sud
->size
|| ud
->width
!= sud
->width
)
3066 if (cis
&& ud
->size
== 1)
3067 return (tolower(ud
->data
[0]) == sud
->data
[0]);
3069 return (memcmp(ud
->data
, sud
->data
, ud
->size
) == 0);
3073 window_copy_search_lr(struct grid
*gd
, struct grid
*sgd
, u_int
*ppx
, u_int py
,
3074 u_int first
, u_int last
, int cis
)
3076 u_int ax
, bx
, px
, pywrap
, endline
;
3078 struct grid_line
*gl
;
3080 endline
= gd
->hsize
+ gd
->sy
- 1;
3081 for (ax
= first
; ax
< last
; ax
++) {
3082 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
3086 while (px
>= gd
->sx
&& pywrap
< endline
) {
3087 gl
= grid_get_line(gd
, pywrap
);
3088 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3093 /* We have run off the end of the grid. */
3096 matched
= window_copy_search_compare(gd
, px
, pywrap
,
3101 if (bx
== sgd
->sx
) {
3110 window_copy_search_rl(struct grid
*gd
,
3111 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
, int cis
)
3113 u_int ax
, bx
, px
, pywrap
, endline
;
3115 struct grid_line
*gl
;
3117 endline
= gd
->hsize
+ gd
->sy
- 1;
3118 for (ax
= last
; ax
> first
; ax
--) {
3119 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
3123 while (px
>= gd
->sx
&& pywrap
< endline
) {
3124 gl
= grid_get_line(gd
, pywrap
);
3125 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3130 /* We have run off the end of the grid. */
3133 matched
= window_copy_search_compare(gd
, px
, pywrap
,
3138 if (bx
== sgd
->sx
) {
3147 window_copy_search_lr_regex(struct grid
*gd
, u_int
*ppx
, u_int
*psx
, u_int py
,
3148 u_int first
, u_int last
, regex_t
*reg
)
3151 u_int endline
, foundx
, foundy
, len
, pywrap
, size
= 1;
3153 regmatch_t regmatch
;
3154 struct grid_line
*gl
;
3157 * This can happen during search if the last match was the last
3158 * character on a line.
3163 /* Set flags for regex search. */
3165 eflags
|= REG_NOTBOL
;
3167 /* Need to look at the entire string. */
3168 buf
= xmalloc(size
);
3170 buf
= window_copy_stringify(gd
, py
, first
, gd
->sx
, buf
, &size
);
3171 len
= gd
->sx
- first
;
3172 endline
= gd
->hsize
+ gd
->sy
- 1;
3174 while (buf
!= NULL
&& pywrap
<= endline
) {
3175 gl
= grid_get_line(gd
, pywrap
);
3176 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3179 buf
= window_copy_stringify(gd
, pywrap
, 0, gd
->sx
, buf
, &size
);
3183 if (regexec(reg
, buf
, 1, ®match
, eflags
) == 0 &&
3184 regmatch
.rm_so
!= regmatch
.rm_eo
) {
3187 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3188 buf
+ regmatch
.rm_so
);
3189 if (foundy
== py
&& foundx
< last
) {
3191 len
-= foundx
- first
;
3192 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3193 buf
+ regmatch
.rm_eo
);
3195 while (foundy
> py
) {
3212 window_copy_search_rl_regex(struct grid
*gd
, u_int
*ppx
, u_int
*psx
, u_int py
,
3213 u_int first
, u_int last
, regex_t
*reg
)
3216 u_int endline
, len
, pywrap
, size
= 1;
3218 struct grid_line
*gl
;
3220 /* Set flags for regex search. */
3222 eflags
|= REG_NOTBOL
;
3224 /* Need to look at the entire string. */
3225 buf
= xmalloc(size
);
3227 buf
= window_copy_stringify(gd
, py
, first
, gd
->sx
, buf
, &size
);
3228 len
= gd
->sx
- first
;
3229 endline
= gd
->hsize
+ gd
->sy
- 1;
3231 while (buf
!= NULL
&& (pywrap
<= endline
)) {
3232 gl
= grid_get_line(gd
, pywrap
);
3233 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3236 buf
= window_copy_stringify(gd
, pywrap
, 0, gd
->sx
, buf
, &size
);
3240 if (window_copy_last_regex(gd
, py
, first
, last
, len
, ppx
, psx
, buf
,
3254 window_copy_cellstring(const struct grid_line
*gl
, u_int px
, size_t *size
,
3257 static struct utf8_data ud
;
3258 struct grid_cell_entry
*gce
;
3261 if (px
>= gl
->cellsize
) {
3267 gce
= &gl
->celldata
[px
];
3268 if (gce
->flags
& GRID_FLAG_PADDING
) {
3273 if (~gce
->flags
& GRID_FLAG_EXTENDED
) {
3276 return (&gce
->data
.data
);
3279 utf8_to_data(gl
->extddata
[gce
->offset
].data
, &ud
);
3288 copy
= xmalloc(ud
.size
);
3289 memcpy(copy
, ud
.data
, ud
.size
);
3293 /* Find last match in given range. */
3295 window_copy_last_regex(struct grid
*gd
, u_int py
, u_int first
, u_int last
,
3296 u_int len
, u_int
*ppx
, u_int
*psx
, const char *buf
, const regex_t
*preg
,
3299 u_int foundx
, foundy
, oldx
, px
= 0, savepx
, savesx
= 0;
3300 regmatch_t regmatch
;
3305 while (regexec(preg
, buf
+ px
, 1, ®match
, eflags
) == 0) {
3306 if (regmatch
.rm_so
== regmatch
.rm_eo
)
3308 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3309 buf
+ px
+ regmatch
.rm_so
);
3310 if (foundy
> py
|| foundx
>= last
)
3312 len
-= foundx
- oldx
;
3314 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3315 buf
+ px
+ regmatch
.rm_eo
);
3316 if (foundy
> py
|| foundx
>= last
) {
3319 while (foundy
> py
) {
3326 savesx
= foundx
- savepx
;
3330 px
+= regmatch
.rm_eo
;
3344 /* Stringify line and append to input buffer. Caller frees. */
3346 window_copy_stringify(struct grid
*gd
, u_int py
, u_int first
, u_int last
,
3347 char *buf
, u_int
*size
)
3349 u_int ax
, bx
, newsize
= *size
;
3350 const struct grid_line
*gl
;
3352 size_t bufsize
= 1024, dlen
;
3355 while (bufsize
< newsize
)
3357 buf
= xrealloc(buf
, bufsize
);
3359 gl
= grid_peek_line(gd
, py
);
3361 for (ax
= first
; ax
< last
; ax
++) {
3362 d
= window_copy_cellstring(gl
, ax
, &dlen
, &allocated
);
3364 while (bufsize
< newsize
) {
3366 buf
= xrealloc(buf
, bufsize
);
3371 memcpy(buf
+ bx
, d
, dlen
);
3377 buf
[newsize
- 1] = '\0';
3383 /* Map start of C string containing UTF-8 data to grid cell position. */
3385 window_copy_cstrtocellpos(struct grid
*gd
, u_int ncells
, u_int
*ppx
, u_int
*ppy
,
3388 u_int cell
, ccell
, px
, pywrap
, pos
, len
;
3390 const struct grid_line
*gl
;
3399 /* Populate the array of cell data. */
3400 cells
= xreallocarray(NULL
, ncells
, sizeof cells
[0]);
3404 gl
= grid_peek_line(gd
, pywrap
);
3405 while (cell
< ncells
) {
3406 cells
[cell
].d
= window_copy_cellstring(gl
, px
,
3407 &cells
[cell
].dlen
, &cells
[cell
].allocated
);
3413 gl
= grid_peek_line(gd
, pywrap
);
3417 /* Locate starting cell. */
3420 while (cell
< ncells
) {
3424 while (ccell
< ncells
) {
3425 if (str
[pos
] == '\0') {
3430 dlen
= cells
[ccell
].dlen
;
3432 if (str
[pos
] != *d
) {
3438 if (dlen
> len
- pos
)
3440 if (memcmp(str
+ pos
, d
, dlen
) != 0) {
3453 /* If not found this will be one past the end. */
3456 while (px
>= gd
->sx
) {
3464 /* Free cell data. */
3465 for (cell
= 0; cell
< ncells
; cell
++) {
3466 if (cells
[cell
].allocated
)
3467 free((void *)cells
[cell
].d
);
3473 window_copy_move_left(struct screen
*s
, u_int
*fx
, u_int
*fy
, int wrapflag
)
3475 if (*fx
== 0) { /* left */
3476 if (*fy
== 0) { /* top */
3478 *fx
= screen_size_x(s
) - 1;
3479 *fy
= screen_hsize(s
) + screen_size_y(s
) - 1;
3483 *fx
= screen_size_x(s
) - 1;
3490 window_copy_move_right(struct screen
*s
, u_int
*fx
, u_int
*fy
, int wrapflag
)
3492 if (*fx
== screen_size_x(s
) - 1) { /* right */
3493 if (*fy
== screen_hsize(s
) + screen_size_y(s
) - 1) { /* bottom */
3507 window_copy_is_lowercase(const char *ptr
)
3509 while (*ptr
!= '\0') {
3510 if (*ptr
!= tolower((u_char
)*ptr
))
3518 * Handle backward wrapped regex searches with overlapping matches. In this case
3519 * find the longest overlapping match from previous wrapped lines.
3522 window_copy_search_back_overlap(struct grid
*gd
, regex_t
*preg
, u_int
*ppx
,
3523 u_int
*psx
, u_int
*ppy
, u_int endline
)
3525 u_int endx
, endy
, oldendx
, oldendy
, px
, py
, sx
;
3528 oldendx
= *ppx
+ *psx
;
3530 while (oldendx
> gd
->sx
- 1) {
3538 while (found
&& px
== 0 && py
- 1 > endline
&&
3539 grid_get_line(gd
, py
- 2)->flags
& GRID_LINE_WRAPPED
&&
3540 endx
== oldendx
&& endy
== oldendy
) {
3542 found
= window_copy_search_rl_regex(gd
, &px
, &sx
, py
- 1, 0,
3547 while (endx
> gd
->sx
- 1) {
3551 if (endx
== oldendx
&& endy
== oldendy
) {
3560 * Search for text stored in sgd starting from position fx,fy up to endline. If
3561 * found, jump to it. If cis then ignore case. The direction is 0 for searching
3562 * up, down otherwise. If wrap then go to begin/end of grid and try again if
3566 window_copy_search_jump(struct window_mode_entry
*wme
, struct grid
*gd
,
3567 struct grid
*sgd
, u_int fx
, u_int fy
, u_int endline
, int cis
, int wrap
,
3568 int direction
, int regex
)
3570 u_int i
, px
, sx
, ssize
= 1;
3571 int found
= 0, cflags
= REG_EXTENDED
;
3576 sbuf
= xmalloc(ssize
);
3578 sbuf
= window_copy_stringify(sgd
, 0, 0, sgd
->sx
, sbuf
, &ssize
);
3580 cflags
|= REG_ICASE
;
3581 if (regcomp(®
, sbuf
, cflags
) != 0) {
3589 for (i
= fy
; i
<= endline
; i
++) {
3591 found
= window_copy_search_lr_regex(gd
,
3592 &px
, &sx
, i
, fx
, gd
->sx
, ®
);
3594 found
= window_copy_search_lr(gd
, sgd
,
3595 &px
, i
, fx
, gd
->sx
, cis
);
3602 for (i
= fy
+ 1; endline
< i
; i
--) {
3604 found
= window_copy_search_rl_regex(gd
,
3605 &px
, &sx
, i
- 1, 0, fx
+ 1, ®
);
3607 window_copy_search_back_overlap(gd
,
3608 ®
, &px
, &sx
, &i
, endline
);
3611 found
= window_copy_search_rl(gd
, sgd
,
3612 &px
, i
- 1, 0, fx
+ 1, cis
);
3625 window_copy_scroll_to(wme
, px
, i
, 1);
3629 return (window_copy_search_jump(wme
, gd
, sgd
,
3630 direction
? 0 : gd
->sx
- 1,
3631 direction
? 0 : gd
->hsize
+ gd
->sy
- 1, fy
, cis
, 0,
3638 window_copy_move_after_search_mark(struct window_copy_mode_data
*data
,
3639 u_int
*fx
, u_int
*fy
, int wrapflag
)
3641 struct screen
*s
= data
->backing
;
3644 if (window_copy_search_mark_at(data
, *fx
, *fy
, &start
) == 0 &&
3645 data
->searchmark
[start
] != 0) {
3646 while (window_copy_search_mark_at(data
, *fx
, *fy
, &at
) == 0) {
3647 if (data
->searchmark
[at
] != data
->searchmark
[start
])
3649 /* Stop if not wrapping and at the end of the grid. */
3651 *fx
== screen_size_x(s
) - 1 &&
3652 *fy
== screen_hsize(s
) + screen_size_y(s
) - 1)
3655 window_copy_move_right(s
, fx
, fy
, wrapflag
);
3661 * Search in for text searchstr. If direction is 0 then search up, otherwise
3665 window_copy_search(struct window_mode_entry
*wme
, int direction
, int regex
)
3667 struct window_pane
*wp
= wme
->wp
;
3668 struct window_copy_mode_data
*data
= wme
->data
;
3669 struct screen
*s
= data
->backing
, ss
;
3670 struct screen_write_ctx ctx
;
3671 struct grid
*gd
= s
->grid
;
3672 const char *str
= data
->searchstr
;
3673 u_int at
, endline
, fx
, fy
, start
;
3674 int cis
, found
, keys
, visible_only
;
3677 if (regex
&& str
[strcspn(str
, "^$*+()?[].\\")] == '\0')
3680 data
->searchdirection
= direction
;
3685 if (data
->searchall
|| wp
->searchstr
== NULL
||
3686 wp
->searchregex
!= regex
) {
3688 data
->searchall
= 0;
3690 visible_only
= (strcmp(wp
->searchstr
, str
) == 0);
3691 if (visible_only
== 0 && data
->searchmark
!= NULL
)
3692 window_copy_clear_marks(wme
);
3693 free(wp
->searchstr
);
3694 wp
->searchstr
= xstrdup(str
);
3695 wp
->searchregex
= regex
;
3698 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3700 screen_init(&ss
, screen_write_strlen("%s", str
), 1, 0);
3701 screen_write_start(&ctx
, &ss
);
3702 screen_write_nputs(&ctx
, -1, &grid_default_cell
, "%s", str
);
3703 screen_write_stop(&ctx
);
3705 wrapflag
= options_get_number(wp
->window
->options
, "wrap-search");
3706 cis
= window_copy_is_lowercase(str
);
3708 keys
= options_get_number(wp
->window
->options
, "mode-keys");
3712 * Behave according to mode-keys. If it is emacs, search forward
3713 * leaves the cursor after the match. If it is vi, the cursor
3714 * remains at the beginning of the match, regardless of
3715 * direction, which means that we need to start the next search
3716 * after the term the cursor is currently on when searching
3719 if (keys
== MODEKEY_VI
) {
3720 if (data
->searchmark
!= NULL
)
3721 window_copy_move_after_search_mark(data
, &fx
,
3725 * When there are no search marks, start the
3726 * search after the current cursor position.
3728 window_copy_move_right(s
, &fx
, &fy
, wrapflag
);
3731 endline
= gd
->hsize
+ gd
->sy
- 1;
3734 window_copy_move_left(s
, &fx
, &fy
, wrapflag
);
3738 found
= window_copy_search_jump(wme
, gd
, ss
.grid
, fx
, fy
, endline
, cis
,
3739 wrapflag
, direction
, regex
);
3741 window_copy_search_marks(wme
, &ss
, regex
, visible_only
);
3743 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3746 * When searching forward, if the cursor is not at the beginning
3747 * of the mark, search again.
3750 window_copy_search_mark_at(data
, fx
, fy
, &at
) == 0 &&
3752 data
->searchmark
!= NULL
&&
3753 data
->searchmark
[at
] == data
->searchmark
[at
- 1]) {
3754 window_copy_move_after_search_mark(data
, &fx
, &fy
,
3756 window_copy_search_jump(wme
, gd
, ss
.grid
, fx
,
3757 fy
, endline
, cis
, wrapflag
, direction
,
3760 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3765 * When in Emacs mode, position the cursor just after
3768 if (keys
== MODEKEY_EMACS
) {
3769 window_copy_move_after_search_mark(data
, &fx
,
3772 data
->cy
= fy
- screen_hsize(data
->backing
) +
3778 * When searching backward, position the cursor at the
3779 * beginning of the mark.
3781 if (window_copy_search_mark_at(data
, fx
, fy
,
3783 while (window_copy_search_mark_at(data
, fx
, fy
,
3785 data
->searchmark
!= NULL
&&
3786 data
->searchmark
[at
] ==
3787 data
->searchmark
[start
]) {
3790 screen_hsize(data
->backing
) +
3795 window_copy_move_left(s
, &fx
, &fy
, 0);
3800 window_copy_redraw_screen(wme
);
3807 window_copy_visible_lines(struct window_copy_mode_data
*data
, u_int
*start
,
3810 struct grid
*gd
= data
->backing
->grid
;
3811 const struct grid_line
*gl
;
3813 for (*start
= gd
->hsize
- data
->oy
; *start
> 0; (*start
)--) {
3814 gl
= grid_peek_line(gd
, (*start
) - 1);
3815 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3818 *end
= gd
->hsize
- data
->oy
+ gd
->sy
;
3822 window_copy_search_mark_at(struct window_copy_mode_data
*data
, u_int px
,
3823 u_int py
, u_int
*at
)
3825 struct screen
*s
= data
->backing
;
3826 struct grid
*gd
= s
->grid
;
3828 if (py
< gd
->hsize
- data
->oy
)
3830 if (py
> gd
->hsize
- data
->oy
+ gd
->sy
- 1)
3832 *at
= ((py
- (gd
->hsize
- data
->oy
)) * gd
->sx
) + px
;
3837 window_copy_search_marks(struct window_mode_entry
*wme
, struct screen
*ssp
,
3838 int regex
, int visible_only
)
3840 struct window_copy_mode_data
*data
= wme
->data
;
3841 struct screen
*s
= data
->backing
, ss
;
3842 struct screen_write_ctx ctx
;
3843 struct grid
*gd
= s
->grid
;
3844 int found
, cis
, stopped
= 0;
3845 int cflags
= REG_EXTENDED
;
3846 u_int px
, py
, i
, b
, nfound
= 0, width
;
3847 u_int ssize
= 1, start
, end
;
3850 uint64_t stop
= 0, tstart
, t
;
3853 width
= screen_write_strlen("%s", data
->searchstr
);
3854 screen_init(&ss
, width
, 1, 0);
3855 screen_write_start(&ctx
, &ss
);
3856 screen_write_nputs(&ctx
, -1, &grid_default_cell
, "%s",
3858 screen_write_stop(&ctx
);
3861 width
= screen_size_x(ssp
);
3863 cis
= window_copy_is_lowercase(data
->searchstr
);
3866 sbuf
= xmalloc(ssize
);
3868 sbuf
= window_copy_stringify(ssp
->grid
, 0, 0, ssp
->grid
->sx
,
3871 cflags
|= REG_ICASE
;
3872 if (regcomp(®
, sbuf
, cflags
) != 0) {
3878 tstart
= get_timer();
3881 window_copy_visible_lines(data
, &start
, &end
);
3884 end
= gd
->hsize
+ gd
->sy
;
3885 stop
= get_timer() + WINDOW_COPY_SEARCH_ALL_TIMEOUT
;
3889 free(data
->searchmark
);
3890 data
->searchmark
= xcalloc(gd
->sx
, gd
->sy
);
3891 data
->searchgen
= 1;
3893 for (py
= start
; py
< end
; py
++) {
3897 found
= window_copy_search_lr_regex(gd
,
3898 &px
, &width
, py
, px
, gd
->sx
, ®
);
3902 found
= window_copy_search_lr(gd
, ssp
->grid
,
3903 &px
, py
, px
, gd
->sx
, cis
);
3909 if (window_copy_search_mark_at(data
, px
, py
, &b
) == 0) {
3910 if (b
+ width
> gd
->sx
* gd
->sy
)
3911 width
= (gd
->sx
* gd
->sy
) - b
;
3912 for (i
= b
; i
< b
+ width
; i
++) {
3913 if (data
->searchmark
[i
] != 0)
3915 data
->searchmark
[i
] = data
->searchgen
;
3917 if (data
->searchgen
== UCHAR_MAX
)
3918 data
->searchgen
= 1;
3926 if (t
- tstart
> WINDOW_COPY_SEARCH_TIMEOUT
) {
3930 if (stop
!= 0 && t
> stop
) {
3935 if (data
->timeout
) {
3936 window_copy_clear_marks(wme
);
3940 if (stopped
&& stop
!= 0) {
3941 /* Try again but just the visible context. */
3942 window_copy_visible_lines(data
, &start
, &end
);
3947 if (!visible_only
) {
3950 data
->searchcount
= 1000;
3951 else if (nfound
> 100)
3952 data
->searchcount
= 100;
3953 else if (nfound
> 10)
3954 data
->searchcount
= 10;
3956 data
->searchcount
= -1;
3957 data
->searchmore
= 1;
3959 data
->searchcount
= nfound
;
3960 data
->searchmore
= 0;
3973 window_copy_clear_marks(struct window_mode_entry
*wme
)
3975 struct window_copy_mode_data
*data
= wme
->data
;
3977 free(data
->searchmark
);
3978 data
->searchmark
= NULL
;
3982 window_copy_search_up(struct window_mode_entry
*wme
, int regex
)
3984 return (window_copy_search(wme
, 0, regex
));
3988 window_copy_search_down(struct window_mode_entry
*wme
, int regex
)
3990 return (window_copy_search(wme
, 1, regex
));
3994 window_copy_goto_line(struct window_mode_entry
*wme
, const char *linestr
)
3996 struct window_copy_mode_data
*data
= wme
->data
;
4000 lineno
= strtonum(linestr
, -1, INT_MAX
, &errstr
);
4003 if (lineno
< 0 || (u_int
)lineno
> screen_hsize(data
->backing
))
4004 lineno
= screen_hsize(data
->backing
);
4007 window_copy_update_selection(wme
, 1, 0);
4008 window_copy_redraw_screen(wme
);
4012 window_copy_match_start_end(struct window_copy_mode_data
*data
, u_int at
,
4013 u_int
*start
, u_int
*end
)
4015 struct grid
*gd
= data
->backing
->grid
;
4016 u_int last
= (gd
->sy
* gd
->sx
) - 1;
4017 u_char mark
= data
->searchmark
[at
];
4020 while (*start
!= 0 && data
->searchmark
[*start
] == mark
)
4022 if (data
->searchmark
[*start
] != mark
)
4024 while (*end
!= last
&& data
->searchmark
[*end
] == mark
)
4026 if (data
->searchmark
[*end
] != mark
)
4031 window_copy_match_at_cursor(struct window_copy_mode_data
*data
)
4033 struct grid
*gd
= data
->backing
->grid
;
4034 struct grid_cell gc
;
4035 u_int at
, start
, end
, cy
, px
, py
;
4036 u_int sx
= screen_size_x(data
->backing
);
4040 if (data
->searchmark
== NULL
)
4043 cy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
4044 if (window_copy_search_mark_at(data
, data
->cx
, cy
, &at
) != 0)
4046 if (data
->searchmark
[at
] == 0) {
4047 /* Allow one position after the match. */
4048 if (at
== 0 || data
->searchmark
[--at
] == 0)
4051 window_copy_match_start_end(data
, at
, &start
, &end
);
4054 * Cells will not be set in the marked array unless they are valid text
4055 * and wrapping will be taken care of, so we can just copy.
4057 for (at
= start
; at
<= end
; at
++) {
4059 px
= at
- (py
* sx
);
4061 grid_get_cell(gd
, px
, gd
->hsize
+ py
- data
->oy
, &gc
);
4062 buf
= xrealloc(buf
, len
+ gc
.data
.size
+ 1);
4063 memcpy(buf
+ len
, gc
.data
.data
, gc
.data
.size
);
4064 len
+= gc
.data
.size
;
4072 window_copy_update_style(struct window_mode_entry
*wme
, u_int fx
, u_int fy
,
4073 struct grid_cell
*gc
, const struct grid_cell
*mgc
,
4074 const struct grid_cell
*cgc
, const struct grid_cell
*mkgc
)
4076 struct window_pane
*wp
= wme
->wp
;
4077 struct window_copy_mode_data
*data
= wme
->data
;
4078 u_int mark
, start
, end
, cy
, cursor
, current
;
4079 int inv
= 0, found
= 0;
4082 if (data
->showmark
&& fy
== data
->my
) {
4083 gc
->attr
= mkgc
->attr
;
4096 if (data
->searchmark
== NULL
)
4099 if (window_copy_search_mark_at(data
, fx
, fy
, ¤t
) != 0)
4101 mark
= data
->searchmark
[current
];
4105 cy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
4106 if (window_copy_search_mark_at(data
, data
->cx
, cy
, &cursor
) == 0) {
4107 keys
= options_get_number(wp
->window
->options
, "mode-keys");
4109 keys
== MODEKEY_EMACS
&&
4110 data
->searchdirection
) {
4111 if (data
->searchmark
[cursor
- 1] == mark
) {
4115 } else if (data
->searchmark
[cursor
] == mark
)
4118 window_copy_match_start_end(data
, cursor
, &start
, &end
);
4119 if (current
>= start
&& current
<= end
) {
4120 gc
->attr
= cgc
->attr
;
4134 gc
->attr
= mgc
->attr
;
4146 window_copy_write_one(struct window_mode_entry
*wme
,
4147 struct screen_write_ctx
*ctx
, u_int py
, u_int fy
, u_int nx
,
4148 const struct grid_cell
*mgc
, const struct grid_cell
*cgc
,
4149 const struct grid_cell
*mkgc
)
4151 struct window_copy_mode_data
*data
= wme
->data
;
4152 struct grid
*gd
= data
->backing
->grid
;
4153 struct grid_cell gc
;
4156 screen_write_cursormove(ctx
, 0, py
, 0);
4157 for (fx
= 0; fx
< nx
; fx
++) {
4158 grid_get_cell(gd
, fx
, fy
, &gc
);
4159 if (fx
+ gc
.data
.width
<= nx
) {
4160 window_copy_update_style(wme
, fx
, fy
, &gc
, mgc
, cgc
,
4162 screen_write_cell(ctx
, &gc
);
4168 window_copy_write_line(struct window_mode_entry
*wme
,
4169 struct screen_write_ctx
*ctx
, u_int py
)
4171 struct window_pane
*wp
= wme
->wp
;
4172 struct window_copy_mode_data
*data
= wme
->data
;
4173 struct screen
*s
= &data
->screen
;
4174 struct options
*oo
= wp
->window
->options
;
4175 struct grid_line
*gl
;
4176 struct grid_cell gc
, mgc
, cgc
, mkgc
;
4177 char hdr
[512], tmp
[256], *t
;
4179 u_int hsize
= screen_hsize(data
->backing
);
4181 style_apply(&gc
, oo
, "mode-style", NULL
);
4182 gc
.flags
|= GRID_FLAG_NOPALETTE
;
4183 style_apply(&mgc
, oo
, "copy-mode-match-style", NULL
);
4184 mgc
.flags
|= GRID_FLAG_NOPALETTE
;
4185 style_apply(&cgc
, oo
, "copy-mode-current-match-style", NULL
);
4186 cgc
.flags
|= GRID_FLAG_NOPALETTE
;
4187 style_apply(&mkgc
, oo
, "copy-mode-mark-style", NULL
);
4188 mkgc
.flags
|= GRID_FLAG_NOPALETTE
;
4190 if (py
== 0 && s
->rupper
< s
->rlower
&& !data
->hide_position
) {
4191 gl
= grid_get_line(data
->backing
->grid
, hsize
- data
->oy
);
4193 xsnprintf(tmp
, sizeof tmp
, "[%u/%u]", data
->oy
, hsize
);
4195 t
= format_pretty_time(gl
->time
, 1);
4196 xsnprintf(tmp
, sizeof tmp
, "%s [%u/%u]", t
, data
->oy
,
4201 if (data
->searchmark
== NULL
) {
4202 if (data
->timeout
) {
4203 size
= xsnprintf(hdr
, sizeof hdr
,
4204 "(timed out) %s", tmp
);
4206 size
= xsnprintf(hdr
, sizeof hdr
, "%s", tmp
);
4208 if (data
->searchcount
== -1)
4209 size
= xsnprintf(hdr
, sizeof hdr
, "%s", tmp
);
4211 size
= xsnprintf(hdr
, sizeof hdr
,
4212 "(%d%s results) %s", data
->searchcount
,
4213 data
->searchmore
? "+" : "", tmp
);
4216 if (size
> screen_size_x(s
))
4217 size
= screen_size_x(s
);
4218 screen_write_cursormove(ctx
, screen_size_x(s
) - size
, 0, 0);
4219 screen_write_puts(ctx
, &gc
, "%s", hdr
);
4223 if (size
< screen_size_x(s
)) {
4224 window_copy_write_one(wme
, ctx
, py
, hsize
- data
->oy
+ py
,
4225 screen_size_x(s
) - size
, &mgc
, &cgc
, &mkgc
);
4228 if (py
== data
->cy
&& data
->cx
== screen_size_x(s
)) {
4229 screen_write_cursormove(ctx
, screen_size_x(s
) - 1, py
, 0);
4230 screen_write_putc(ctx
, &grid_default_cell
, '$');
4235 window_copy_write_lines(struct window_mode_entry
*wme
,
4236 struct screen_write_ctx
*ctx
, u_int py
, u_int ny
)
4240 for (yy
= py
; yy
< py
+ ny
; yy
++)
4241 window_copy_write_line(wme
, ctx
, py
);
4245 window_copy_redraw_selection(struct window_mode_entry
*wme
, u_int old_y
)
4247 struct window_copy_mode_data
*data
= wme
->data
;
4248 struct grid
*gd
= data
->backing
->grid
;
4249 u_int new_y
, start
, end
;
4252 if (old_y
<= new_y
) {
4261 * In word selection mode the first word on the line below the cursor
4262 * might be selected, so add this line to the redraw area.
4264 if (data
->selflag
== SEL_WORD
) {
4265 /* Last grid line in data coordinates. */
4266 if (end
< gd
->sy
+ data
->oy
- 1)
4269 window_copy_redraw_lines(wme
, start
, end
- start
+ 1);
4273 window_copy_redraw_lines(struct window_mode_entry
*wme
, u_int py
, u_int ny
)
4275 struct window_pane
*wp
= wme
->wp
;
4276 struct window_copy_mode_data
*data
= wme
->data
;
4277 struct screen_write_ctx ctx
;
4280 screen_write_start_pane(&ctx
, wp
, NULL
);
4281 for (i
= py
; i
< py
+ ny
; i
++)
4282 window_copy_write_line(wme
, &ctx
, i
);
4283 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
4284 screen_write_stop(&ctx
);
4288 window_copy_redraw_screen(struct window_mode_entry
*wme
)
4290 struct window_copy_mode_data
*data
= wme
->data
;
4292 window_copy_redraw_lines(wme
, 0, screen_size_y(&data
->screen
));
4296 window_copy_synchronize_cursor_end(struct window_mode_entry
*wme
, int begin
,
4299 struct window_copy_mode_data
*data
= wme
->data
;
4303 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4304 switch (data
->selflag
) {
4309 if (data
->dy
> yy
|| (data
->dy
== yy
&& data
->dx
> xx
)) {
4310 /* Right to left selection. */
4311 window_copy_cursor_previous_word_pos(wme
,
4312 data
->separators
, &xx
, &yy
);
4315 /* Reset the end. */
4316 data
->endselx
= data
->endselrx
;
4317 data
->endsely
= data
->endselry
;
4319 /* Left to right selection. */
4320 if (xx
>= window_copy_find_length(wme
, yy
) ||
4321 !window_copy_in_set(wme
, xx
+ 1, yy
, WHITESPACE
)) {
4322 window_copy_cursor_next_word_end_pos(wme
,
4323 data
->separators
, &xx
, &yy
);
4326 /* Reset the start. */
4327 data
->selx
= data
->selrx
;
4328 data
->sely
= data
->selry
;
4335 if (data
->dy
> yy
) {
4336 /* Right to left selection. */
4340 /* Reset the end. */
4341 data
->endselx
= data
->endselrx
;
4342 data
->endsely
= data
->endselry
;
4344 /* Left to right selection. */
4345 if (yy
< data
->endselry
)
4346 yy
= data
->endselry
;
4347 xx
= window_copy_find_length(wme
, yy
);
4349 /* Reset the start. */
4350 data
->selx
= data
->selrx
;
4351 data
->sely
= data
->selry
;
4367 window_copy_synchronize_cursor(struct window_mode_entry
*wme
, int no_reset
)
4369 struct window_copy_mode_data
*data
= wme
->data
;
4371 switch (data
->cursordrag
) {
4372 case CURSORDRAG_ENDSEL
:
4373 window_copy_synchronize_cursor_end(wme
, 0, no_reset
);
4375 case CURSORDRAG_SEL
:
4376 window_copy_synchronize_cursor_end(wme
, 1, no_reset
);
4378 case CURSORDRAG_NONE
:
4384 window_copy_update_cursor(struct window_mode_entry
*wme
, u_int cx
, u_int cy
)
4386 struct window_pane
*wp
= wme
->wp
;
4387 struct window_copy_mode_data
*data
= wme
->data
;
4388 struct screen
*s
= &data
->screen
;
4389 struct screen_write_ctx ctx
;
4390 u_int old_cx
, old_cy
;
4392 old_cx
= data
->cx
; old_cy
= data
->cy
;
4393 data
->cx
= cx
; data
->cy
= cy
;
4394 if (old_cx
== screen_size_x(s
))
4395 window_copy_redraw_lines(wme
, old_cy
, 1);
4396 if (data
->cx
== screen_size_x(s
))
4397 window_copy_redraw_lines(wme
, data
->cy
, 1);
4399 screen_write_start_pane(&ctx
, wp
, NULL
);
4400 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
4401 screen_write_stop(&ctx
);
4406 window_copy_start_selection(struct window_mode_entry
*wme
)
4408 struct window_copy_mode_data
*data
= wme
->data
;
4410 data
->selx
= data
->cx
;
4411 data
->sely
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4413 data
->endselx
= data
->selx
;
4414 data
->endsely
= data
->sely
;
4416 data
->cursordrag
= CURSORDRAG_ENDSEL
;
4418 window_copy_set_selection(wme
, 1, 0);
4422 window_copy_adjust_selection(struct window_mode_entry
*wme
, u_int
*selx
,
4425 struct window_copy_mode_data
*data
= wme
->data
;
4426 struct screen
*s
= &data
->screen
;
4433 ty
= screen_hsize(data
->backing
) - data
->oy
;
4435 relpos
= WINDOW_COPY_REL_POS_ABOVE
;
4436 if (!data
->rectflag
)
4439 } else if (sy
> ty
+ screen_size_y(s
) - 1) {
4440 relpos
= WINDOW_COPY_REL_POS_BELOW
;
4441 if (!data
->rectflag
)
4442 sx
= screen_size_x(s
) - 1;
4443 sy
= screen_size_y(s
) - 1;
4445 relpos
= WINDOW_COPY_REL_POS_ON_SCREEN
;
4455 window_copy_update_selection(struct window_mode_entry
*wme
, int may_redraw
,
4458 struct window_copy_mode_data
*data
= wme
->data
;
4459 struct screen
*s
= &data
->screen
;
4461 if (s
->sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
)
4463 return (window_copy_set_selection(wme
, may_redraw
, no_reset
));
4467 window_copy_set_selection(struct window_mode_entry
*wme
, int may_redraw
,
4470 struct window_pane
*wp
= wme
->wp
;
4471 struct window_copy_mode_data
*data
= wme
->data
;
4472 struct screen
*s
= &data
->screen
;
4473 struct options
*oo
= wp
->window
->options
;
4474 struct grid_cell gc
;
4475 u_int sx
, sy
, cy
, endsx
, endsy
;
4476 int startrelpos
, endrelpos
;
4478 window_copy_synchronize_cursor(wme
, no_reset
);
4480 /* Adjust the selection. */
4483 startrelpos
= window_copy_adjust_selection(wme
, &sx
, &sy
);
4485 /* Adjust the end of selection. */
4486 endsx
= data
->endselx
;
4487 endsy
= data
->endsely
;
4488 endrelpos
= window_copy_adjust_selection(wme
, &endsx
, &endsy
);
4490 /* Selection is outside of the current screen */
4491 if (startrelpos
== endrelpos
&&
4492 startrelpos
!= WINDOW_COPY_REL_POS_ON_SCREEN
) {
4493 screen_hide_selection(s
);
4497 /* Set colours and selection. */
4498 style_apply(&gc
, oo
, "mode-style", NULL
);
4499 gc
.flags
|= GRID_FLAG_NOPALETTE
;
4500 screen_set_selection(s
, sx
, sy
, endsx
, endsy
, data
->rectflag
,
4501 data
->modekeys
, &gc
);
4503 if (data
->rectflag
&& may_redraw
) {
4505 * Can't rely on the caller to redraw the right lines for
4506 * rectangle selection - find the highest line and the number
4507 * of lines, and redraw just past that in both directions
4510 if (data
->cursordrag
== CURSORDRAG_ENDSEL
) {
4512 window_copy_redraw_lines(wme
, sy
, cy
- sy
+ 1);
4514 window_copy_redraw_lines(wme
, cy
, sy
- cy
+ 1);
4517 window_copy_redraw_lines(wme
, endsy
,
4520 window_copy_redraw_lines(wme
, cy
,
4530 window_copy_get_selection(struct window_mode_entry
*wme
, size_t *len
)
4532 struct window_pane
*wp
= wme
->wp
;
4533 struct window_copy_mode_data
*data
= wme
->data
;
4534 struct screen
*s
= &data
->screen
;
4537 u_int i
, xx
, yy
, sx
, sy
, ex
, ey
, ey_last
;
4538 u_int firstsx
, lastex
, restex
, restsx
, selx
;
4541 if (data
->screen
.sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
) {
4542 buf
= window_copy_match_at_cursor(data
);
4556 * The selection extends from selx,sely to (adjusted) cx,cy on
4560 /* Find start and end. */
4563 if (yy
< data
->sely
|| (yy
== data
->sely
&& xx
< data
->selx
)) {
4565 ex
= data
->selx
; ey
= data
->sely
;
4567 sx
= data
->selx
; sy
= data
->sely
;
4571 /* Trim ex to end of line. */
4572 ey_last
= window_copy_find_length(wme
, ey
);
4577 * Deal with rectangle-copy if necessary; four situations: start of
4578 * first line (firstsx), end of last line (lastex), start (restsx) and
4579 * end (restex) of all other lines.
4581 xx
= screen_size_x(s
);
4584 * Behave according to mode-keys. If it is emacs, copy like emacs,
4585 * keeping the top-left-most character, and dropping the
4586 * bottom-right-most, regardless of copy direction. If it is vi, also
4587 * keep bottom-right-most character.
4589 keys
= options_get_number(wp
->window
->options
, "mode-keys");
4590 if (data
->rectflag
) {
4592 * Need to ignore the column with the cursor in it, which for
4593 * rectangular copy means knowing which side the cursor is on.
4595 if (data
->cursordrag
== CURSORDRAG_ENDSEL
)
4598 selx
= data
->endselx
;
4599 if (selx
< data
->cx
) {
4600 /* Selection start is on the left. */
4601 if (keys
== MODEKEY_EMACS
) {
4606 lastex
= data
->cx
+ 1;
4607 restex
= data
->cx
+ 1;
4612 /* Cursor is on the left. */
4619 if (keys
== MODEKEY_EMACS
)
4628 /* Copy the lines. */
4629 for (i
= sy
; i
<= ey
; i
++) {
4630 window_copy_copy_line(wme
, &buf
, &off
, i
,
4631 (i
== sy
? firstsx
: restsx
),
4632 (i
== ey
? lastex
: restex
));
4635 /* Don't bother if no data. */
4641 /* Remove final \n (unless at end in vi mode). */
4642 if (keys
== MODEKEY_EMACS
|| lastex
<= ey_last
) {
4643 if (~grid_get_line(data
->backing
->grid
, ey
)->flags
&
4644 GRID_LINE_WRAPPED
|| lastex
!= ey_last
)
4652 window_copy_copy_buffer(struct window_mode_entry
*wme
, const char *prefix
,
4653 void *buf
, size_t len
)
4655 struct window_pane
*wp
= wme
->wp
;
4656 struct screen_write_ctx ctx
;
4658 if (options_get_number(global_options
, "set-clipboard") != 0) {
4659 screen_write_start_pane(&ctx
, wp
, NULL
);
4660 screen_write_setselection(&ctx
, "", buf
, len
);
4661 screen_write_stop(&ctx
);
4662 notify_pane("pane-set-clipboard", wp
);
4665 paste_add(prefix
, buf
, len
);
4669 window_copy_pipe_run(struct window_mode_entry
*wme
, struct session
*s
,
4670 const char *cmd
, size_t *len
)
4675 buf
= window_copy_get_selection(wme
, len
);
4676 if (cmd
== NULL
|| *cmd
== '\0')
4677 cmd
= options_get_string(global_options
, "copy-command");
4678 if (cmd
!= NULL
&& *cmd
!= '\0') {
4679 job
= job_run(cmd
, 0, NULL
, NULL
, s
, NULL
, NULL
, NULL
, NULL
,
4680 NULL
, JOB_NOWAIT
, -1, -1);
4681 bufferevent_write(job_get_event(job
), buf
, *len
);
4687 window_copy_pipe(struct window_mode_entry
*wme
, struct session
*s
,
4692 window_copy_pipe_run(wme
, s
, cmd
, &len
);
4696 window_copy_copy_pipe(struct window_mode_entry
*wme
, struct session
*s
,
4697 const char *prefix
, const char *cmd
)
4702 buf
= window_copy_pipe_run(wme
, s
, cmd
, &len
);
4704 window_copy_copy_buffer(wme
, prefix
, buf
, len
);
4708 window_copy_copy_selection(struct window_mode_entry
*wme
, const char *prefix
)
4713 buf
= window_copy_get_selection(wme
, &len
);
4715 window_copy_copy_buffer(wme
, prefix
, buf
, len
);
4719 window_copy_append_selection(struct window_mode_entry
*wme
)
4721 struct window_pane
*wp
= wme
->wp
;
4723 struct paste_buffer
*pb
;
4724 const char *bufdata
, *bufname
= NULL
;
4725 size_t len
, bufsize
;
4726 struct screen_write_ctx ctx
;
4728 buf
= window_copy_get_selection(wme
, &len
);
4732 if (options_get_number(global_options
, "set-clipboard") != 0) {
4733 screen_write_start_pane(&ctx
, wp
, NULL
);
4734 screen_write_setselection(&ctx
, "", buf
, len
);
4735 screen_write_stop(&ctx
);
4736 notify_pane("pane-set-clipboard", wp
);
4739 pb
= paste_get_top(&bufname
);
4741 bufdata
= paste_buffer_data(pb
, &bufsize
);
4742 buf
= xrealloc(buf
, len
+ bufsize
);
4743 memmove(buf
+ bufsize
, buf
, len
);
4744 memcpy(buf
, bufdata
, bufsize
);
4747 if (paste_set(buf
, len
, bufname
, NULL
) != 0)
4752 window_copy_copy_line(struct window_mode_entry
*wme
, char **buf
, size_t *off
,
4753 u_int sy
, u_int sx
, u_int ex
)
4755 struct window_copy_mode_data
*data
= wme
->data
;
4756 struct grid
*gd
= data
->backing
->grid
;
4757 struct grid_cell gc
;
4758 struct grid_line
*gl
;
4759 struct utf8_data ud
;
4760 u_int i
, xx
, wrapped
= 0;
4767 * Work out if the line was wrapped at the screen edge and all of it is
4770 gl
= grid_get_line(gd
, sy
);
4771 if (gl
->flags
& GRID_LINE_WRAPPED
&& gl
->cellsize
<= gd
->sx
)
4774 /* If the line was wrapped, don't strip spaces (use the full length). */
4778 xx
= window_copy_find_length(wme
, sy
);
4785 for (i
= sx
; i
< ex
; i
++) {
4786 grid_get_cell(gd
, i
, sy
, &gc
);
4787 if (gc
.flags
& GRID_FLAG_PADDING
)
4789 utf8_copy(&ud
, &gc
.data
);
4790 if (ud
.size
== 1 && (gc
.attr
& GRID_ATTR_CHARSET
)) {
4791 s
= tty_acs_get(NULL
, ud
.data
[0]);
4792 if (s
!= NULL
&& strlen(s
) <= sizeof ud
.data
) {
4793 ud
.size
= strlen(s
);
4794 memcpy(ud
.data
, s
, ud
.size
);
4798 *buf
= xrealloc(*buf
, (*off
) + ud
.size
);
4799 memcpy(*buf
+ *off
, ud
.data
, ud
.size
);
4804 /* Only add a newline if the line wasn't wrapped. */
4805 if (!wrapped
|| ex
!= xx
) {
4806 *buf
= xrealloc(*buf
, (*off
) + 1);
4807 (*buf
)[(*off
)++] = '\n';
4812 window_copy_clear_selection(struct window_mode_entry
*wme
)
4814 struct window_copy_mode_data
*data
= wme
->data
;
4817 screen_clear_selection(&data
->screen
);
4819 data
->cursordrag
= CURSORDRAG_NONE
;
4820 data
->lineflag
= LINE_SEL_NONE
;
4821 data
->selflag
= SEL_CHAR
;
4823 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4824 px
= window_copy_find_length(wme
, py
);
4826 window_copy_update_cursor(wme
, px
, data
->cy
);
4830 window_copy_in_set(struct window_mode_entry
*wme
, u_int px
, u_int py
,
4833 struct window_copy_mode_data
*data
= wme
->data
;
4834 struct grid_cell gc
;
4836 grid_get_cell(data
->backing
->grid
, px
, py
, &gc
);
4837 if (gc
.flags
& GRID_FLAG_PADDING
)
4839 return (utf8_cstrhas(set
, &gc
.data
));
4843 window_copy_find_length(struct window_mode_entry
*wme
, u_int py
)
4845 struct window_copy_mode_data
*data
= wme
->data
;
4847 return (grid_line_length(data
->backing
->grid
, py
));
4851 window_copy_cursor_start_of_line(struct window_mode_entry
*wme
)
4853 struct window_copy_mode_data
*data
= wme
->data
;
4854 struct screen
*back_s
= data
->backing
;
4855 struct grid_reader gr
;
4856 u_int px
, py
, oldy
, hsize
;
4859 hsize
= screen_hsize(back_s
);
4860 py
= hsize
+ data
->cy
- data
->oy
;
4863 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4864 grid_reader_cursor_start_of_line(&gr
, 1);
4865 grid_reader_get_cursor(&gr
, &px
, &py
);
4866 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
4870 window_copy_cursor_back_to_indentation(struct window_mode_entry
*wme
)
4872 struct window_copy_mode_data
*data
= wme
->data
;
4873 struct screen
*back_s
= data
->backing
;
4874 struct grid_reader gr
;
4875 u_int px
, py
, oldy
, hsize
;
4878 hsize
= screen_hsize(back_s
);
4879 py
= hsize
+ data
->cy
- data
->oy
;
4882 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4883 grid_reader_cursor_back_to_indentation(&gr
);
4884 grid_reader_get_cursor(&gr
, &px
, &py
);
4885 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
4889 window_copy_cursor_end_of_line(struct window_mode_entry
*wme
)
4891 struct window_copy_mode_data
*data
= wme
->data
;
4892 struct screen
*back_s
= data
->backing
;
4893 struct grid_reader gr
;
4894 u_int px
, py
, oldy
, hsize
;
4897 hsize
= screen_hsize(back_s
);
4898 py
= hsize
+ data
->cy
- data
->oy
;
4901 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4902 if (data
->screen
.sel
!= NULL
&& data
->rectflag
)
4903 grid_reader_cursor_end_of_line(&gr
, 1, 1);
4905 grid_reader_cursor_end_of_line(&gr
, 1, 0);
4906 grid_reader_get_cursor(&gr
, &px
, &py
);
4907 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
4908 data
->oy
, oldy
, px
, py
, 0);
4912 window_copy_other_end(struct window_mode_entry
*wme
)
4914 struct window_copy_mode_data
*data
= wme
->data
;
4915 struct screen
*s
= &data
->screen
;
4916 u_int selx
, sely
, cy
, yy
, hsize
;
4918 if (s
->sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
)
4921 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
4922 data
->lineflag
= LINE_SEL_RIGHT_LEFT
;
4923 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
4924 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
4926 switch (data
->cursordrag
) {
4927 case CURSORDRAG_NONE
:
4928 case CURSORDRAG_SEL
:
4929 data
->cursordrag
= CURSORDRAG_ENDSEL
;
4931 case CURSORDRAG_ENDSEL
:
4932 data
->cursordrag
= CURSORDRAG_SEL
;
4936 selx
= data
->endselx
;
4937 sely
= data
->endsely
;
4938 if (data
->cursordrag
== CURSORDRAG_SEL
) {
4944 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4948 hsize
= screen_hsize(data
->backing
);
4949 if (sely
< hsize
- data
->oy
) { /* above */
4950 data
->oy
= hsize
- sely
;
4952 } else if (sely
> hsize
- data
->oy
+ screen_size_y(s
)) { /* below */
4953 data
->oy
= hsize
- sely
+ screen_size_y(s
) - 1;
4954 data
->cy
= screen_size_y(s
) - 1;
4956 data
->cy
= cy
+ sely
- yy
;
4958 window_copy_update_selection(wme
, 1, 1);
4959 window_copy_redraw_screen(wme
);
4963 window_copy_cursor_left(struct window_mode_entry
*wme
)
4965 struct window_copy_mode_data
*data
= wme
->data
;
4966 struct screen
*back_s
= data
->backing
;
4967 struct grid_reader gr
;
4968 u_int px
, py
, oldy
, hsize
;
4971 hsize
= screen_hsize(back_s
);
4972 py
= hsize
+ data
->cy
- data
->oy
;
4975 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4976 grid_reader_cursor_left(&gr
, 1);
4977 grid_reader_get_cursor(&gr
, &px
, &py
);
4978 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
4982 window_copy_cursor_right(struct window_mode_entry
*wme
, int all
)
4984 struct window_copy_mode_data
*data
= wme
->data
;
4985 struct screen
*back_s
= data
->backing
;
4986 struct grid_reader gr
;
4987 u_int px
, py
, oldy
, hsize
;
4990 hsize
= screen_hsize(back_s
);
4991 py
= hsize
+ data
->cy
- data
->oy
;
4994 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4995 grid_reader_cursor_right(&gr
, 1, all
);
4996 grid_reader_get_cursor(&gr
, &px
, &py
);
4997 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
4998 data
->oy
, oldy
, px
, py
, 0);
5002 window_copy_cursor_up(struct window_mode_entry
*wme
, int scroll_only
)
5004 struct window_copy_mode_data
*data
= wme
->data
;
5005 struct screen
*s
= &data
->screen
;
5006 u_int ox
, oy
, px
, py
;
5009 norectsel
= data
->screen
.sel
== NULL
|| !data
->rectflag
;
5010 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5011 ox
= window_copy_find_length(wme
, oy
);
5012 if (norectsel
&& data
->cx
!= ox
) {
5013 data
->lastcx
= data
->cx
;
5017 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
&& oy
== data
->sely
)
5018 window_copy_other_end(wme
);
5020 if (scroll_only
|| data
->cy
== 0) {
5022 data
->cx
= data
->lastcx
;
5023 window_copy_scroll_down(wme
, 1);
5025 if (data
->cy
== screen_size_y(s
) - 1)
5026 window_copy_redraw_lines(wme
, data
->cy
, 1);
5028 window_copy_redraw_lines(wme
, data
->cy
, 2);
5032 window_copy_update_cursor(wme
, data
->lastcx
,
5035 window_copy_update_cursor(wme
, data
->cx
, data
->cy
- 1);
5036 if (window_copy_update_selection(wme
, 1, 0)) {
5037 if (data
->cy
== screen_size_y(s
) - 1)
5038 window_copy_redraw_lines(wme
, data
->cy
, 1);
5040 window_copy_redraw_lines(wme
, data
->cy
, 2);
5045 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5046 px
= window_copy_find_length(wme
, py
);
5047 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
5050 window_copy_update_cursor(wme
, px
, data
->cy
);
5051 if (window_copy_update_selection(wme
, 1, 0))
5052 window_copy_redraw_lines(wme
, data
->cy
, 1);
5056 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
5058 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5060 px
= screen_size_x(data
->backing
);
5062 px
= window_copy_find_length(wme
, py
);
5063 window_copy_update_cursor(wme
, px
, data
->cy
);
5064 if (window_copy_update_selection(wme
, 1, 0))
5065 window_copy_redraw_lines(wme
, data
->cy
, 1);
5067 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
5069 window_copy_update_cursor(wme
, 0, data
->cy
);
5070 if (window_copy_update_selection(wme
, 1, 0))
5071 window_copy_redraw_lines(wme
, data
->cy
, 1);
5076 window_copy_cursor_down(struct window_mode_entry
*wme
, int scroll_only
)
5078 struct window_copy_mode_data
*data
= wme
->data
;
5079 struct screen
*s
= &data
->screen
;
5080 u_int ox
, oy
, px
, py
;
5083 norectsel
= data
->screen
.sel
== NULL
|| !data
->rectflag
;
5084 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5085 ox
= window_copy_find_length(wme
, oy
);
5086 if (norectsel
&& data
->cx
!= ox
) {
5087 data
->lastcx
= data
->cx
;
5091 if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
&& oy
== data
->endsely
)
5092 window_copy_other_end(wme
);
5094 if (scroll_only
|| data
->cy
== screen_size_y(s
) - 1) {
5096 data
->cx
= data
->lastcx
;
5097 window_copy_scroll_up(wme
, 1);
5098 if (scroll_only
&& data
->cy
> 0)
5099 window_copy_redraw_lines(wme
, data
->cy
- 1, 2);
5102 window_copy_update_cursor(wme
, data
->lastcx
,
5105 window_copy_update_cursor(wme
, data
->cx
, data
->cy
+ 1);
5106 if (window_copy_update_selection(wme
, 1, 0))
5107 window_copy_redraw_lines(wme
, data
->cy
- 1, 2);
5111 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5112 px
= window_copy_find_length(wme
, py
);
5113 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
5116 window_copy_update_cursor(wme
, px
, data
->cy
);
5117 if (window_copy_update_selection(wme
, 1, 0))
5118 window_copy_redraw_lines(wme
, data
->cy
, 1);
5122 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
5124 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5126 px
= screen_size_x(data
->backing
);
5128 px
= window_copy_find_length(wme
, py
);
5129 window_copy_update_cursor(wme
, px
, data
->cy
);
5130 if (window_copy_update_selection(wme
, 1, 0))
5131 window_copy_redraw_lines(wme
, data
->cy
, 1);
5133 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
5135 window_copy_update_cursor(wme
, 0, data
->cy
);
5136 if (window_copy_update_selection(wme
, 1, 0))
5137 window_copy_redraw_lines(wme
, data
->cy
, 1);
5142 window_copy_cursor_jump(struct window_mode_entry
*wme
)
5144 struct window_copy_mode_data
*data
= wme
->data
;
5145 struct screen
*back_s
= data
->backing
;
5146 struct grid_reader gr
;
5147 u_int px
, py
, oldy
, hsize
;
5150 hsize
= screen_hsize(back_s
);
5151 py
= hsize
+ data
->cy
- data
->oy
;
5154 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5155 if (grid_reader_cursor_jump(&gr
, data
->jumpchar
)) {
5156 grid_reader_get_cursor(&gr
, &px
, &py
);
5157 window_copy_acquire_cursor_down(wme
, hsize
,
5158 screen_size_y(back_s
), data
->oy
, oldy
, px
, py
, 0);
5163 window_copy_cursor_jump_back(struct window_mode_entry
*wme
)
5165 struct window_copy_mode_data
*data
= wme
->data
;
5166 struct screen
*back_s
= data
->backing
;
5167 struct grid_reader gr
;
5168 u_int px
, py
, oldy
, hsize
;
5171 hsize
= screen_hsize(back_s
);
5172 py
= hsize
+ data
->cy
- data
->oy
;
5175 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5176 grid_reader_cursor_left(&gr
, 0);
5177 if (grid_reader_cursor_jump_back(&gr
, data
->jumpchar
)) {
5178 grid_reader_get_cursor(&gr
, &px
, &py
);
5179 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
,
5185 window_copy_cursor_jump_to(struct window_mode_entry
*wme
)
5187 struct window_copy_mode_data
*data
= wme
->data
;
5188 struct screen
*back_s
= data
->backing
;
5189 struct grid_reader gr
;
5190 u_int px
, py
, oldy
, hsize
;
5193 hsize
= screen_hsize(back_s
);
5194 py
= hsize
+ data
->cy
- data
->oy
;
5197 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5198 if (grid_reader_cursor_jump(&gr
, data
->jumpchar
)) {
5199 grid_reader_cursor_left(&gr
, 1);
5200 grid_reader_get_cursor(&gr
, &px
, &py
);
5201 window_copy_acquire_cursor_down(wme
, hsize
,
5202 screen_size_y(back_s
), data
->oy
, oldy
, px
, py
, 0);
5207 window_copy_cursor_jump_to_back(struct window_mode_entry
*wme
)
5209 struct window_copy_mode_data
*data
= wme
->data
;
5210 struct screen
*back_s
= data
->backing
;
5211 struct grid_reader gr
;
5212 u_int px
, py
, oldy
, hsize
;
5215 hsize
= screen_hsize(back_s
);
5216 py
= hsize
+ data
->cy
- data
->oy
;
5219 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5220 grid_reader_cursor_left(&gr
, 0);
5221 grid_reader_cursor_left(&gr
, 0);
5222 if (grid_reader_cursor_jump_back(&gr
, data
->jumpchar
)) {
5223 grid_reader_cursor_right(&gr
, 1, 0);
5224 grid_reader_get_cursor(&gr
, &px
, &py
);
5225 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
,
5231 window_copy_cursor_next_word(struct window_mode_entry
*wme
,
5232 const char *separators
)
5234 struct window_copy_mode_data
*data
= wme
->data
;
5235 struct screen
*back_s
= data
->backing
;
5236 struct grid_reader gr
;
5237 u_int px
, py
, oldy
, hsize
;
5240 hsize
= screen_hsize(back_s
);
5241 py
= hsize
+ data
->cy
- data
->oy
;
5244 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5245 grid_reader_cursor_next_word(&gr
, separators
);
5246 grid_reader_get_cursor(&gr
, &px
, &py
);
5247 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
5248 data
->oy
, oldy
, px
, py
, 0);
5251 /* Compute the next place where a word ends. */
5253 window_copy_cursor_next_word_end_pos(struct window_mode_entry
*wme
,
5254 const char *separators
, u_int
*ppx
, u_int
*ppy
)
5256 struct window_pane
*wp
= wme
->wp
;
5257 struct window_copy_mode_data
*data
= wme
->data
;
5258 struct options
*oo
= wp
->window
->options
;
5259 struct screen
*back_s
= data
->backing
;
5260 struct grid_reader gr
;
5261 u_int px
, py
, hsize
;
5264 hsize
= screen_hsize(back_s
);
5265 py
= hsize
+ data
->cy
- data
->oy
;
5267 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5268 if (options_get_number(oo
, "mode-keys") == MODEKEY_VI
) {
5269 if (!grid_reader_in_set(&gr
, WHITESPACE
))
5270 grid_reader_cursor_right(&gr
, 0, 0);
5271 grid_reader_cursor_next_word_end(&gr
, separators
);
5272 grid_reader_cursor_left(&gr
, 1);
5274 grid_reader_cursor_next_word_end(&gr
, separators
);
5275 grid_reader_get_cursor(&gr
, &px
, &py
);
5280 /* Move to the next place where a word ends. */
5282 window_copy_cursor_next_word_end(struct window_mode_entry
*wme
,
5283 const char *separators
, int no_reset
)
5285 struct window_pane
*wp
= wme
->wp
;
5286 struct window_copy_mode_data
*data
= wme
->data
;
5287 struct options
*oo
= wp
->window
->options
;
5288 struct screen
*back_s
= data
->backing
;
5289 struct grid_reader gr
;
5290 u_int px
, py
, oldy
, hsize
;
5293 hsize
= screen_hsize(back_s
);
5294 py
= hsize
+ data
->cy
- data
->oy
;
5297 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5298 if (options_get_number(oo
, "mode-keys") == MODEKEY_VI
) {
5299 if (!grid_reader_in_set(&gr
, WHITESPACE
))
5300 grid_reader_cursor_right(&gr
, 0, 0);
5301 grid_reader_cursor_next_word_end(&gr
, separators
);
5302 grid_reader_cursor_left(&gr
, 1);
5304 grid_reader_cursor_next_word_end(&gr
, separators
);
5305 grid_reader_get_cursor(&gr
, &px
, &py
);
5306 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
5307 data
->oy
, oldy
, px
, py
, no_reset
);
5310 /* Compute the previous place where a word begins. */
5312 window_copy_cursor_previous_word_pos(struct window_mode_entry
*wme
,
5313 const char *separators
, u_int
*ppx
, u_int
*ppy
)
5315 struct window_copy_mode_data
*data
= wme
->data
;
5316 struct screen
*back_s
= data
->backing
;
5317 struct grid_reader gr
;
5318 u_int px
, py
, hsize
;
5321 hsize
= screen_hsize(back_s
);
5322 py
= hsize
+ data
->cy
- data
->oy
;
5324 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5325 grid_reader_cursor_previous_word(&gr
, separators
, /* already= */ 0,
5326 /* stop_at_eol= */ 1);
5327 grid_reader_get_cursor(&gr
, &px
, &py
);
5332 /* Move to the previous place where a word begins. */
5334 window_copy_cursor_previous_word(struct window_mode_entry
*wme
,
5335 const char *separators
, int already
)
5337 struct window_copy_mode_data
*data
= wme
->data
;
5338 struct window
*w
= wme
->wp
->window
;
5339 struct screen
*back_s
= data
->backing
;
5340 struct grid_reader gr
;
5341 u_int px
, py
, oldy
, hsize
;
5344 if (options_get_number(w
->options
, "mode-keys") == MODEKEY_EMACS
)
5350 hsize
= screen_hsize(back_s
);
5351 py
= hsize
+ data
->cy
- data
->oy
;
5354 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5355 grid_reader_cursor_previous_word(&gr
, separators
, already
, stop_at_eol
);
5356 grid_reader_get_cursor(&gr
, &px
, &py
);
5357 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
5361 window_copy_scroll_up(struct window_mode_entry
*wme
, u_int ny
)
5363 struct window_pane
*wp
= wme
->wp
;
5364 struct window_copy_mode_data
*data
= wme
->data
;
5365 struct screen
*s
= &data
->screen
;
5366 struct screen_write_ctx ctx
;
5374 if (data
->searchmark
!= NULL
&& !data
->timeout
)
5375 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
5376 window_copy_update_selection(wme
, 0, 0);
5378 screen_write_start_pane(&ctx
, wp
, NULL
);
5379 screen_write_cursormove(&ctx
, 0, 0, 0);
5380 screen_write_deleteline(&ctx
, ny
, 8);
5381 window_copy_write_lines(wme
, &ctx
, screen_size_y(s
) - ny
, ny
);
5382 window_copy_write_line(wme
, &ctx
, 0);
5383 if (screen_size_y(s
) > 1)
5384 window_copy_write_line(wme
, &ctx
, 1);
5385 if (screen_size_y(s
) > 3)
5386 window_copy_write_line(wme
, &ctx
, screen_size_y(s
) - 2);
5387 if (s
->sel
!= NULL
&& screen_size_y(s
) > ny
)
5388 window_copy_write_line(wme
, &ctx
, screen_size_y(s
) - ny
- 1);
5389 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
5390 screen_write_stop(&ctx
);
5394 window_copy_scroll_down(struct window_mode_entry
*wme
, u_int ny
)
5396 struct window_pane
*wp
= wme
->wp
;
5397 struct window_copy_mode_data
*data
= wme
->data
;
5398 struct screen
*s
= &data
->screen
;
5399 struct screen_write_ctx ctx
;
5401 if (ny
> screen_hsize(data
->backing
))
5404 if (data
->oy
> screen_hsize(data
->backing
) - ny
)
5405 ny
= screen_hsize(data
->backing
) - data
->oy
;
5410 if (data
->searchmark
!= NULL
&& !data
->timeout
)
5411 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
5412 window_copy_update_selection(wme
, 0, 0);
5414 screen_write_start_pane(&ctx
, wp
, NULL
);
5415 screen_write_cursormove(&ctx
, 0, 0, 0);
5416 screen_write_insertline(&ctx
, ny
, 8);
5417 window_copy_write_lines(wme
, &ctx
, 0, ny
);
5418 if (s
->sel
!= NULL
&& screen_size_y(s
) > ny
)
5419 window_copy_write_line(wme
, &ctx
, ny
);
5420 else if (ny
== 1) /* nuke position */
5421 window_copy_write_line(wme
, &ctx
, 1);
5422 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
5423 screen_write_stop(&ctx
);
5427 window_copy_rectangle_set(struct window_mode_entry
*wme
, int rectflag
)
5429 struct window_copy_mode_data
*data
= wme
->data
;
5432 data
->rectflag
= rectflag
;
5434 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5435 px
= window_copy_find_length(wme
, py
);
5437 window_copy_update_cursor(wme
, px
, data
->cy
);
5439 window_copy_update_selection(wme
, 1, 0);
5440 window_copy_redraw_screen(wme
);
5444 window_copy_move_mouse(struct mouse_event
*m
)
5446 struct window_pane
*wp
;
5447 struct window_mode_entry
*wme
;
5450 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5453 wme
= TAILQ_FIRST(&wp
->modes
);
5456 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5459 if (cmd_mouse_at(wp
, m
, &x
, &y
, 0) != 0)
5462 window_copy_update_cursor(wme
, x
, y
);
5466 window_copy_start_drag(struct client
*c
, struct mouse_event
*m
)
5468 struct window_pane
*wp
;
5469 struct window_mode_entry
*wme
;
5470 struct window_copy_mode_data
*data
;
5476 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5479 wme
= TAILQ_FIRST(&wp
->modes
);
5482 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5485 if (cmd_mouse_at(wp
, m
, &x
, &y
, 1) != 0)
5488 c
->tty
.mouse_drag_update
= window_copy_drag_update
;
5489 c
->tty
.mouse_drag_release
= window_copy_drag_release
;
5492 yg
= screen_hsize(data
->backing
) + y
- data
->oy
;
5493 if (x
< data
->selrx
|| x
> data
->endselrx
|| yg
!= data
->selry
)
5494 data
->selflag
= SEL_CHAR
;
5495 switch (data
->selflag
) {
5497 if (data
->separators
!= NULL
) {
5498 window_copy_update_cursor(wme
, x
, y
);
5499 window_copy_cursor_previous_word_pos(wme
,
5500 data
->separators
, &x
, &y
);
5501 y
-= screen_hsize(data
->backing
) - data
->oy
;
5503 window_copy_update_cursor(wme
, x
, y
);
5506 window_copy_update_cursor(wme
, 0, y
);
5509 window_copy_update_cursor(wme
, x
, y
);
5510 window_copy_start_selection(wme
);
5514 window_copy_redraw_screen(wme
);
5515 window_copy_drag_update(c
, m
);
5519 window_copy_drag_update(struct client
*c
, struct mouse_event
*m
)
5521 struct window_pane
*wp
;
5522 struct window_mode_entry
*wme
;
5523 struct window_copy_mode_data
*data
;
5524 u_int x
, y
, old_cx
, old_cy
;
5525 struct timeval tv
= {
5526 .tv_usec
= WINDOW_COPY_DRAG_REPEAT_TIME
5532 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5535 wme
= TAILQ_FIRST(&wp
->modes
);
5538 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5542 evtimer_del(&data
->dragtimer
);
5544 if (cmd_mouse_at(wp
, m
, &x
, &y
, 0) != 0)
5549 window_copy_update_cursor(wme
, x
, y
);
5550 if (window_copy_update_selection(wme
, 1, 0))
5551 window_copy_redraw_selection(wme
, old_cy
);
5552 if (old_cy
!= data
->cy
|| old_cx
== data
->cx
) {
5554 evtimer_add(&data
->dragtimer
, &tv
);
5555 window_copy_cursor_up(wme
, 1);
5556 } else if (y
== screen_size_y(&data
->screen
) - 1) {
5557 evtimer_add(&data
->dragtimer
, &tv
);
5558 window_copy_cursor_down(wme
, 1);
5564 window_copy_drag_release(struct client
*c
, struct mouse_event
*m
)
5566 struct window_pane
*wp
;
5567 struct window_mode_entry
*wme
;
5568 struct window_copy_mode_data
*data
;
5573 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5576 wme
= TAILQ_FIRST(&wp
->modes
);
5579 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5583 evtimer_del(&data
->dragtimer
);
5587 window_copy_jump_to_mark(struct window_mode_entry
*wme
)
5589 struct window_copy_mode_data
*data
= wme
->data
;
5593 tmy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5594 data
->cx
= data
->mx
;
5595 if (data
->my
< screen_hsize(data
->backing
)) {
5597 data
->oy
= screen_hsize(data
->backing
) - data
->my
;
5599 data
->cy
= data
->my
- screen_hsize(data
->backing
);
5605 window_copy_update_selection(wme
, 0, 0);
5606 window_copy_redraw_screen(wme
);
5609 /* Scroll up if the cursor went off the visible screen. */
5611 window_copy_acquire_cursor_up(struct window_mode_entry
*wme
, u_int hsize
,
5612 u_int oy
, u_int oldy
, u_int px
, u_int py
)
5614 u_int cy
, yy
, ny
, nd
;
5627 window_copy_cursor_up(wme
, 1);
5630 window_copy_update_cursor(wme
, px
, cy
);
5631 if (window_copy_update_selection(wme
, 1, 0))
5632 window_copy_redraw_lines(wme
, cy
, nd
);
5635 /* Scroll down if the cursor went off the visible screen. */
5637 window_copy_acquire_cursor_down(struct window_mode_entry
*wme
, u_int hsize
,
5638 u_int sy
, u_int oy
, u_int oldy
, u_int px
, u_int py
, int no_reset
)
5640 u_int cy
, yy
, ny
, nd
;
5642 cy
= py
- hsize
+ oy
;
5653 window_copy_cursor_down(wme
, 1);
5657 window_copy_update_cursor(wme
, px
, yy
);
5659 window_copy_update_cursor(wme
, px
, cy
);
5660 if (window_copy_update_selection(wme
, 1, no_reset
))
5661 window_copy_redraw_lines(wme
, oldy
, nd
);