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 */
226 int viewmode
; /* view mode entered */
228 u_int oy
; /* number of lines scrolled up */
230 u_int selx
; /* beginning of selection */
233 u_int endselx
; /* end of selection */
237 CURSORDRAG_NONE
, /* selection is independent of cursor */
238 CURSORDRAG_ENDSEL
, /* end is synchronized with cursor */
239 CURSORDRAG_SEL
, /* start is synchronized with cursor */
247 } lineflag
; /* line selection mode */
248 int rectflag
; /* in rectangle copy mode? */
249 int scroll_exit
; /* exit on scroll to end? */
250 int hide_position
; /* hide position marker */
253 SEL_CHAR
, /* select one char at a time */
254 SEL_WORD
, /* select one word at a time */
255 SEL_LINE
, /* select one line at a time */
258 const char *separators
; /* word separators */
260 u_int dx
; /* drag start position */
263 u_int selrx
; /* selection reset positions */
271 u_int lastcx
; /* position in last line w/ content */
272 u_int lastsx
; /* size of last line w/ content */
274 u_int mx
; /* mark position */
291 int timeout
; /* search has timed out */
292 #define WINDOW_COPY_SEARCH_TIMEOUT 10000
293 #define WINDOW_COPY_SEARCH_ALL_TIMEOUT 200
296 struct utf8_data
*jumpchar
;
298 struct event dragtimer
;
299 #define WINDOW_COPY_DRAG_REPEAT_TIME 50000
303 window_copy_scroll_timer(__unused
int fd
, __unused
short events
, void *arg
)
305 struct window_mode_entry
*wme
= arg
;
306 struct window_pane
*wp
= wme
->wp
;
307 struct window_copy_mode_data
*data
= wme
->data
;
308 struct timeval tv
= {
309 .tv_usec
= WINDOW_COPY_DRAG_REPEAT_TIME
312 evtimer_del(&data
->dragtimer
);
314 if (TAILQ_FIRST(&wp
->modes
) != wme
)
318 evtimer_add(&data
->dragtimer
, &tv
);
319 window_copy_cursor_up(wme
, 1);
320 } else if (data
->cy
== screen_size_y(&data
->screen
) - 1) {
321 evtimer_add(&data
->dragtimer
, &tv
);
322 window_copy_cursor_down(wme
, 1);
326 static struct screen
*
327 window_copy_clone_screen(struct screen
*src
, struct screen
*hint
, u_int
*cx
,
331 const struct grid_line
*gl
;
335 dst
= xcalloc(1, sizeof *dst
);
337 sy
= screen_hsize(src
) + screen_size_y(src
);
339 while (sy
> screen_hsize(src
)) {
340 gl
= grid_peek_line(src
->grid
, sy
- 1);
341 if (gl
->cellused
!= 0)
346 log_debug("%s: target screen is %ux%u, source %ux%u", __func__
,
347 screen_size_x(src
), sy
, screen_size_x(hint
),
348 screen_hsize(src
) + screen_size_y(src
));
349 screen_init(dst
, screen_size_x(src
), sy
, screen_hlimit(src
));
352 * Ensure history is on for the backing grid so lines are not deleted
355 dst
->grid
->flags
|= GRID_HISTORY
;
356 grid_duplicate_lines(dst
->grid
, 0, src
->grid
, 0, sy
);
358 dst
->grid
->sy
= sy
- screen_hsize(src
);
359 dst
->grid
->hsize
= screen_hsize(src
);
360 dst
->grid
->hscrolled
= src
->grid
->hscrolled
;
361 if (src
->cy
> dst
->grid
->sy
- 1) {
363 dst
->cy
= dst
->grid
->sy
- 1;
369 if (cx
!= NULL
&& cy
!= NULL
) {
371 *cy
= screen_hsize(dst
) + dst
->cy
;
372 reflow
= (screen_size_x(hint
) != screen_size_x(dst
));
377 grid_wrap_position(dst
->grid
, *cx
, *cy
, &wx
, &wy
);
378 screen_resize_cursor(dst
, screen_size_x(hint
), screen_size_y(hint
), 1,
381 grid_unwrap_position(dst
->grid
, cx
, cy
, wx
, wy
);
386 static struct window_copy_mode_data
*
387 window_copy_common_init(struct window_mode_entry
*wme
)
389 struct window_pane
*wp
= wme
->wp
;
390 struct window_copy_mode_data
*data
;
391 struct screen
*base
= &wp
->base
;
393 wme
->data
= data
= xcalloc(1, sizeof *data
);
395 data
->cursordrag
= CURSORDRAG_NONE
;
396 data
->lineflag
= LINE_SEL_NONE
;
397 data
->selflag
= SEL_CHAR
;
399 if (wp
->searchstr
!= NULL
) {
400 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
401 data
->searchregex
= wp
->searchregex
;
402 data
->searchstr
= xstrdup(wp
->searchstr
);
404 data
->searchtype
= WINDOW_COPY_OFF
;
405 data
->searchregex
= 0;
406 data
->searchstr
= NULL
;
408 data
->searchx
= data
->searchy
= data
->searcho
= -1;
411 data
->jumptype
= WINDOW_COPY_OFF
;
412 data
->jumpchar
= NULL
;
414 screen_init(&data
->screen
, screen_size_x(base
), screen_size_y(base
), 0);
415 data
->modekeys
= options_get_number(wp
->window
->options
, "mode-keys");
417 evtimer_set(&data
->dragtimer
, window_copy_scroll_timer
, wme
);
422 static struct screen
*
423 window_copy_init(struct window_mode_entry
*wme
,
424 __unused
struct cmd_find_state
*fs
, struct args
*args
)
426 struct window_pane
*wp
= wme
->swp
;
427 struct window_copy_mode_data
*data
;
428 struct screen
*base
= &wp
->base
;
429 struct screen_write_ctx ctx
;
432 data
= window_copy_common_init(wme
);
433 data
->backing
= window_copy_clone_screen(base
, &data
->screen
, &cx
, &cy
,
434 wme
->swp
!= wme
->wp
);
437 if (cy
< screen_hsize(data
->backing
)) {
439 data
->oy
= screen_hsize(data
->backing
) - cy
;
441 data
->cy
= cy
- screen_hsize(data
->backing
);
445 data
->scroll_exit
= args_has(args
, 'e');
446 data
->hide_position
= args_has(args
, 'H');
448 data
->screen
.cx
= data
->cx
;
449 data
->screen
.cy
= data
->cy
;
451 data
->my
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
454 screen_write_start(&ctx
, &data
->screen
);
455 for (i
= 0; i
< screen_size_y(&data
->screen
); i
++)
456 window_copy_write_line(wme
, &ctx
, i
);
457 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
458 screen_write_stop(&ctx
);
460 return (&data
->screen
);
463 static struct screen
*
464 window_copy_view_init(struct window_mode_entry
*wme
,
465 __unused
struct cmd_find_state
*fs
, __unused
struct args
*args
)
467 struct window_pane
*wp
= wme
->wp
;
468 struct window_copy_mode_data
*data
;
469 struct screen
*base
= &wp
->base
;
472 data
= window_copy_common_init(wme
);
475 data
->backing
= s
= xmalloc(sizeof *data
->backing
);
476 screen_init(s
, screen_size_x(base
), screen_size_y(base
), UINT_MAX
);
478 data
->my
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
481 return (&data
->screen
);
485 window_copy_free(struct window_mode_entry
*wme
)
487 struct window_copy_mode_data
*data
= wme
->data
;
489 evtimer_del(&data
->dragtimer
);
491 free(data
->searchmark
);
492 free(data
->searchstr
);
493 free(data
->jumpchar
);
495 screen_free(data
->backing
);
498 screen_free(&data
->screen
);
503 window_copy_add(struct window_pane
*wp
, const char *fmt
, ...)
508 window_copy_vadd(wp
, fmt
, ap
);
513 window_copy_vadd(struct window_pane
*wp
, const char *fmt
, va_list ap
)
515 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
516 struct window_copy_mode_data
*data
= wme
->data
;
517 struct screen
*backing
= data
->backing
;
518 struct screen_write_ctx back_ctx
, ctx
;
520 u_int old_hsize
, old_cy
;
522 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
524 old_hsize
= screen_hsize(data
->backing
);
525 screen_write_start(&back_ctx
, backing
);
526 if (data
->backing_written
) {
528 * On the second or later line, do a CRLF before writing
529 * (so it's on a new line).
531 screen_write_carriagereturn(&back_ctx
);
532 screen_write_linefeed(&back_ctx
, 0, 8);
534 data
->backing_written
= 1;
535 old_cy
= backing
->cy
;
536 screen_write_vnputs(&back_ctx
, 0, &gc
, fmt
, ap
);
537 screen_write_stop(&back_ctx
);
539 data
->oy
+= screen_hsize(data
->backing
) - old_hsize
;
541 screen_write_start_pane(&ctx
, wp
, &data
->screen
);
544 * If the history has changed, draw the top line.
545 * (If there's any history at all, it has changed.)
547 if (screen_hsize(data
->backing
))
548 window_copy_redraw_lines(wme
, 0, 1);
550 /* Write the new lines. */
551 window_copy_redraw_lines(wme
, old_cy
, backing
->cy
- old_cy
+ 1);
553 screen_write_stop(&ctx
);
557 window_copy_pageup(struct window_pane
*wp
, int half_page
)
559 window_copy_pageup1(TAILQ_FIRST(&wp
->modes
), half_page
);
563 window_copy_pageup1(struct window_mode_entry
*wme
, int half_page
)
565 struct window_copy_mode_data
*data
= wme
->data
;
566 struct screen
*s
= &data
->screen
;
567 u_int n
, ox
, oy
, px
, py
;
569 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
570 ox
= window_copy_find_length(wme
, oy
);
572 if (data
->cx
!= ox
) {
573 data
->lastcx
= data
->cx
;
576 data
->cx
= data
->lastcx
;
579 if (screen_size_y(s
) > 2) {
581 n
= screen_size_y(s
) / 2;
583 n
= screen_size_y(s
) - 2;
586 if (data
->oy
+ n
> screen_hsize(data
->backing
)) {
587 data
->oy
= screen_hsize(data
->backing
);
595 if (data
->screen
.sel
== NULL
|| !data
->rectflag
) {
596 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
597 px
= window_copy_find_length(wme
, py
);
598 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
600 window_copy_cursor_end_of_line(wme
);
603 if (data
->searchmark
!= NULL
&& !data
->timeout
)
604 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
605 window_copy_update_selection(wme
, 1, 0);
606 window_copy_redraw_screen(wme
);
610 window_copy_pagedown(struct window_mode_entry
*wme
, int half_page
,
613 struct window_copy_mode_data
*data
= wme
->data
;
614 struct screen
*s
= &data
->screen
;
615 u_int n
, ox
, oy
, px
, py
;
617 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
618 ox
= window_copy_find_length(wme
, oy
);
620 if (data
->cx
!= ox
) {
621 data
->lastcx
= data
->cx
;
624 data
->cx
= data
->lastcx
;
627 if (screen_size_y(s
) > 2) {
629 n
= screen_size_y(s
) / 2;
631 n
= screen_size_y(s
) - 2;
636 if (data
->cy
+ (n
- data
->oy
) >= screen_size_y(data
->backing
))
637 data
->cy
= screen_size_y(data
->backing
) - 1;
639 data
->cy
+= n
- data
->oy
;
643 if (data
->screen
.sel
== NULL
|| !data
->rectflag
) {
644 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
645 px
= window_copy_find_length(wme
, py
);
646 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
648 window_copy_cursor_end_of_line(wme
);
651 if (scroll_exit
&& data
->oy
== 0)
653 if (data
->searchmark
!= NULL
&& !data
->timeout
)
654 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
655 window_copy_update_selection(wme
, 1, 0);
656 window_copy_redraw_screen(wme
);
661 window_copy_previous_paragraph(struct window_mode_entry
*wme
)
663 struct window_copy_mode_data
*data
= wme
->data
;
666 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
668 while (oy
> 0 && window_copy_find_length(wme
, oy
) == 0)
671 while (oy
> 0 && window_copy_find_length(wme
, oy
) > 0)
674 window_copy_scroll_to(wme
, 0, oy
, 0);
678 window_copy_next_paragraph(struct window_mode_entry
*wme
)
680 struct window_copy_mode_data
*data
= wme
->data
;
681 struct screen
*s
= &data
->screen
;
684 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
685 maxy
= screen_hsize(data
->backing
) + screen_size_y(s
) - 1;
687 while (oy
< maxy
&& window_copy_find_length(wme
, oy
) == 0)
690 while (oy
< maxy
&& window_copy_find_length(wme
, oy
) > 0)
693 ox
= window_copy_find_length(wme
, oy
);
694 window_copy_scroll_to(wme
, ox
, oy
, 0);
698 window_copy_get_word(struct window_pane
*wp
, u_int x
, u_int y
)
700 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
701 struct window_copy_mode_data
*data
= wme
->data
;
702 struct grid
*gd
= data
->screen
.grid
;
704 return (format_grid_word(gd
, x
, gd
->hsize
+ y
));
708 window_copy_get_line(struct window_pane
*wp
, u_int y
)
710 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
711 struct window_copy_mode_data
*data
= wme
->data
;
712 struct grid
*gd
= data
->screen
.grid
;
714 return (format_grid_line(gd
, gd
->hsize
+ y
));
718 window_copy_cursor_word_cb(struct format_tree
*ft
)
720 struct window_pane
*wp
= format_get_pane(ft
);
721 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
722 struct window_copy_mode_data
*data
= wme
->data
;
724 return (window_copy_get_word(wp
, data
->cx
, data
->cy
));
728 window_copy_cursor_line_cb(struct format_tree
*ft
)
730 struct window_pane
*wp
= format_get_pane(ft
);
731 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
732 struct window_copy_mode_data
*data
= wme
->data
;
734 return (window_copy_get_line(wp
, data
->cy
));
738 window_copy_search_match_cb(struct format_tree
*ft
)
740 struct window_pane
*wp
= format_get_pane(ft
);
741 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
742 struct window_copy_mode_data
*data
= wme
->data
;
744 return (window_copy_match_at_cursor(data
));
748 window_copy_formats(struct window_mode_entry
*wme
, struct format_tree
*ft
)
750 struct window_copy_mode_data
*data
= wme
->data
;
752 format_add(ft
, "scroll_position", "%d", data
->oy
);
753 format_add(ft
, "rectangle_toggle", "%d", data
->rectflag
);
755 format_add(ft
, "copy_cursor_x", "%d", data
->cx
);
756 format_add(ft
, "copy_cursor_y", "%d", data
->cy
);
758 format_add(ft
, "selection_present", "%d", data
->screen
.sel
!= NULL
);
759 if (data
->screen
.sel
!= NULL
) {
760 format_add(ft
, "selection_start_x", "%d", data
->selx
);
761 format_add(ft
, "selection_start_y", "%d", data
->sely
);
762 format_add(ft
, "selection_end_x", "%d", data
->endselx
);
763 format_add(ft
, "selection_end_y", "%d", data
->endsely
);
764 format_add(ft
, "selection_active", "%d",
765 data
->cursordrag
!= CURSORDRAG_NONE
);
767 format_add(ft
, "selection_active", "%d", 0);
769 format_add(ft
, "search_present", "%d", data
->searchmark
!= NULL
);
770 format_add_cb(ft
, "search_match", window_copy_search_match_cb
);
772 format_add_cb(ft
, "copy_cursor_word", window_copy_cursor_word_cb
);
773 format_add_cb(ft
, "copy_cursor_line", window_copy_cursor_line_cb
);
777 window_copy_size_changed(struct window_mode_entry
*wme
)
779 struct window_copy_mode_data
*data
= wme
->data
;
780 struct screen
*s
= &data
->screen
;
781 struct screen_write_ctx ctx
;
782 int search
= (data
->searchmark
!= NULL
);
784 window_copy_clear_selection(wme
);
785 window_copy_clear_marks(wme
);
787 screen_write_start(&ctx
, s
);
788 window_copy_write_lines(wme
, &ctx
, 0, screen_size_y(s
));
789 screen_write_stop(&ctx
);
791 if (search
&& !data
->timeout
)
792 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 0);
793 data
->searchx
= data
->cx
;
794 data
->searchy
= data
->cy
;
795 data
->searcho
= data
->oy
;
799 window_copy_resize(struct window_mode_entry
*wme
, u_int sx
, u_int sy
)
801 struct window_copy_mode_data
*data
= wme
->data
;
802 struct screen
*s
= &data
->screen
;
803 struct grid
*gd
= data
->backing
->grid
;
804 u_int cx
, cy
, wx
, wy
;
807 screen_resize(s
, sx
, sy
, 0);
809 cy
= gd
->hsize
+ data
->cy
- data
->oy
;
810 reflow
= (gd
->sx
!= sx
);
812 grid_wrap_position(gd
, cx
, cy
, &wx
, &wy
);
813 screen_resize_cursor(data
->backing
, sx
, sy
, 1, 0, 0);
815 grid_unwrap_position(gd
, &cx
, &cy
, wx
, wy
);
818 if (cy
< gd
->hsize
) {
820 data
->oy
= gd
->hsize
- cy
;
822 data
->cy
= cy
- gd
->hsize
;
826 window_copy_size_changed(wme
);
827 window_copy_redraw_screen(wme
);
831 window_copy_key_table(struct window_mode_entry
*wme
)
833 struct window_pane
*wp
= wme
->wp
;
835 if (options_get_number(wp
->window
->options
, "mode-keys") == MODEKEY_VI
)
836 return ("copy-mode-vi");
837 return ("copy-mode");
841 window_copy_expand_search_string(struct window_copy_cmd_state
*cs
)
843 struct window_mode_entry
*wme
= cs
->wme
;
844 struct window_copy_mode_data
*data
= wme
->data
;
845 const char *ss
= args_string(cs
->args
, 1);
848 if (ss
== NULL
|| *ss
== '\0')
851 if (args_has(cs
->args
, 'F')) {
852 expanded
= format_single(NULL
, ss
, NULL
, NULL
, NULL
, wme
->wp
);
853 if (*expanded
== '\0') {
857 free(data
->searchstr
);
858 data
->searchstr
= expanded
;
860 free(data
->searchstr
);
861 data
->searchstr
= xstrdup(ss
);
866 static enum window_copy_cmd_action
867 window_copy_cmd_append_selection(struct window_copy_cmd_state
*cs
)
869 struct window_mode_entry
*wme
= cs
->wme
;
870 struct session
*s
= cs
->s
;
873 window_copy_append_selection(wme
);
874 window_copy_clear_selection(wme
);
875 return (WINDOW_COPY_CMD_REDRAW
);
878 static enum window_copy_cmd_action
879 window_copy_cmd_append_selection_and_cancel(struct window_copy_cmd_state
*cs
)
881 struct window_mode_entry
*wme
= cs
->wme
;
882 struct session
*s
= cs
->s
;
885 window_copy_append_selection(wme
);
886 window_copy_clear_selection(wme
);
887 return (WINDOW_COPY_CMD_CANCEL
);
890 static enum window_copy_cmd_action
891 window_copy_cmd_back_to_indentation(struct window_copy_cmd_state
*cs
)
893 struct window_mode_entry
*wme
= cs
->wme
;
895 window_copy_cursor_back_to_indentation(wme
);
896 return (WINDOW_COPY_CMD_NOTHING
);
899 static enum window_copy_cmd_action
900 window_copy_cmd_begin_selection(struct window_copy_cmd_state
*cs
)
902 struct window_mode_entry
*wme
= cs
->wme
;
903 struct client
*c
= cs
->c
;
904 struct mouse_event
*m
= cs
->m
;
905 struct window_copy_mode_data
*data
= wme
->data
;
908 window_copy_start_drag(c
, m
);
909 return (WINDOW_COPY_CMD_NOTHING
);
912 data
->lineflag
= LINE_SEL_NONE
;
913 data
->selflag
= SEL_CHAR
;
914 window_copy_start_selection(wme
);
915 return (WINDOW_COPY_CMD_REDRAW
);
918 static enum window_copy_cmd_action
919 window_copy_cmd_stop_selection(struct window_copy_cmd_state
*cs
)
921 struct window_mode_entry
*wme
= cs
->wme
;
922 struct window_copy_mode_data
*data
= wme
->data
;
924 data
->cursordrag
= CURSORDRAG_NONE
;
925 data
->lineflag
= LINE_SEL_NONE
;
926 data
->selflag
= SEL_CHAR
;
927 return (WINDOW_COPY_CMD_NOTHING
);
930 static enum window_copy_cmd_action
931 window_copy_cmd_bottom_line(struct window_copy_cmd_state
*cs
)
933 struct window_mode_entry
*wme
= cs
->wme
;
934 struct window_copy_mode_data
*data
= wme
->data
;
937 data
->cy
= screen_size_y(&data
->screen
) - 1;
939 window_copy_update_selection(wme
, 1, 0);
940 return (WINDOW_COPY_CMD_REDRAW
);
943 static enum window_copy_cmd_action
944 window_copy_cmd_cancel(__unused
struct window_copy_cmd_state
*cs
)
946 return (WINDOW_COPY_CMD_CANCEL
);
949 static enum window_copy_cmd_action
950 window_copy_cmd_clear_selection(struct window_copy_cmd_state
*cs
)
952 struct window_mode_entry
*wme
= cs
->wme
;
954 window_copy_clear_selection(wme
);
955 return (WINDOW_COPY_CMD_REDRAW
);
958 static enum window_copy_cmd_action
959 window_copy_do_copy_end_of_line(struct window_copy_cmd_state
*cs
, int pipe
,
962 struct window_mode_entry
*wme
= cs
->wme
;
963 struct client
*c
= cs
->c
;
964 struct session
*s
= cs
->s
;
965 struct winlink
*wl
= cs
->wl
;
966 struct window_pane
*wp
= wme
->wp
;
967 u_int count
= args_count(cs
->args
);
968 u_int np
= wme
->prefix
, ocx
, ocy
, ooy
;
969 struct window_copy_mode_data
*data
= wme
->data
;
970 char *prefix
= NULL
, *command
= NULL
;
971 const char *arg1
= args_string(cs
->args
, 1);
972 const char *arg2
= args_string(cs
->args
, 2);
976 prefix
= format_single(NULL
, arg2
, c
, s
, wl
, wp
);
977 if (s
!= NULL
&& count
> 1 && *arg1
!= '\0')
978 command
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
981 prefix
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
988 window_copy_start_selection(wme
);
990 window_copy_cursor_down(wme
, 0);
991 window_copy_cursor_end_of_line(wme
);
995 window_copy_copy_pipe(wme
, s
, prefix
, command
);
997 window_copy_copy_selection(wme
, prefix
);
1002 return (WINDOW_COPY_CMD_CANCEL
);
1005 window_copy_clear_selection(wme
);
1013 return (WINDOW_COPY_CMD_REDRAW
);
1016 static enum window_copy_cmd_action
1017 window_copy_cmd_copy_end_of_line(struct window_copy_cmd_state
*cs
)
1019 return (window_copy_do_copy_end_of_line(cs
, 0, 0));
1022 static enum window_copy_cmd_action
1023 window_copy_cmd_copy_end_of_line_and_cancel(struct window_copy_cmd_state
*cs
)
1025 return (window_copy_do_copy_end_of_line(cs
, 0, 1));
1028 static enum window_copy_cmd_action
1029 window_copy_cmd_copy_pipe_end_of_line(struct window_copy_cmd_state
*cs
)
1031 return (window_copy_do_copy_end_of_line(cs
, 1, 0));
1034 static enum window_copy_cmd_action
1035 window_copy_cmd_copy_pipe_end_of_line_and_cancel(
1036 struct window_copy_cmd_state
*cs
)
1038 return (window_copy_do_copy_end_of_line(cs
, 1, 1));
1041 static enum window_copy_cmd_action
1042 window_copy_do_copy_line(struct window_copy_cmd_state
*cs
, int pipe
, int cancel
)
1044 struct window_mode_entry
*wme
= cs
->wme
;
1045 struct client
*c
= cs
->c
;
1046 struct session
*s
= cs
->s
;
1047 struct winlink
*wl
= cs
->wl
;
1048 struct window_pane
*wp
= wme
->wp
;
1049 struct window_copy_mode_data
*data
= wme
->data
;
1050 u_int count
= args_count(cs
->args
);
1051 u_int np
= wme
->prefix
, ocx
, ocy
, ooy
;
1052 char *prefix
= NULL
, *command
= NULL
;
1053 const char *arg1
= args_string(cs
->args
, 1);
1054 const char *arg2
= args_string(cs
->args
, 2);
1058 prefix
= format_single(NULL
, arg2
, c
, s
, wl
, wp
);
1059 if (s
!= NULL
&& count
> 1 && *arg1
!= '\0')
1060 command
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1063 prefix
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1070 data
->selflag
= SEL_CHAR
;
1071 window_copy_cursor_start_of_line(wme
);
1072 window_copy_start_selection(wme
);
1073 for (; np
> 1; np
--)
1074 window_copy_cursor_down(wme
, 0);
1075 window_copy_cursor_end_of_line(wme
);
1079 window_copy_copy_pipe(wme
, s
, prefix
, command
);
1081 window_copy_copy_selection(wme
, prefix
);
1086 return (WINDOW_COPY_CMD_CANCEL
);
1089 window_copy_clear_selection(wme
);
1097 return (WINDOW_COPY_CMD_REDRAW
);
1100 static enum window_copy_cmd_action
1101 window_copy_cmd_copy_line(struct window_copy_cmd_state
*cs
)
1103 return (window_copy_do_copy_line(cs
, 0, 0));
1106 static enum window_copy_cmd_action
1107 window_copy_cmd_copy_line_and_cancel(struct window_copy_cmd_state
*cs
)
1109 return (window_copy_do_copy_line(cs
, 0, 1));
1112 static enum window_copy_cmd_action
1113 window_copy_cmd_copy_pipe_line(struct window_copy_cmd_state
*cs
)
1115 return (window_copy_do_copy_line(cs
, 1, 0));
1118 static enum window_copy_cmd_action
1119 window_copy_cmd_copy_pipe_line_and_cancel(struct window_copy_cmd_state
*cs
)
1121 return (window_copy_do_copy_line(cs
, 1, 1));
1124 static enum window_copy_cmd_action
1125 window_copy_cmd_copy_selection_no_clear(struct window_copy_cmd_state
*cs
)
1127 struct window_mode_entry
*wme
= cs
->wme
;
1128 struct client
*c
= cs
->c
;
1129 struct session
*s
= cs
->s
;
1130 struct winlink
*wl
= cs
->wl
;
1131 struct window_pane
*wp
= wme
->wp
;
1132 char *prefix
= NULL
;
1133 const char *arg1
= args_string(cs
->args
, 1);
1136 prefix
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1139 window_copy_copy_selection(wme
, prefix
);
1142 return (WINDOW_COPY_CMD_NOTHING
);
1145 static enum window_copy_cmd_action
1146 window_copy_cmd_copy_selection(struct window_copy_cmd_state
*cs
)
1148 struct window_mode_entry
*wme
= cs
->wme
;
1150 window_copy_cmd_copy_selection_no_clear(cs
);
1151 window_copy_clear_selection(wme
);
1152 return (WINDOW_COPY_CMD_REDRAW
);
1155 static enum window_copy_cmd_action
1156 window_copy_cmd_copy_selection_and_cancel(struct window_copy_cmd_state
*cs
)
1158 struct window_mode_entry
*wme
= cs
->wme
;
1160 window_copy_cmd_copy_selection_no_clear(cs
);
1161 window_copy_clear_selection(wme
);
1162 return (WINDOW_COPY_CMD_CANCEL
);
1165 static enum window_copy_cmd_action
1166 window_copy_cmd_cursor_down(struct window_copy_cmd_state
*cs
)
1168 struct window_mode_entry
*wme
= cs
->wme
;
1169 u_int np
= wme
->prefix
;
1171 for (; np
!= 0; np
--)
1172 window_copy_cursor_down(wme
, 0);
1173 return (WINDOW_COPY_CMD_NOTHING
);
1176 static enum window_copy_cmd_action
1177 window_copy_cmd_cursor_down_and_cancel(struct window_copy_cmd_state
*cs
)
1179 struct window_mode_entry
*wme
= cs
->wme
;
1180 struct window_copy_mode_data
*data
= wme
->data
;
1181 u_int np
= wme
->prefix
, cy
;
1184 for (; np
!= 0; np
--)
1185 window_copy_cursor_down(wme
, 0);
1186 if (cy
== data
->cy
&& data
->oy
== 0)
1187 return (WINDOW_COPY_CMD_CANCEL
);
1188 return (WINDOW_COPY_CMD_NOTHING
);
1191 static enum window_copy_cmd_action
1192 window_copy_cmd_cursor_left(struct window_copy_cmd_state
*cs
)
1194 struct window_mode_entry
*wme
= cs
->wme
;
1195 u_int np
= wme
->prefix
;
1197 for (; np
!= 0; np
--)
1198 window_copy_cursor_left(wme
);
1199 return (WINDOW_COPY_CMD_NOTHING
);
1202 static enum window_copy_cmd_action
1203 window_copy_cmd_cursor_right(struct window_copy_cmd_state
*cs
)
1205 struct window_mode_entry
*wme
= cs
->wme
;
1206 struct window_copy_mode_data
*data
= wme
->data
;
1207 u_int np
= wme
->prefix
;
1209 for (; np
!= 0; np
--) {
1210 window_copy_cursor_right(wme
, data
->screen
.sel
!= NULL
&&
1213 return (WINDOW_COPY_CMD_NOTHING
);
1216 static enum window_copy_cmd_action
1217 window_copy_cmd_cursor_up(struct window_copy_cmd_state
*cs
)
1219 struct window_mode_entry
*wme
= cs
->wme
;
1220 u_int np
= wme
->prefix
;
1222 for (; np
!= 0; np
--)
1223 window_copy_cursor_up(wme
, 0);
1224 return (WINDOW_COPY_CMD_NOTHING
);
1227 static enum window_copy_cmd_action
1228 window_copy_cmd_end_of_line(struct window_copy_cmd_state
*cs
)
1230 struct window_mode_entry
*wme
= cs
->wme
;
1232 window_copy_cursor_end_of_line(wme
);
1233 return (WINDOW_COPY_CMD_NOTHING
);
1236 static enum window_copy_cmd_action
1237 window_copy_cmd_halfpage_down(struct window_copy_cmd_state
*cs
)
1239 struct window_mode_entry
*wme
= cs
->wme
;
1240 struct window_copy_mode_data
*data
= wme
->data
;
1241 u_int np
= wme
->prefix
;
1243 for (; np
!= 0; np
--) {
1244 if (window_copy_pagedown(wme
, 1, data
->scroll_exit
))
1245 return (WINDOW_COPY_CMD_CANCEL
);
1247 return (WINDOW_COPY_CMD_NOTHING
);
1250 static enum window_copy_cmd_action
1251 window_copy_cmd_halfpage_down_and_cancel(struct window_copy_cmd_state
*cs
)
1254 struct window_mode_entry
*wme
= cs
->wme
;
1255 u_int np
= wme
->prefix
;
1257 for (; np
!= 0; np
--) {
1258 if (window_copy_pagedown(wme
, 1, 1))
1259 return (WINDOW_COPY_CMD_CANCEL
);
1261 return (WINDOW_COPY_CMD_NOTHING
);
1264 static enum window_copy_cmd_action
1265 window_copy_cmd_halfpage_up(struct window_copy_cmd_state
*cs
)
1267 struct window_mode_entry
*wme
= cs
->wme
;
1268 u_int np
= wme
->prefix
;
1270 for (; np
!= 0; np
--)
1271 window_copy_pageup1(wme
, 1);
1272 return (WINDOW_COPY_CMD_NOTHING
);
1275 static enum window_copy_cmd_action
1276 window_copy_cmd_history_bottom(struct window_copy_cmd_state
*cs
)
1278 struct window_mode_entry
*wme
= cs
->wme
;
1279 struct window_copy_mode_data
*data
= wme
->data
;
1280 struct screen
*s
= data
->backing
;
1283 oy
= screen_hsize(s
) + data
->cy
- data
->oy
;
1284 if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
&& oy
== data
->endsely
)
1285 window_copy_other_end(wme
);
1287 data
->cy
= screen_size_y(&data
->screen
) - 1;
1288 data
->cx
= window_copy_find_length(wme
, screen_hsize(s
) + data
->cy
);
1291 if (data
->searchmark
!= NULL
&& !data
->timeout
)
1292 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
1293 window_copy_update_selection(wme
, 1, 0);
1294 return (WINDOW_COPY_CMD_REDRAW
);
1297 static enum window_copy_cmd_action
1298 window_copy_cmd_history_top(struct window_copy_cmd_state
*cs
)
1300 struct window_mode_entry
*wme
= cs
->wme
;
1301 struct window_copy_mode_data
*data
= wme
->data
;
1304 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1305 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
&& oy
== data
->sely
)
1306 window_copy_other_end(wme
);
1310 data
->oy
= screen_hsize(data
->backing
);
1312 if (data
->searchmark
!= NULL
&& !data
->timeout
)
1313 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
1314 window_copy_update_selection(wme
, 1, 0);
1315 return (WINDOW_COPY_CMD_REDRAW
);
1318 static enum window_copy_cmd_action
1319 window_copy_cmd_jump_again(struct window_copy_cmd_state
*cs
)
1321 struct window_mode_entry
*wme
= cs
->wme
;
1322 struct window_copy_mode_data
*data
= wme
->data
;
1323 u_int np
= wme
->prefix
;
1325 switch (data
->jumptype
) {
1326 case WINDOW_COPY_JUMPFORWARD
:
1327 for (; np
!= 0; np
--)
1328 window_copy_cursor_jump(wme
);
1330 case WINDOW_COPY_JUMPBACKWARD
:
1331 for (; np
!= 0; np
--)
1332 window_copy_cursor_jump_back(wme
);
1334 case WINDOW_COPY_JUMPTOFORWARD
:
1335 for (; np
!= 0; np
--)
1336 window_copy_cursor_jump_to(wme
);
1338 case WINDOW_COPY_JUMPTOBACKWARD
:
1339 for (; np
!= 0; np
--)
1340 window_copy_cursor_jump_to_back(wme
);
1343 return (WINDOW_COPY_CMD_NOTHING
);
1346 static enum window_copy_cmd_action
1347 window_copy_cmd_jump_reverse(struct window_copy_cmd_state
*cs
)
1349 struct window_mode_entry
*wme
= cs
->wme
;
1350 struct window_copy_mode_data
*data
= wme
->data
;
1351 u_int np
= wme
->prefix
;
1353 switch (data
->jumptype
) {
1354 case WINDOW_COPY_JUMPFORWARD
:
1355 for (; np
!= 0; np
--)
1356 window_copy_cursor_jump_back(wme
);
1358 case WINDOW_COPY_JUMPBACKWARD
:
1359 for (; np
!= 0; np
--)
1360 window_copy_cursor_jump(wme
);
1362 case WINDOW_COPY_JUMPTOFORWARD
:
1363 for (; np
!= 0; np
--)
1364 window_copy_cursor_jump_to_back(wme
);
1366 case WINDOW_COPY_JUMPTOBACKWARD
:
1367 for (; np
!= 0; np
--)
1368 window_copy_cursor_jump_to(wme
);
1371 return (WINDOW_COPY_CMD_NOTHING
);
1374 static enum window_copy_cmd_action
1375 window_copy_cmd_middle_line(struct window_copy_cmd_state
*cs
)
1377 struct window_mode_entry
*wme
= cs
->wme
;
1378 struct window_copy_mode_data
*data
= wme
->data
;
1381 data
->cy
= (screen_size_y(&data
->screen
) - 1) / 2;
1383 window_copy_update_selection(wme
, 1, 0);
1384 return (WINDOW_COPY_CMD_REDRAW
);
1387 static enum window_copy_cmd_action
1388 window_copy_cmd_previous_matching_bracket(struct window_copy_cmd_state
*cs
)
1390 struct window_mode_entry
*wme
= cs
->wme
;
1391 u_int np
= wme
->prefix
;
1392 struct window_copy_mode_data
*data
= wme
->data
;
1393 struct screen
*s
= data
->backing
;
1394 char open
[] = "{[(", close
[] = "}])";
1395 char tried
, found
, start
, *cp
;
1396 u_int px
, py
, xx
, n
;
1397 struct grid_cell gc
;
1400 for (; np
!= 0; np
--) {
1401 /* Get cursor position and line length. */
1403 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1404 xx
= window_copy_find_length(wme
, py
);
1409 * Get the current character. If not on a bracket, try the
1410 * previous. If still not, then behave like previous-word.
1414 grid_get_cell(s
->grid
, px
, py
, &gc
);
1415 if (gc
.data
.size
!= 1 || (gc
.flags
& GRID_FLAG_PADDING
))
1418 found
= *gc
.data
.data
;
1419 cp
= strchr(close
, found
);
1422 if (data
->modekeys
== MODEKEY_EMACS
) {
1423 if (!tried
&& px
> 0) {
1428 window_copy_cursor_previous_word(wme
, close
, 1);
1432 start
= open
[cp
- close
];
1434 /* Walk backward until the matching bracket is reached. */
1445 xx
= window_copy_find_length(wme
, py
);
1446 } while (xx
== 0 && py
> 0);
1447 if (xx
== 0 && py
== 0) {
1455 grid_get_cell(s
->grid
, px
, py
, &gc
);
1456 if (gc
.data
.size
== 1 &&
1457 (~gc
.flags
& GRID_FLAG_PADDING
)) {
1458 if (*gc
.data
.data
== found
)
1460 else if (*gc
.data
.data
== start
)
1465 /* Move the cursor to the found location if any. */
1467 window_copy_scroll_to(wme
, px
, py
, 0);
1470 return (WINDOW_COPY_CMD_NOTHING
);
1473 static enum window_copy_cmd_action
1474 window_copy_cmd_next_matching_bracket(struct window_copy_cmd_state
*cs
)
1476 struct window_mode_entry
*wme
= cs
->wme
;
1477 u_int np
= wme
->prefix
;
1478 struct window_copy_mode_data
*data
= wme
->data
;
1479 struct screen
*s
= data
->backing
;
1480 char open
[] = "{[(", close
[] = "}])";
1481 char tried
, found
, end
, *cp
;
1482 u_int px
, py
, xx
, yy
, sx
, sy
, n
;
1483 struct grid_cell gc
;
1485 struct grid_line
*gl
;
1487 for (; np
!= 0; np
--) {
1488 /* Get cursor position and line length. */
1490 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1491 xx
= window_copy_find_length(wme
, py
);
1492 yy
= screen_hsize(s
) + screen_size_y(s
) - 1;
1497 * Get the current character. If not on a bracket, try the
1498 * next. If still not, then behave like next-word.
1502 grid_get_cell(s
->grid
, px
, py
, &gc
);
1503 if (gc
.data
.size
!= 1 || (gc
.flags
& GRID_FLAG_PADDING
))
1506 found
= *gc
.data
.data
;
1509 * In vi mode, attempt to move to previous bracket if a
1510 * closing bracket is found first. If this fails,
1511 * return to the original cursor position.
1513 cp
= strchr(close
, found
);
1514 if (cp
!= NULL
&& data
->modekeys
== MODEKEY_VI
) {
1516 sy
= screen_hsize(s
) + data
->cy
- data
->oy
;
1518 window_copy_scroll_to(wme
, px
, py
, 0);
1519 window_copy_cmd_previous_matching_bracket(cs
);
1522 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1523 grid_get_cell(s
->grid
, px
, py
, &gc
);
1524 if (gc
.data
.size
== 1 &&
1525 (~gc
.flags
& GRID_FLAG_PADDING
) &&
1526 strchr(close
, *gc
.data
.data
) != NULL
)
1527 window_copy_scroll_to(wme
, sx
, sy
, 0);
1531 cp
= strchr(open
, found
);
1534 if (data
->modekeys
== MODEKEY_EMACS
) {
1535 if (!tried
&& px
<= xx
) {
1540 window_copy_cursor_next_word_end(wme
, open
, 0);
1543 /* For vi, continue searching for bracket until EOL. */
1547 gl
= grid_get_line(s
->grid
, py
);
1548 if (~gl
->flags
& GRID_LINE_WRAPPED
)
1550 if (gl
->cellsize
> s
->grid
->sx
)
1554 xx
= window_copy_find_length(wme
, py
);
1559 end
= close
[cp
- open
];
1561 /* Walk forward until the matching bracket is reached. */
1572 xx
= window_copy_find_length(wme
, py
);
1576 grid_get_cell(s
->grid
, px
, py
, &gc
);
1577 if (gc
.data
.size
== 1 &&
1578 (~gc
.flags
& GRID_FLAG_PADDING
)) {
1579 if (*gc
.data
.data
== found
)
1581 else if (*gc
.data
.data
== end
)
1586 /* Move the cursor to the found location if any. */
1588 window_copy_scroll_to(wme
, px
, py
, 0);
1591 return (WINDOW_COPY_CMD_NOTHING
);
1594 static enum window_copy_cmd_action
1595 window_copy_cmd_next_paragraph(struct window_copy_cmd_state
*cs
)
1597 struct window_mode_entry
*wme
= cs
->wme
;
1598 u_int np
= wme
->prefix
;
1600 for (; np
!= 0; np
--)
1601 window_copy_next_paragraph(wme
);
1602 return (WINDOW_COPY_CMD_NOTHING
);
1605 static enum window_copy_cmd_action
1606 window_copy_cmd_next_space(struct window_copy_cmd_state
*cs
)
1608 struct window_mode_entry
*wme
= cs
->wme
;
1609 u_int np
= wme
->prefix
;
1611 for (; np
!= 0; np
--)
1612 window_copy_cursor_next_word(wme
, "");
1613 return (WINDOW_COPY_CMD_NOTHING
);
1616 static enum window_copy_cmd_action
1617 window_copy_cmd_next_space_end(struct window_copy_cmd_state
*cs
)
1619 struct window_mode_entry
*wme
= cs
->wme
;
1620 u_int np
= wme
->prefix
;
1622 for (; np
!= 0; np
--)
1623 window_copy_cursor_next_word_end(wme
, "", 0);
1624 return (WINDOW_COPY_CMD_NOTHING
);
1627 static enum window_copy_cmd_action
1628 window_copy_cmd_next_word(struct window_copy_cmd_state
*cs
)
1630 struct window_mode_entry
*wme
= cs
->wme
;
1631 u_int np
= wme
->prefix
;
1632 const char *separators
;
1634 separators
= options_get_string(cs
->s
->options
, "word-separators");
1636 for (; np
!= 0; np
--)
1637 window_copy_cursor_next_word(wme
, separators
);
1638 return (WINDOW_COPY_CMD_NOTHING
);
1641 static enum window_copy_cmd_action
1642 window_copy_cmd_next_word_end(struct window_copy_cmd_state
*cs
)
1644 struct window_mode_entry
*wme
= cs
->wme
;
1645 u_int np
= wme
->prefix
;
1646 const char *separators
;
1648 separators
= options_get_string(cs
->s
->options
, "word-separators");
1650 for (; np
!= 0; np
--)
1651 window_copy_cursor_next_word_end(wme
, separators
, 0);
1652 return (WINDOW_COPY_CMD_NOTHING
);
1655 static enum window_copy_cmd_action
1656 window_copy_cmd_other_end(struct window_copy_cmd_state
*cs
)
1658 struct window_mode_entry
*wme
= cs
->wme
;
1659 u_int np
= wme
->prefix
;
1660 struct window_copy_mode_data
*data
= wme
->data
;
1662 data
->selflag
= SEL_CHAR
;
1664 window_copy_other_end(wme
);
1665 return (WINDOW_COPY_CMD_NOTHING
);
1668 static enum window_copy_cmd_action
1669 window_copy_cmd_page_down(struct window_copy_cmd_state
*cs
)
1671 struct window_mode_entry
*wme
= cs
->wme
;
1672 struct window_copy_mode_data
*data
= wme
->data
;
1673 u_int np
= wme
->prefix
;
1675 for (; np
!= 0; np
--) {
1676 if (window_copy_pagedown(wme
, 0, data
->scroll_exit
))
1677 return (WINDOW_COPY_CMD_CANCEL
);
1679 return (WINDOW_COPY_CMD_NOTHING
);
1682 static enum window_copy_cmd_action
1683 window_copy_cmd_page_down_and_cancel(struct window_copy_cmd_state
*cs
)
1685 struct window_mode_entry
*wme
= cs
->wme
;
1686 u_int np
= wme
->prefix
;
1688 for (; np
!= 0; np
--) {
1689 if (window_copy_pagedown(wme
, 0, 1))
1690 return (WINDOW_COPY_CMD_CANCEL
);
1692 return (WINDOW_COPY_CMD_NOTHING
);
1695 static enum window_copy_cmd_action
1696 window_copy_cmd_page_up(struct window_copy_cmd_state
*cs
)
1698 struct window_mode_entry
*wme
= cs
->wme
;
1699 u_int np
= wme
->prefix
;
1701 for (; np
!= 0; np
--)
1702 window_copy_pageup1(wme
, 0);
1703 return (WINDOW_COPY_CMD_NOTHING
);
1706 static enum window_copy_cmd_action
1707 window_copy_cmd_previous_paragraph(struct window_copy_cmd_state
*cs
)
1709 struct window_mode_entry
*wme
= cs
->wme
;
1710 u_int np
= wme
->prefix
;
1712 for (; np
!= 0; np
--)
1713 window_copy_previous_paragraph(wme
);
1714 return (WINDOW_COPY_CMD_NOTHING
);
1717 static enum window_copy_cmd_action
1718 window_copy_cmd_previous_space(struct window_copy_cmd_state
*cs
)
1720 struct window_mode_entry
*wme
= cs
->wme
;
1721 u_int np
= wme
->prefix
;
1723 for (; np
!= 0; np
--)
1724 window_copy_cursor_previous_word(wme
, "", 1);
1725 return (WINDOW_COPY_CMD_NOTHING
);
1728 static enum window_copy_cmd_action
1729 window_copy_cmd_previous_word(struct window_copy_cmd_state
*cs
)
1731 struct window_mode_entry
*wme
= cs
->wme
;
1732 u_int np
= wme
->prefix
;
1733 const char *separators
;
1735 separators
= options_get_string(cs
->s
->options
, "word-separators");
1737 for (; np
!= 0; np
--)
1738 window_copy_cursor_previous_word(wme
, separators
, 1);
1739 return (WINDOW_COPY_CMD_NOTHING
);
1742 static enum window_copy_cmd_action
1743 window_copy_cmd_rectangle_on(struct window_copy_cmd_state
*cs
)
1745 struct window_mode_entry
*wme
= cs
->wme
;
1746 struct window_copy_mode_data
*data
= wme
->data
;
1748 data
->lineflag
= LINE_SEL_NONE
;
1749 window_copy_rectangle_set(wme
, 1);
1751 return (WINDOW_COPY_CMD_NOTHING
);
1754 static enum window_copy_cmd_action
1755 window_copy_cmd_rectangle_off(struct window_copy_cmd_state
*cs
)
1757 struct window_mode_entry
*wme
= cs
->wme
;
1758 struct window_copy_mode_data
*data
= wme
->data
;
1760 data
->lineflag
= LINE_SEL_NONE
;
1761 window_copy_rectangle_set(wme
, 0);
1763 return (WINDOW_COPY_CMD_NOTHING
);
1766 static enum window_copy_cmd_action
1767 window_copy_cmd_rectangle_toggle(struct window_copy_cmd_state
*cs
)
1769 struct window_mode_entry
*wme
= cs
->wme
;
1770 struct window_copy_mode_data
*data
= wme
->data
;
1772 data
->lineflag
= LINE_SEL_NONE
;
1773 window_copy_rectangle_set(wme
, !data
->rectflag
);
1775 return (WINDOW_COPY_CMD_NOTHING
);
1778 static enum window_copy_cmd_action
1779 window_copy_cmd_scroll_down(struct window_copy_cmd_state
*cs
)
1781 struct window_mode_entry
*wme
= cs
->wme
;
1782 struct window_copy_mode_data
*data
= wme
->data
;
1783 u_int np
= wme
->prefix
;
1785 for (; np
!= 0; np
--)
1786 window_copy_cursor_down(wme
, 1);
1787 if (data
->scroll_exit
&& data
->oy
== 0)
1788 return (WINDOW_COPY_CMD_CANCEL
);
1789 return (WINDOW_COPY_CMD_NOTHING
);
1792 static enum window_copy_cmd_action
1793 window_copy_cmd_scroll_down_and_cancel(struct window_copy_cmd_state
*cs
)
1795 struct window_mode_entry
*wme
= cs
->wme
;
1796 struct window_copy_mode_data
*data
= wme
->data
;
1797 u_int np
= wme
->prefix
;
1799 for (; np
!= 0; np
--)
1800 window_copy_cursor_down(wme
, 1);
1802 return (WINDOW_COPY_CMD_CANCEL
);
1803 return (WINDOW_COPY_CMD_NOTHING
);
1806 static enum window_copy_cmd_action
1807 window_copy_cmd_scroll_up(struct window_copy_cmd_state
*cs
)
1809 struct window_mode_entry
*wme
= cs
->wme
;
1810 u_int np
= wme
->prefix
;
1812 for (; np
!= 0; np
--)
1813 window_copy_cursor_up(wme
, 1);
1814 return (WINDOW_COPY_CMD_NOTHING
);
1817 static enum window_copy_cmd_action
1818 window_copy_cmd_search_again(struct window_copy_cmd_state
*cs
)
1820 struct window_mode_entry
*wme
= cs
->wme
;
1821 struct window_copy_mode_data
*data
= wme
->data
;
1822 u_int np
= wme
->prefix
;
1824 if (data
->searchtype
== WINDOW_COPY_SEARCHUP
) {
1825 for (; np
!= 0; np
--)
1826 window_copy_search_up(wme
, data
->searchregex
);
1827 } else if (data
->searchtype
== WINDOW_COPY_SEARCHDOWN
) {
1828 for (; np
!= 0; np
--)
1829 window_copy_search_down(wme
, data
->searchregex
);
1831 return (WINDOW_COPY_CMD_NOTHING
);
1834 static enum window_copy_cmd_action
1835 window_copy_cmd_search_reverse(struct window_copy_cmd_state
*cs
)
1837 struct window_mode_entry
*wme
= cs
->wme
;
1838 struct window_copy_mode_data
*data
= wme
->data
;
1839 u_int np
= wme
->prefix
;
1841 if (data
->searchtype
== WINDOW_COPY_SEARCHUP
) {
1842 for (; np
!= 0; np
--)
1843 window_copy_search_down(wme
, data
->searchregex
);
1844 } else if (data
->searchtype
== WINDOW_COPY_SEARCHDOWN
) {
1845 for (; np
!= 0; np
--)
1846 window_copy_search_up(wme
, data
->searchregex
);
1848 return (WINDOW_COPY_CMD_NOTHING
);
1851 static enum window_copy_cmd_action
1852 window_copy_cmd_select_line(struct window_copy_cmd_state
*cs
)
1854 struct window_mode_entry
*wme
= cs
->wme
;
1855 struct window_copy_mode_data
*data
= wme
->data
;
1856 u_int np
= wme
->prefix
;
1858 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
1860 data
->selflag
= SEL_LINE
;
1861 data
->dx
= data
->cx
;
1862 data
->dy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1864 window_copy_cursor_start_of_line(wme
);
1865 data
->selrx
= data
->cx
;
1866 data
->selry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1867 data
->endselry
= data
->selry
;
1868 window_copy_start_selection(wme
);
1869 window_copy_cursor_end_of_line(wme
);
1870 data
->endselry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1871 data
->endselrx
= window_copy_find_length(wme
, data
->endselry
);
1872 for (; np
> 1; np
--) {
1873 window_copy_cursor_down(wme
, 0);
1874 window_copy_cursor_end_of_line(wme
);
1877 return (WINDOW_COPY_CMD_REDRAW
);
1880 static enum window_copy_cmd_action
1881 window_copy_cmd_select_word(struct window_copy_cmd_state
*cs
)
1883 struct window_mode_entry
*wme
= cs
->wme
;
1884 struct options
*session_options
= cs
->s
->options
;
1885 struct window_copy_mode_data
*data
= wme
->data
;
1886 u_int px
, py
, nextx
, nexty
;
1888 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
1890 data
->selflag
= SEL_WORD
;
1891 data
->dx
= data
->cx
;
1892 data
->dy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1894 data
->separators
= options_get_string(session_options
,
1896 window_copy_cursor_previous_word(wme
, data
->separators
, 0);
1898 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1901 window_copy_start_selection(wme
);
1903 /* Handle single character words. */
1906 if (grid_get_line(data
->backing
->grid
, nexty
)->flags
&
1907 GRID_LINE_WRAPPED
&& nextx
> screen_size_x(data
->backing
) - 1) {
1911 if (px
>= window_copy_find_length(wme
, py
) ||
1912 !window_copy_in_set(wme
, nextx
, nexty
, WHITESPACE
))
1913 window_copy_cursor_next_word_end(wme
, data
->separators
, 1);
1915 window_copy_update_cursor(wme
, px
, data
->cy
);
1916 if (window_copy_update_selection(wme
, 1, 1))
1917 window_copy_redraw_lines(wme
, data
->cy
, 1);
1919 data
->endselrx
= data
->cx
;
1920 data
->endselry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1921 if (data
->dy
> data
->endselry
) {
1922 data
->dy
= data
->endselry
;
1923 data
->dx
= data
->endselrx
;
1924 } else if (data
->dx
> data
->endselrx
)
1925 data
->dx
= data
->endselrx
;
1927 return (WINDOW_COPY_CMD_REDRAW
);
1930 static enum window_copy_cmd_action
1931 window_copy_cmd_set_mark(struct window_copy_cmd_state
*cs
)
1933 struct window_copy_mode_data
*data
= cs
->wme
->data
;
1935 data
->mx
= data
->cx
;
1936 data
->my
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1938 return (WINDOW_COPY_CMD_REDRAW
);
1941 static enum window_copy_cmd_action
1942 window_copy_cmd_start_of_line(struct window_copy_cmd_state
*cs
)
1944 struct window_mode_entry
*wme
= cs
->wme
;
1946 window_copy_cursor_start_of_line(wme
);
1947 return (WINDOW_COPY_CMD_NOTHING
);
1950 static enum window_copy_cmd_action
1951 window_copy_cmd_top_line(struct window_copy_cmd_state
*cs
)
1953 struct window_mode_entry
*wme
= cs
->wme
;
1954 struct window_copy_mode_data
*data
= wme
->data
;
1959 window_copy_update_selection(wme
, 1, 0);
1960 return (WINDOW_COPY_CMD_REDRAW
);
1963 static enum window_copy_cmd_action
1964 window_copy_cmd_copy_pipe_no_clear(struct window_copy_cmd_state
*cs
)
1966 struct window_mode_entry
*wme
= cs
->wme
;
1967 struct client
*c
= cs
->c
;
1968 struct session
*s
= cs
->s
;
1969 struct winlink
*wl
= cs
->wl
;
1970 struct window_pane
*wp
= wme
->wp
;
1971 char *command
= NULL
, *prefix
= NULL
;
1972 const char *arg1
= args_string(cs
->args
, 1);
1973 const char *arg2
= args_string(cs
->args
, 2);
1976 prefix
= format_single(NULL
, arg2
, c
, s
, wl
, wp
);
1978 if (s
!= NULL
&& arg1
!= NULL
&& *arg1
!= '\0')
1979 command
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1980 window_copy_copy_pipe(wme
, s
, prefix
, command
);
1984 return (WINDOW_COPY_CMD_NOTHING
);
1987 static enum window_copy_cmd_action
1988 window_copy_cmd_copy_pipe(struct window_copy_cmd_state
*cs
)
1990 struct window_mode_entry
*wme
= cs
->wme
;
1992 window_copy_cmd_copy_pipe_no_clear(cs
);
1993 window_copy_clear_selection(wme
);
1994 return (WINDOW_COPY_CMD_REDRAW
);
1997 static enum window_copy_cmd_action
1998 window_copy_cmd_copy_pipe_and_cancel(struct window_copy_cmd_state
*cs
)
2000 struct window_mode_entry
*wme
= cs
->wme
;
2002 window_copy_cmd_copy_pipe_no_clear(cs
);
2003 window_copy_clear_selection(wme
);
2004 return (WINDOW_COPY_CMD_CANCEL
);
2007 static enum window_copy_cmd_action
2008 window_copy_cmd_pipe_no_clear(struct window_copy_cmd_state
*cs
)
2010 struct window_mode_entry
*wme
= cs
->wme
;
2011 struct client
*c
= cs
->c
;
2012 struct session
*s
= cs
->s
;
2013 struct winlink
*wl
= cs
->wl
;
2014 struct window_pane
*wp
= wme
->wp
;
2015 char *command
= NULL
;
2016 const char *arg1
= args_string(cs
->args
, 1);
2018 if (s
!= NULL
&& arg1
!= NULL
&& *arg1
!= '\0')
2019 command
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
2020 window_copy_pipe(wme
, s
, command
);
2023 return (WINDOW_COPY_CMD_NOTHING
);
2026 static enum window_copy_cmd_action
2027 window_copy_cmd_pipe(struct window_copy_cmd_state
*cs
)
2029 struct window_mode_entry
*wme
= cs
->wme
;
2031 window_copy_cmd_pipe_no_clear(cs
);
2032 window_copy_clear_selection(wme
);
2033 return (WINDOW_COPY_CMD_REDRAW
);
2036 static enum window_copy_cmd_action
2037 window_copy_cmd_pipe_and_cancel(struct window_copy_cmd_state
*cs
)
2039 struct window_mode_entry
*wme
= cs
->wme
;
2041 window_copy_cmd_pipe_no_clear(cs
);
2042 window_copy_clear_selection(wme
);
2043 return (WINDOW_COPY_CMD_CANCEL
);
2046 static enum window_copy_cmd_action
2047 window_copy_cmd_goto_line(struct window_copy_cmd_state
*cs
)
2049 struct window_mode_entry
*wme
= cs
->wme
;
2050 const char *arg1
= args_string(cs
->args
, 1);
2053 window_copy_goto_line(wme
, arg1
);
2054 return (WINDOW_COPY_CMD_NOTHING
);
2057 static enum window_copy_cmd_action
2058 window_copy_cmd_jump_backward(struct window_copy_cmd_state
*cs
)
2060 struct window_mode_entry
*wme
= cs
->wme
;
2061 struct window_copy_mode_data
*data
= wme
->data
;
2062 u_int np
= wme
->prefix
;
2063 const char *arg1
= args_string(cs
->args
, 1);
2065 if (*arg1
!= '\0') {
2066 data
->jumptype
= WINDOW_COPY_JUMPBACKWARD
;
2067 free(data
->jumpchar
);
2068 data
->jumpchar
= utf8_fromcstr(arg1
);
2069 for (; np
!= 0; np
--)
2070 window_copy_cursor_jump_back(wme
);
2072 return (WINDOW_COPY_CMD_NOTHING
);
2075 static enum window_copy_cmd_action
2076 window_copy_cmd_jump_forward(struct window_copy_cmd_state
*cs
)
2078 struct window_mode_entry
*wme
= cs
->wme
;
2079 struct window_copy_mode_data
*data
= wme
->data
;
2080 u_int np
= wme
->prefix
;
2081 const char *arg1
= args_string(cs
->args
, 1);
2083 if (*arg1
!= '\0') {
2084 data
->jumptype
= WINDOW_COPY_JUMPFORWARD
;
2085 free(data
->jumpchar
);
2086 data
->jumpchar
= utf8_fromcstr(arg1
);
2087 for (; np
!= 0; np
--)
2088 window_copy_cursor_jump(wme
);
2090 return (WINDOW_COPY_CMD_NOTHING
);
2093 static enum window_copy_cmd_action
2094 window_copy_cmd_jump_to_backward(struct window_copy_cmd_state
*cs
)
2096 struct window_mode_entry
*wme
= cs
->wme
;
2097 struct window_copy_mode_data
*data
= wme
->data
;
2098 u_int np
= wme
->prefix
;
2099 const char *arg1
= args_string(cs
->args
, 1);
2101 if (*arg1
!= '\0') {
2102 data
->jumptype
= WINDOW_COPY_JUMPTOBACKWARD
;
2103 free(data
->jumpchar
);
2104 data
->jumpchar
= utf8_fromcstr(arg1
);
2105 for (; np
!= 0; np
--)
2106 window_copy_cursor_jump_to_back(wme
);
2108 return (WINDOW_COPY_CMD_NOTHING
);
2111 static enum window_copy_cmd_action
2112 window_copy_cmd_jump_to_forward(struct window_copy_cmd_state
*cs
)
2114 struct window_mode_entry
*wme
= cs
->wme
;
2115 struct window_copy_mode_data
*data
= wme
->data
;
2116 u_int np
= wme
->prefix
;
2117 const char *arg1
= args_string(cs
->args
, 1);
2119 if (*arg1
!= '\0') {
2120 data
->jumptype
= WINDOW_COPY_JUMPTOFORWARD
;
2121 free(data
->jumpchar
);
2122 data
->jumpchar
= utf8_fromcstr(arg1
);
2123 for (; np
!= 0; np
--)
2124 window_copy_cursor_jump_to(wme
);
2126 return (WINDOW_COPY_CMD_NOTHING
);
2129 static enum window_copy_cmd_action
2130 window_copy_cmd_jump_to_mark(struct window_copy_cmd_state
*cs
)
2132 struct window_mode_entry
*wme
= cs
->wme
;
2134 window_copy_jump_to_mark(wme
);
2135 return (WINDOW_COPY_CMD_NOTHING
);
2138 static enum window_copy_cmd_action
2139 window_copy_cmd_search_backward(struct window_copy_cmd_state
*cs
)
2141 struct window_mode_entry
*wme
= cs
->wme
;
2142 struct window_copy_mode_data
*data
= wme
->data
;
2143 u_int np
= wme
->prefix
;
2145 if (!window_copy_expand_search_string(cs
))
2146 return (WINDOW_COPY_CMD_NOTHING
);
2148 if (data
->searchstr
!= NULL
) {
2149 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2150 data
->searchregex
= 1;
2152 for (; np
!= 0; np
--)
2153 window_copy_search_up(wme
, 1);
2155 return (WINDOW_COPY_CMD_NOTHING
);
2158 static enum window_copy_cmd_action
2159 window_copy_cmd_search_backward_text(struct window_copy_cmd_state
*cs
)
2161 struct window_mode_entry
*wme
= cs
->wme
;
2162 struct window_copy_mode_data
*data
= wme
->data
;
2163 u_int np
= wme
->prefix
;
2165 if (!window_copy_expand_search_string(cs
))
2166 return (WINDOW_COPY_CMD_NOTHING
);
2168 if (data
->searchstr
!= NULL
) {
2169 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2170 data
->searchregex
= 0;
2172 for (; np
!= 0; np
--)
2173 window_copy_search_up(wme
, 0);
2175 return (WINDOW_COPY_CMD_NOTHING
);
2178 static enum window_copy_cmd_action
2179 window_copy_cmd_search_forward(struct window_copy_cmd_state
*cs
)
2181 struct window_mode_entry
*wme
= cs
->wme
;
2182 struct window_copy_mode_data
*data
= wme
->data
;
2183 u_int np
= wme
->prefix
;
2185 if (!window_copy_expand_search_string(cs
))
2186 return (WINDOW_COPY_CMD_NOTHING
);
2188 if (data
->searchstr
!= NULL
) {
2189 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2190 data
->searchregex
= 1;
2192 for (; np
!= 0; np
--)
2193 window_copy_search_down(wme
, 1);
2195 return (WINDOW_COPY_CMD_NOTHING
);
2198 static enum window_copy_cmd_action
2199 window_copy_cmd_search_forward_text(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
;
2205 if (!window_copy_expand_search_string(cs
))
2206 return (WINDOW_COPY_CMD_NOTHING
);
2208 if (data
->searchstr
!= NULL
) {
2209 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2210 data
->searchregex
= 0;
2212 for (; np
!= 0; np
--)
2213 window_copy_search_down(wme
, 0);
2215 return (WINDOW_COPY_CMD_NOTHING
);
2218 static enum window_copy_cmd_action
2219 window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state
*cs
)
2221 struct window_mode_entry
*wme
= cs
->wme
;
2222 struct window_copy_mode_data
*data
= wme
->data
;
2223 const char *arg1
= args_string(cs
->args
, 1);
2224 const char *ss
= data
->searchstr
;
2226 enum window_copy_cmd_action action
= WINDOW_COPY_CMD_NOTHING
;
2230 log_debug("%s: %s", __func__
, arg1
);
2233 if (data
->searchx
== -1 || data
->searchy
== -1) {
2234 data
->searchx
= data
->cx
;
2235 data
->searchy
= data
->cy
;
2236 data
->searcho
= data
->oy
;
2237 } else if (ss
!= NULL
&& strcmp(arg1
, ss
) != 0) {
2238 data
->cx
= data
->searchx
;
2239 data
->cy
= data
->searchy
;
2240 data
->oy
= data
->searcho
;
2241 action
= WINDOW_COPY_CMD_REDRAW
;
2243 if (*arg1
== '\0') {
2244 window_copy_clear_marks(wme
);
2245 return (WINDOW_COPY_CMD_REDRAW
);
2250 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2251 data
->searchregex
= 0;
2252 free(data
->searchstr
);
2253 data
->searchstr
= xstrdup(arg1
);
2254 if (!window_copy_search_up(wme
, 0)) {
2255 window_copy_clear_marks(wme
);
2256 return (WINDOW_COPY_CMD_REDRAW
);
2260 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2261 data
->searchregex
= 0;
2262 free(data
->searchstr
);
2263 data
->searchstr
= xstrdup(arg1
);
2264 if (!window_copy_search_down(wme
, 0)) {
2265 window_copy_clear_marks(wme
);
2266 return (WINDOW_COPY_CMD_REDRAW
);
2273 static enum window_copy_cmd_action
2274 window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state
*cs
)
2276 struct window_mode_entry
*wme
= cs
->wme
;
2277 struct window_copy_mode_data
*data
= wme
->data
;
2278 const char *arg1
= args_string(cs
->args
, 1);
2279 const char *ss
= data
->searchstr
;
2281 enum window_copy_cmd_action action
= WINDOW_COPY_CMD_NOTHING
;
2285 log_debug("%s: %s", __func__
, arg1
);
2288 if (data
->searchx
== -1 || data
->searchy
== -1) {
2289 data
->searchx
= data
->cx
;
2290 data
->searchy
= data
->cy
;
2291 data
->searcho
= data
->oy
;
2292 } else if (ss
!= NULL
&& strcmp(arg1
, ss
) != 0) {
2293 data
->cx
= data
->searchx
;
2294 data
->cy
= data
->searchy
;
2295 data
->oy
= data
->searcho
;
2296 action
= WINDOW_COPY_CMD_REDRAW
;
2298 if (*arg1
== '\0') {
2299 window_copy_clear_marks(wme
);
2300 return (WINDOW_COPY_CMD_REDRAW
);
2305 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2306 data
->searchregex
= 0;
2307 free(data
->searchstr
);
2308 data
->searchstr
= xstrdup(arg1
);
2309 if (!window_copy_search_down(wme
, 0)) {
2310 window_copy_clear_marks(wme
);
2311 return (WINDOW_COPY_CMD_REDRAW
);
2315 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2316 data
->searchregex
= 0;
2317 free(data
->searchstr
);
2318 data
->searchstr
= xstrdup(arg1
);
2319 if (!window_copy_search_up(wme
, 0)) {
2320 window_copy_clear_marks(wme
);
2321 return (WINDOW_COPY_CMD_REDRAW
);
2327 static enum window_copy_cmd_action
2328 window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state
*cs
)
2330 struct window_mode_entry
*wme
= cs
->wme
;
2331 struct window_pane
*wp
= wme
->swp
;
2332 struct window_copy_mode_data
*data
= wme
->data
;
2335 return (WINDOW_COPY_CMD_NOTHING
);
2337 screen_free(data
->backing
);
2338 free(data
->backing
);
2339 data
->backing
= window_copy_clone_screen(&wp
->base
, &data
->screen
, NULL
, NULL
, wme
->swp
!= wme
->wp
);
2341 window_copy_size_changed(wme
);
2342 return (WINDOW_COPY_CMD_REDRAW
);
2345 static const struct {
2346 const char *command
;
2349 enum window_copy_cmd_clear clear
;
2350 enum window_copy_cmd_action (*f
)(struct window_copy_cmd_state
*);
2351 } window_copy_cmd_table
[] = {
2352 { .command
= "append-selection",
2355 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2356 .f
= window_copy_cmd_append_selection
2358 { .command
= "append-selection-and-cancel",
2361 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2362 .f
= window_copy_cmd_append_selection_and_cancel
2364 { .command
= "back-to-indentation",
2367 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2368 .f
= window_copy_cmd_back_to_indentation
2370 { .command
= "begin-selection",
2373 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2374 .f
= window_copy_cmd_begin_selection
2376 { .command
= "bottom-line",
2379 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2380 .f
= window_copy_cmd_bottom_line
2382 { .command
= "cancel",
2385 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2386 .f
= window_copy_cmd_cancel
2388 { .command
= "clear-selection",
2391 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2392 .f
= window_copy_cmd_clear_selection
2394 { .command
= "copy-end-of-line",
2397 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2398 .f
= window_copy_cmd_copy_end_of_line
2400 { .command
= "copy-end-of-line-and-cancel",
2403 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2404 .f
= window_copy_cmd_copy_end_of_line_and_cancel
2406 { .command
= "copy-pipe-end-of-line",
2409 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2410 .f
= window_copy_cmd_copy_pipe_end_of_line
2412 { .command
= "copy-pipe-end-of-line-and-cancel",
2415 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2416 .f
= window_copy_cmd_copy_pipe_end_of_line_and_cancel
2418 { .command
= "copy-line",
2421 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2422 .f
= window_copy_cmd_copy_line
2424 { .command
= "copy-line-and-cancel",
2427 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2428 .f
= window_copy_cmd_copy_line_and_cancel
2430 { .command
= "copy-pipe-line",
2433 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2434 .f
= window_copy_cmd_copy_pipe_line
2436 { .command
= "copy-pipe-line-and-cancel",
2439 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2440 .f
= window_copy_cmd_copy_pipe_line_and_cancel
2442 { .command
= "copy-pipe-no-clear",
2445 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2446 .f
= window_copy_cmd_copy_pipe_no_clear
2448 { .command
= "copy-pipe",
2451 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2452 .f
= window_copy_cmd_copy_pipe
2454 { .command
= "copy-pipe-and-cancel",
2457 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2458 .f
= window_copy_cmd_copy_pipe_and_cancel
2460 { .command
= "copy-selection-no-clear",
2463 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2464 .f
= window_copy_cmd_copy_selection_no_clear
2466 { .command
= "copy-selection",
2469 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2470 .f
= window_copy_cmd_copy_selection
2472 { .command
= "copy-selection-and-cancel",
2475 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2476 .f
= window_copy_cmd_copy_selection_and_cancel
2478 { .command
= "cursor-down",
2481 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2482 .f
= window_copy_cmd_cursor_down
2484 { .command
= "cursor-down-and-cancel",
2487 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2488 .f
= window_copy_cmd_cursor_down_and_cancel
2490 { .command
= "cursor-left",
2493 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2494 .f
= window_copy_cmd_cursor_left
2496 { .command
= "cursor-right",
2499 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2500 .f
= window_copy_cmd_cursor_right
2502 { .command
= "cursor-up",
2505 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2506 .f
= window_copy_cmd_cursor_up
2508 { .command
= "end-of-line",
2511 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2512 .f
= window_copy_cmd_end_of_line
2514 { .command
= "goto-line",
2517 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2518 .f
= window_copy_cmd_goto_line
2520 { .command
= "halfpage-down",
2523 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2524 .f
= window_copy_cmd_halfpage_down
2526 { .command
= "halfpage-down-and-cancel",
2529 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2530 .f
= window_copy_cmd_halfpage_down_and_cancel
2532 { .command
= "halfpage-up",
2535 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2536 .f
= window_copy_cmd_halfpage_up
2538 { .command
= "history-bottom",
2541 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2542 .f
= window_copy_cmd_history_bottom
2544 { .command
= "history-top",
2547 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2548 .f
= window_copy_cmd_history_top
2550 { .command
= "jump-again",
2553 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2554 .f
= window_copy_cmd_jump_again
2556 { .command
= "jump-backward",
2559 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2560 .f
= window_copy_cmd_jump_backward
2562 { .command
= "jump-forward",
2565 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2566 .f
= window_copy_cmd_jump_forward
2568 { .command
= "jump-reverse",
2571 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2572 .f
= window_copy_cmd_jump_reverse
2574 { .command
= "jump-to-backward",
2577 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2578 .f
= window_copy_cmd_jump_to_backward
2580 { .command
= "jump-to-forward",
2583 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2584 .f
= window_copy_cmd_jump_to_forward
2586 { .command
= "jump-to-mark",
2589 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2590 .f
= window_copy_cmd_jump_to_mark
2592 { .command
= "middle-line",
2595 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2596 .f
= window_copy_cmd_middle_line
2598 { .command
= "next-matching-bracket",
2601 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2602 .f
= window_copy_cmd_next_matching_bracket
2604 { .command
= "next-paragraph",
2607 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2608 .f
= window_copy_cmd_next_paragraph
2610 { .command
= "next-space",
2613 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2614 .f
= window_copy_cmd_next_space
2616 { .command
= "next-space-end",
2619 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2620 .f
= window_copy_cmd_next_space_end
2622 { .command
= "next-word",
2625 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2626 .f
= window_copy_cmd_next_word
2628 { .command
= "next-word-end",
2631 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2632 .f
= window_copy_cmd_next_word_end
2634 { .command
= "other-end",
2637 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2638 .f
= window_copy_cmd_other_end
2640 { .command
= "page-down",
2643 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2644 .f
= window_copy_cmd_page_down
2646 { .command
= "page-down-and-cancel",
2649 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2650 .f
= window_copy_cmd_page_down_and_cancel
2652 { .command
= "page-up",
2655 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2656 .f
= window_copy_cmd_page_up
2658 { .command
= "pipe-no-clear",
2661 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2662 .f
= window_copy_cmd_pipe_no_clear
2664 { .command
= "pipe",
2667 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2668 .f
= window_copy_cmd_pipe
2670 { .command
= "pipe-and-cancel",
2673 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2674 .f
= window_copy_cmd_pipe_and_cancel
2676 { .command
= "previous-matching-bracket",
2679 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2680 .f
= window_copy_cmd_previous_matching_bracket
2682 { .command
= "previous-paragraph",
2685 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2686 .f
= window_copy_cmd_previous_paragraph
2688 { .command
= "previous-space",
2691 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2692 .f
= window_copy_cmd_previous_space
2694 { .command
= "previous-word",
2697 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2698 .f
= window_copy_cmd_previous_word
2700 { .command
= "rectangle-on",
2703 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2704 .f
= window_copy_cmd_rectangle_on
2706 { .command
= "rectangle-off",
2709 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2710 .f
= window_copy_cmd_rectangle_off
2712 { .command
= "rectangle-toggle",
2715 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2716 .f
= window_copy_cmd_rectangle_toggle
2718 { .command
= "refresh-from-pane",
2721 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2722 .f
= window_copy_cmd_refresh_from_pane
2724 { .command
= "scroll-down",
2727 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2728 .f
= window_copy_cmd_scroll_down
2730 { .command
= "scroll-down-and-cancel",
2733 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2734 .f
= window_copy_cmd_scroll_down_and_cancel
2736 { .command
= "scroll-up",
2739 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2740 .f
= window_copy_cmd_scroll_up
2742 { .command
= "search-again",
2745 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2746 .f
= window_copy_cmd_search_again
2748 { .command
= "search-backward",
2751 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2752 .f
= window_copy_cmd_search_backward
2754 { .command
= "search-backward-text",
2757 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2758 .f
= window_copy_cmd_search_backward_text
2760 { .command
= "search-backward-incremental",
2763 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2764 .f
= window_copy_cmd_search_backward_incremental
2766 { .command
= "search-forward",
2769 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2770 .f
= window_copy_cmd_search_forward
2772 { .command
= "search-forward-text",
2775 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2776 .f
= window_copy_cmd_search_forward_text
2778 { .command
= "search-forward-incremental",
2781 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2782 .f
= window_copy_cmd_search_forward_incremental
2784 { .command
= "search-reverse",
2787 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2788 .f
= window_copy_cmd_search_reverse
2790 { .command
= "select-line",
2793 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2794 .f
= window_copy_cmd_select_line
2796 { .command
= "select-word",
2799 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2800 .f
= window_copy_cmd_select_word
2802 { .command
= "set-mark",
2805 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2806 .f
= window_copy_cmd_set_mark
2808 { .command
= "start-of-line",
2811 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2812 .f
= window_copy_cmd_start_of_line
2814 { .command
= "stop-selection",
2817 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2818 .f
= window_copy_cmd_stop_selection
2820 { .command
= "top-line",
2823 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2824 .f
= window_copy_cmd_top_line
2829 window_copy_command(struct window_mode_entry
*wme
, struct client
*c
,
2830 struct session
*s
, struct winlink
*wl
, struct args
*args
,
2831 struct mouse_event
*m
)
2833 struct window_copy_mode_data
*data
= wme
->data
;
2834 struct window_copy_cmd_state cs
;
2835 enum window_copy_cmd_action action
;
2836 enum window_copy_cmd_clear clear
= WINDOW_COPY_CMD_CLEAR_NEVER
;
2837 const char *command
;
2838 u_int i
, count
= args_count(args
);
2843 command
= args_string(args
, 0);
2845 if (m
!= NULL
&& m
->valid
&& !MOUSE_WHEEL(m
->b
))
2846 window_copy_move_mouse(m
);
2856 action
= WINDOW_COPY_CMD_NOTHING
;
2857 for (i
= 0; i
< nitems(window_copy_cmd_table
); i
++) {
2858 if (strcmp(window_copy_cmd_table
[i
].command
, command
) == 0) {
2859 if (count
- 1 < window_copy_cmd_table
[i
].minargs
||
2860 count
- 1 > window_copy_cmd_table
[i
].maxargs
)
2862 clear
= window_copy_cmd_table
[i
].clear
;
2863 action
= window_copy_cmd_table
[i
].f(&cs
);
2868 if (strncmp(command
, "search-", 7) != 0 && data
->searchmark
!= NULL
) {
2869 keys
= options_get_number(wme
->wp
->window
->options
, "mode-keys");
2870 if (clear
== WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
&&
2872 clear
= WINDOW_COPY_CMD_CLEAR_NEVER
;
2873 if (clear
!= WINDOW_COPY_CMD_CLEAR_NEVER
) {
2874 window_copy_clear_marks(wme
);
2875 data
->searchx
= data
->searchy
= -1;
2877 if (action
== WINDOW_COPY_CMD_NOTHING
)
2878 action
= WINDOW_COPY_CMD_REDRAW
;
2882 if (action
== WINDOW_COPY_CMD_CANCEL
)
2883 window_pane_reset_mode(wme
->wp
);
2884 else if (action
== WINDOW_COPY_CMD_REDRAW
)
2885 window_copy_redraw_screen(wme
);
2889 window_copy_scroll_to(struct window_mode_entry
*wme
, u_int px
, u_int py
,
2892 struct window_copy_mode_data
*data
= wme
->data
;
2893 struct grid
*gd
= data
->backing
->grid
;
2898 if (py
>= gd
->hsize
- data
->oy
&& py
< gd
->hsize
- data
->oy
+ gd
->sy
)
2899 data
->cy
= py
- (gd
->hsize
- data
->oy
);
2905 } else if (py
> gd
->hsize
+ gd
->sy
- gap
) {
2907 data
->cy
= py
- gd
->hsize
;
2909 offset
= py
+ gap
- gd
->sy
;
2910 data
->cy
= py
- offset
;
2912 data
->oy
= gd
->hsize
- offset
;
2915 if (!no_redraw
&& data
->searchmark
!= NULL
&& !data
->timeout
)
2916 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
2917 window_copy_update_selection(wme
, 1, 0);
2919 window_copy_redraw_screen(wme
);
2923 window_copy_search_compare(struct grid
*gd
, u_int px
, u_int py
,
2924 struct grid
*sgd
, u_int spx
, int cis
)
2926 struct grid_cell gc
, sgc
;
2927 const struct utf8_data
*ud
, *sud
;
2929 grid_get_cell(gd
, px
, py
, &gc
);
2931 grid_get_cell(sgd
, spx
, 0, &sgc
);
2934 if (ud
->size
!= sud
->size
|| ud
->width
!= sud
->width
)
2937 if (cis
&& ud
->size
== 1)
2938 return (tolower(ud
->data
[0]) == sud
->data
[0]);
2940 return (memcmp(ud
->data
, sud
->data
, ud
->size
) == 0);
2944 window_copy_search_lr(struct grid
*gd
, struct grid
*sgd
, u_int
*ppx
, u_int py
,
2945 u_int first
, u_int last
, int cis
)
2947 u_int ax
, bx
, px
, pywrap
, endline
;
2949 struct grid_line
*gl
;
2951 endline
= gd
->hsize
+ gd
->sy
- 1;
2952 for (ax
= first
; ax
< last
; ax
++) {
2953 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
2957 while (px
>= gd
->sx
&& pywrap
< endline
) {
2958 gl
= grid_get_line(gd
, pywrap
);
2959 if (~gl
->flags
& GRID_LINE_WRAPPED
)
2964 /* We have run off the end of the grid. */
2967 matched
= window_copy_search_compare(gd
, px
, pywrap
,
2972 if (bx
== sgd
->sx
) {
2981 window_copy_search_rl(struct grid
*gd
,
2982 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
, int cis
)
2984 u_int ax
, bx
, px
, pywrap
, endline
;
2986 struct grid_line
*gl
;
2988 endline
= gd
->hsize
+ gd
->sy
- 1;
2989 for (ax
= last
; ax
> first
; ax
--) {
2990 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
2994 while (px
>= gd
->sx
&& pywrap
< endline
) {
2995 gl
= grid_get_line(gd
, pywrap
);
2996 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3001 /* We have run off the end of the grid. */
3004 matched
= window_copy_search_compare(gd
, px
, pywrap
,
3009 if (bx
== sgd
->sx
) {
3018 window_copy_search_lr_regex(struct grid
*gd
, u_int
*ppx
, u_int
*psx
, u_int py
,
3019 u_int first
, u_int last
, regex_t
*reg
)
3022 u_int endline
, foundx
, foundy
, len
, pywrap
, size
= 1;
3024 regmatch_t regmatch
;
3025 struct grid_line
*gl
;
3028 * This can happen during search if the last match was the last
3029 * character on a line.
3034 /* Set flags for regex search. */
3036 eflags
|= REG_NOTBOL
;
3038 /* Need to look at the entire string. */
3039 buf
= xmalloc(size
);
3041 buf
= window_copy_stringify(gd
, py
, first
, gd
->sx
, buf
, &size
);
3042 len
= gd
->sx
- first
;
3043 endline
= gd
->hsize
+ gd
->sy
- 1;
3045 while (buf
!= NULL
&& pywrap
<= endline
) {
3046 gl
= grid_get_line(gd
, pywrap
);
3047 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3050 buf
= window_copy_stringify(gd
, pywrap
, 0, gd
->sx
, buf
, &size
);
3054 if (regexec(reg
, buf
, 1, ®match
, eflags
) == 0 &&
3055 regmatch
.rm_so
!= regmatch
.rm_eo
) {
3058 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3059 buf
+ regmatch
.rm_so
);
3060 if (foundy
== py
&& foundx
< last
) {
3062 len
-= foundx
- first
;
3063 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3064 buf
+ regmatch
.rm_eo
);
3066 while (foundy
> py
) {
3083 window_copy_search_rl_regex(struct grid
*gd
, u_int
*ppx
, u_int
*psx
, u_int py
,
3084 u_int first
, u_int last
, regex_t
*reg
)
3087 u_int endline
, len
, pywrap
, size
= 1;
3089 struct grid_line
*gl
;
3091 /* Set flags for regex search. */
3093 eflags
|= REG_NOTBOL
;
3095 /* Need to look at the entire string. */
3096 buf
= xmalloc(size
);
3098 buf
= window_copy_stringify(gd
, py
, first
, gd
->sx
, buf
, &size
);
3099 len
= gd
->sx
- first
;
3100 endline
= gd
->hsize
+ gd
->sy
- 1;
3102 while (buf
!= NULL
&& (pywrap
<= endline
)) {
3103 gl
= grid_get_line(gd
, pywrap
);
3104 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3107 buf
= window_copy_stringify(gd
, pywrap
, 0, gd
->sx
, buf
, &size
);
3111 if (window_copy_last_regex(gd
, py
, first
, last
, len
, ppx
, psx
, buf
,
3125 window_copy_cellstring(const struct grid_line
*gl
, u_int px
, size_t *size
,
3128 static struct utf8_data ud
;
3129 struct grid_cell_entry
*gce
;
3132 if (px
>= gl
->cellsize
) {
3138 gce
= &gl
->celldata
[px
];
3139 if (gce
->flags
& GRID_FLAG_PADDING
) {
3144 if (~gce
->flags
& GRID_FLAG_EXTENDED
) {
3147 return (&gce
->data
.data
);
3150 utf8_to_data(gl
->extddata
[gce
->offset
].data
, &ud
);
3154 copy
= xmalloc(ud
.size
);
3155 memcpy(copy
, ud
.data
, ud
.size
);
3159 /* Find last match in given range. */
3161 window_copy_last_regex(struct grid
*gd
, u_int py
, u_int first
, u_int last
,
3162 u_int len
, u_int
*ppx
, u_int
*psx
, const char *buf
, const regex_t
*preg
,
3165 u_int foundx
, foundy
, oldx
, px
= 0, savepx
, savesx
= 0;
3166 regmatch_t regmatch
;
3171 while (regexec(preg
, buf
+ px
, 1, ®match
, eflags
) == 0) {
3172 if (regmatch
.rm_so
== regmatch
.rm_eo
)
3174 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3175 buf
+ px
+ regmatch
.rm_so
);
3176 if (foundy
> py
|| foundx
>= last
)
3178 len
-= foundx
- oldx
;
3180 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3181 buf
+ px
+ regmatch
.rm_eo
);
3182 if (foundy
> py
|| foundx
>= last
) {
3185 while (foundy
> py
) {
3192 savesx
= foundx
- savepx
;
3196 px
+= regmatch
.rm_eo
;
3210 /* Stringify line and append to input buffer. Caller frees. */
3212 window_copy_stringify(struct grid
*gd
, u_int py
, u_int first
, u_int last
,
3213 char *buf
, u_int
*size
)
3215 u_int ax
, bx
, newsize
= *size
;
3216 const struct grid_line
*gl
;
3218 size_t bufsize
= 1024, dlen
;
3221 while (bufsize
< newsize
)
3223 buf
= xrealloc(buf
, bufsize
);
3225 gl
= grid_peek_line(gd
, py
);
3227 for (ax
= first
; ax
< last
; ax
++) {
3228 d
= window_copy_cellstring(gl
, ax
, &dlen
, &allocated
);
3230 while (bufsize
< newsize
) {
3232 buf
= xrealloc(buf
, bufsize
);
3237 memcpy(buf
+ bx
, d
, dlen
);
3243 buf
[newsize
- 1] = '\0';
3249 /* Map start of C string containing UTF-8 data to grid cell position. */
3251 window_copy_cstrtocellpos(struct grid
*gd
, u_int ncells
, u_int
*ppx
, u_int
*ppy
,
3254 u_int cell
, ccell
, px
, pywrap
, pos
, len
;
3256 const struct grid_line
*gl
;
3265 /* Populate the array of cell data. */
3266 cells
= xreallocarray(NULL
, ncells
, sizeof cells
[0]);
3270 gl
= grid_peek_line(gd
, pywrap
);
3271 while (cell
< ncells
) {
3272 cells
[cell
].d
= window_copy_cellstring(gl
, px
,
3273 &cells
[cell
].dlen
, &cells
[cell
].allocated
);
3279 gl
= grid_peek_line(gd
, pywrap
);
3283 /* Locate starting cell. */
3286 while (cell
< ncells
) {
3290 while (ccell
< ncells
) {
3291 if (str
[pos
] == '\0') {
3296 dlen
= cells
[ccell
].dlen
;
3298 if (str
[pos
] != *d
) {
3304 if (dlen
> len
- pos
)
3306 if (memcmp(str
+ pos
, d
, dlen
) != 0) {
3319 /* If not found this will be one past the end. */
3322 while (px
>= gd
->sx
) {
3330 /* Free cell data. */
3331 for (cell
= 0; cell
< ncells
; cell
++) {
3332 if (cells
[cell
].allocated
)
3333 free((void *)cells
[cell
].d
);
3339 window_copy_move_left(struct screen
*s
, u_int
*fx
, u_int
*fy
, int wrapflag
)
3341 if (*fx
== 0) { /* left */
3342 if (*fy
== 0) { /* top */
3344 *fx
= screen_size_x(s
) - 1;
3345 *fy
= screen_hsize(s
) + screen_size_y(s
) - 1;
3349 *fx
= screen_size_x(s
) - 1;
3356 window_copy_move_right(struct screen
*s
, u_int
*fx
, u_int
*fy
, int wrapflag
)
3358 if (*fx
== screen_size_x(s
) - 1) { /* right */
3359 if (*fy
== screen_hsize(s
) + screen_size_y(s
) - 1) { /* bottom */
3373 window_copy_is_lowercase(const char *ptr
)
3375 while (*ptr
!= '\0') {
3376 if (*ptr
!= tolower((u_char
)*ptr
))
3384 * Handle backward wrapped regex searches with overlapping matches. In this case
3385 * find the longest overlapping match from previous wrapped lines.
3388 window_copy_search_back_overlap(struct grid
*gd
, regex_t
*preg
, u_int
*ppx
,
3389 u_int
*psx
, u_int
*ppy
, u_int endline
)
3391 u_int endx
, endy
, oldendx
, oldendy
, px
, py
, sx
;
3394 oldendx
= *ppx
+ *psx
;
3396 while (oldendx
> gd
->sx
- 1) {
3404 while (found
&& px
== 0 && py
- 1 > endline
&&
3405 grid_get_line(gd
, py
- 2)->flags
& GRID_LINE_WRAPPED
&&
3406 endx
== oldendx
&& endy
== oldendy
) {
3408 found
= window_copy_search_rl_regex(gd
, &px
, &sx
, py
- 1, 0,
3413 while (endx
> gd
->sx
- 1) {
3417 if (endx
== oldendx
&& endy
== oldendy
) {
3426 * Search for text stored in sgd starting from position fx,fy up to endline. If
3427 * found, jump to it. If cis then ignore case. The direction is 0 for searching
3428 * up, down otherwise. If wrap then go to begin/end of grid and try again if
3432 window_copy_search_jump(struct window_mode_entry
*wme
, struct grid
*gd
,
3433 struct grid
*sgd
, u_int fx
, u_int fy
, u_int endline
, int cis
, int wrap
,
3434 int direction
, int regex
)
3436 u_int i
, px
, sx
, ssize
= 1;
3437 int found
= 0, cflags
= REG_EXTENDED
;
3442 sbuf
= xmalloc(ssize
);
3444 sbuf
= window_copy_stringify(sgd
, 0, 0, sgd
->sx
, sbuf
, &ssize
);
3446 cflags
|= REG_ICASE
;
3447 if (regcomp(®
, sbuf
, cflags
) != 0) {
3455 for (i
= fy
; i
<= endline
; i
++) {
3457 found
= window_copy_search_lr_regex(gd
,
3458 &px
, &sx
, i
, fx
, gd
->sx
, ®
);
3460 found
= window_copy_search_lr(gd
, sgd
,
3461 &px
, i
, fx
, gd
->sx
, cis
);
3468 for (i
= fy
+ 1; endline
< i
; i
--) {
3470 found
= window_copy_search_rl_regex(gd
,
3471 &px
, &sx
, i
- 1, 0, fx
+ 1, ®
);
3473 window_copy_search_back_overlap(gd
,
3474 ®
, &px
, &sx
, &i
, endline
);
3477 found
= window_copy_search_rl(gd
, sgd
,
3478 &px
, i
- 1, 0, fx
+ 1, cis
);
3491 window_copy_scroll_to(wme
, px
, i
, 1);
3495 return (window_copy_search_jump(wme
, gd
, sgd
,
3496 direction
? 0 : gd
->sx
- 1,
3497 direction
? 0 : gd
->hsize
+ gd
->sy
- 1, fy
, cis
, 0,
3504 window_copy_move_after_search_mark(struct window_copy_mode_data
*data
,
3505 u_int
*fx
, u_int
*fy
, int wrapflag
)
3507 struct screen
*s
= data
->backing
;
3510 if (window_copy_search_mark_at(data
, *fx
, *fy
, &start
) == 0 &&
3511 data
->searchmark
[start
] != 0) {
3512 while (window_copy_search_mark_at(data
, *fx
, *fy
, &at
) == 0) {
3513 if (data
->searchmark
[at
] != data
->searchmark
[start
])
3515 /* Stop if not wrapping and at the end of the grid. */
3517 *fx
== screen_size_x(s
) - 1 &&
3518 *fy
== screen_hsize(s
) + screen_size_y(s
) - 1)
3521 window_copy_move_right(s
, fx
, fy
, wrapflag
);
3527 * Search in for text searchstr. If direction is 0 then search up, otherwise
3531 window_copy_search(struct window_mode_entry
*wme
, int direction
, int regex
)
3533 struct window_pane
*wp
= wme
->wp
;
3534 struct window_copy_mode_data
*data
= wme
->data
;
3535 struct screen
*s
= data
->backing
, ss
;
3536 struct screen_write_ctx ctx
;
3537 struct grid
*gd
= s
->grid
;
3538 const char *str
= data
->searchstr
;
3539 u_int at
, endline
, fx
, fy
, start
;
3540 int cis
, found
, keys
, visible_only
;
3543 if (regex
&& str
[strcspn(str
, "^$*+()?[].\\")] == '\0')
3546 data
->searchdirection
= direction
;
3551 if (data
->searchall
|| wp
->searchstr
== NULL
||
3552 wp
->searchregex
!= regex
) {
3554 data
->searchall
= 0;
3556 visible_only
= (strcmp(wp
->searchstr
, str
) == 0);
3557 free(wp
->searchstr
);
3558 wp
->searchstr
= xstrdup(str
);
3559 wp
->searchregex
= regex
;
3562 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3564 screen_init(&ss
, screen_write_strlen("%s", str
), 1, 0);
3565 screen_write_start(&ctx
, &ss
);
3566 screen_write_nputs(&ctx
, -1, &grid_default_cell
, "%s", str
);
3567 screen_write_stop(&ctx
);
3569 wrapflag
= options_get_number(wp
->window
->options
, "wrap-search");
3570 cis
= window_copy_is_lowercase(str
);
3572 keys
= options_get_number(wp
->window
->options
, "mode-keys");
3576 * Behave according to mode-keys. If it is emacs, search forward
3577 * leaves the cursor after the match. If it is vi, the cursor
3578 * remains at the beginning of the match, regardless of
3579 * direction, which means that we need to start the next search
3580 * after the term the cursor is currently on when searching
3583 if (keys
== MODEKEY_VI
) {
3584 if (data
->searchmark
!= NULL
)
3585 window_copy_move_after_search_mark(data
, &fx
,
3589 * When there are no search marks, start the
3590 * search after the current cursor position.
3592 window_copy_move_right(s
, &fx
, &fy
, wrapflag
);
3595 endline
= gd
->hsize
+ gd
->sy
- 1;
3598 window_copy_move_left(s
, &fx
, &fy
, wrapflag
);
3602 found
= window_copy_search_jump(wme
, gd
, ss
.grid
, fx
, fy
, endline
, cis
,
3603 wrapflag
, direction
, regex
);
3605 window_copy_search_marks(wme
, &ss
, regex
, visible_only
);
3607 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3610 * When searching forward, if the cursor is not at the beginning
3611 * of the mark, search again.
3614 window_copy_search_mark_at(data
, fx
, fy
, &at
) == 0 &&
3616 data
->searchmark
[at
] == data
->searchmark
[at
- 1]) {
3617 window_copy_move_after_search_mark(data
, &fx
, &fy
,
3619 window_copy_search_jump(wme
, gd
, ss
.grid
, fx
,
3620 fy
, endline
, cis
, wrapflag
, direction
,
3623 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3628 * When in Emacs mode, position the cursor just after
3631 if (keys
== MODEKEY_EMACS
) {
3632 window_copy_move_after_search_mark(data
, &fx
,
3635 data
->cy
= fy
- screen_hsize(data
->backing
) +
3641 * When searching backward, position the cursor at the
3642 * beginning of the mark.
3644 if (window_copy_search_mark_at(data
, fx
, fy
,
3646 while (window_copy_search_mark_at(data
, fx
, fy
,
3648 data
->searchmark
[at
] ==
3649 data
->searchmark
[start
]) {
3652 screen_hsize(data
->backing
) +
3657 window_copy_move_left(s
, &fx
, &fy
, 0);
3662 window_copy_redraw_screen(wme
);
3669 window_copy_visible_lines(struct window_copy_mode_data
*data
, u_int
*start
,
3672 struct grid
*gd
= data
->backing
->grid
;
3673 const struct grid_line
*gl
;
3675 for (*start
= gd
->hsize
- data
->oy
; *start
> 0; (*start
)--) {
3676 gl
= grid_peek_line(gd
, (*start
) - 1);
3677 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3680 *end
= gd
->hsize
- data
->oy
+ gd
->sy
;
3684 window_copy_search_mark_at(struct window_copy_mode_data
*data
, u_int px
,
3685 u_int py
, u_int
*at
)
3687 struct screen
*s
= data
->backing
;
3688 struct grid
*gd
= s
->grid
;
3690 if (py
< gd
->hsize
- data
->oy
)
3692 if (py
> gd
->hsize
- data
->oy
+ gd
->sy
- 1)
3694 *at
= ((py
- (gd
->hsize
- data
->oy
)) * gd
->sx
) + px
;
3699 window_copy_search_marks(struct window_mode_entry
*wme
, struct screen
*ssp
,
3700 int regex
, int visible_only
)
3702 struct window_copy_mode_data
*data
= wme
->data
;
3703 struct screen
*s
= data
->backing
, ss
;
3704 struct screen_write_ctx ctx
;
3705 struct grid
*gd
= s
->grid
;
3706 int found
, cis
, stopped
= 0;
3707 int cflags
= REG_EXTENDED
;
3708 u_int px
, py
, i
, b
, nfound
= 0, width
;
3709 u_int ssize
= 1, start
, end
;
3712 uint64_t stop
= 0, tstart
, t
;
3715 width
= screen_write_strlen("%s", data
->searchstr
);
3716 screen_init(&ss
, width
, 1, 0);
3717 screen_write_start(&ctx
, &ss
);
3718 screen_write_nputs(&ctx
, -1, &grid_default_cell
, "%s",
3720 screen_write_stop(&ctx
);
3723 width
= screen_size_x(ssp
);
3725 cis
= window_copy_is_lowercase(data
->searchstr
);
3728 sbuf
= xmalloc(ssize
);
3730 sbuf
= window_copy_stringify(ssp
->grid
, 0, 0, ssp
->grid
->sx
,
3733 cflags
|= REG_ICASE
;
3734 if (regcomp(®
, sbuf
, cflags
) != 0) {
3740 tstart
= get_timer();
3743 window_copy_visible_lines(data
, &start
, &end
);
3746 end
= gd
->hsize
+ gd
->sy
;
3747 stop
= get_timer() + WINDOW_COPY_SEARCH_ALL_TIMEOUT
;
3751 free(data
->searchmark
);
3752 data
->searchmark
= xcalloc(gd
->sx
, gd
->sy
);
3753 data
->searchgen
= 1;
3755 for (py
= start
; py
< end
; py
++) {
3759 found
= window_copy_search_lr_regex(gd
,
3760 &px
, &width
, py
, px
, gd
->sx
, ®
);
3764 found
= window_copy_search_lr(gd
, ssp
->grid
,
3765 &px
, py
, px
, gd
->sx
, cis
);
3771 if (window_copy_search_mark_at(data
, px
, py
, &b
) == 0) {
3772 if (b
+ width
> gd
->sx
* gd
->sy
)
3773 width
= (gd
->sx
* gd
->sy
) - b
;
3774 for (i
= b
; i
< b
+ width
; i
++) {
3775 if (data
->searchmark
[i
] != 0)
3777 data
->searchmark
[i
] = data
->searchgen
;
3779 if (data
->searchgen
== UCHAR_MAX
)
3780 data
->searchgen
= 1;
3788 if (t
- tstart
> WINDOW_COPY_SEARCH_TIMEOUT
) {
3792 if (stop
!= 0 && t
> stop
) {
3797 if (data
->timeout
) {
3798 window_copy_clear_marks(wme
);
3802 if (stopped
&& stop
!= 0) {
3803 /* Try again but just the visible context. */
3804 window_copy_visible_lines(data
, &start
, &end
);
3809 if (!visible_only
) {
3812 data
->searchcount
= 1000;
3813 else if (nfound
> 100)
3814 data
->searchcount
= 100;
3815 else if (nfound
> 10)
3816 data
->searchcount
= 10;
3818 data
->searchcount
= -1;
3819 data
->searchmore
= 1;
3821 data
->searchcount
= nfound
;
3822 data
->searchmore
= 0;
3835 window_copy_clear_marks(struct window_mode_entry
*wme
)
3837 struct window_copy_mode_data
*data
= wme
->data
;
3839 free(data
->searchmark
);
3840 data
->searchmark
= NULL
;
3844 window_copy_search_up(struct window_mode_entry
*wme
, int regex
)
3846 return (window_copy_search(wme
, 0, regex
));
3850 window_copy_search_down(struct window_mode_entry
*wme
, int regex
)
3852 return (window_copy_search(wme
, 1, regex
));
3856 window_copy_goto_line(struct window_mode_entry
*wme
, const char *linestr
)
3858 struct window_copy_mode_data
*data
= wme
->data
;
3862 lineno
= strtonum(linestr
, -1, INT_MAX
, &errstr
);
3865 if (lineno
< 0 || (u_int
)lineno
> screen_hsize(data
->backing
))
3866 lineno
= screen_hsize(data
->backing
);
3869 window_copy_update_selection(wme
, 1, 0);
3870 window_copy_redraw_screen(wme
);
3874 window_copy_match_start_end(struct window_copy_mode_data
*data
, u_int at
,
3875 u_int
*start
, u_int
*end
)
3877 struct grid
*gd
= data
->backing
->grid
;
3878 u_int last
= (gd
->sy
* gd
->sx
) - 1;
3879 u_char mark
= data
->searchmark
[at
];
3882 while (*start
!= 0 && data
->searchmark
[*start
] == mark
)
3884 if (data
->searchmark
[*start
] != mark
)
3886 while (*end
!= last
&& data
->searchmark
[*end
] == mark
)
3888 if (data
->searchmark
[*end
] != mark
)
3893 window_copy_match_at_cursor(struct window_copy_mode_data
*data
)
3895 struct grid
*gd
= data
->backing
->grid
;
3896 struct grid_cell gc
;
3897 u_int at
, start
, end
, cy
, px
, py
;
3898 u_int sx
= screen_size_x(data
->backing
);
3902 if (data
->searchmark
== NULL
)
3905 cy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3906 if (window_copy_search_mark_at(data
, data
->cx
, cy
, &at
) != 0)
3908 if (data
->searchmark
[at
] == 0) {
3909 /* Allow one position after the match. */
3910 if (at
== 0 || data
->searchmark
[--at
] == 0)
3913 window_copy_match_start_end(data
, at
, &start
, &end
);
3916 * Cells will not be set in the marked array unless they are valid text
3917 * and wrapping will be taken care of, so we can just copy.
3919 for (at
= start
; at
<= end
; at
++) {
3921 px
= at
- (py
* sx
);
3923 grid_get_cell(gd
, px
, gd
->hsize
+ py
- data
->oy
, &gc
);
3924 buf
= xrealloc(buf
, len
+ gc
.data
.size
+ 1);
3925 memcpy(buf
+ len
, gc
.data
.data
, gc
.data
.size
);
3926 len
+= gc
.data
.size
;
3934 window_copy_update_style(struct window_mode_entry
*wme
, u_int fx
, u_int fy
,
3935 struct grid_cell
*gc
, const struct grid_cell
*mgc
,
3936 const struct grid_cell
*cgc
, const struct grid_cell
*mkgc
)
3938 struct window_pane
*wp
= wme
->wp
;
3939 struct window_copy_mode_data
*data
= wme
->data
;
3940 u_int mark
, start
, end
, cy
, cursor
, current
;
3941 int inv
= 0, found
= 0;
3944 if (data
->showmark
&& fy
== data
->my
) {
3945 gc
->attr
= mkgc
->attr
;
3958 if (data
->searchmark
== NULL
)
3961 if (window_copy_search_mark_at(data
, fx
, fy
, ¤t
) != 0)
3963 mark
= data
->searchmark
[current
];
3967 cy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3968 if (window_copy_search_mark_at(data
, data
->cx
, cy
, &cursor
) == 0) {
3969 keys
= options_get_number(wp
->window
->options
, "mode-keys");
3971 keys
== MODEKEY_EMACS
&&
3972 data
->searchdirection
) {
3973 if (data
->searchmark
[cursor
- 1] == mark
) {
3977 } else if (data
->searchmark
[cursor
] == mark
)
3980 window_copy_match_start_end(data
, cursor
, &start
, &end
);
3981 if (current
>= start
&& current
<= end
) {
3982 gc
->attr
= cgc
->attr
;
3996 gc
->attr
= mgc
->attr
;
4008 window_copy_write_one(struct window_mode_entry
*wme
,
4009 struct screen_write_ctx
*ctx
, u_int py
, u_int fy
, u_int nx
,
4010 const struct grid_cell
*mgc
, const struct grid_cell
*cgc
,
4011 const struct grid_cell
*mkgc
)
4013 struct window_copy_mode_data
*data
= wme
->data
;
4014 struct grid
*gd
= data
->backing
->grid
;
4015 struct grid_cell gc
;
4018 screen_write_cursormove(ctx
, 0, py
, 0);
4019 for (fx
= 0; fx
< nx
; fx
++) {
4020 grid_get_cell(gd
, fx
, fy
, &gc
);
4021 if (fx
+ gc
.data
.width
<= nx
) {
4022 window_copy_update_style(wme
, fx
, fy
, &gc
, mgc
, cgc
,
4024 screen_write_cell(ctx
, &gc
);
4030 window_copy_write_line(struct window_mode_entry
*wme
,
4031 struct screen_write_ctx
*ctx
, u_int py
)
4033 struct window_pane
*wp
= wme
->wp
;
4034 struct window_copy_mode_data
*data
= wme
->data
;
4035 struct screen
*s
= &data
->screen
;
4036 struct options
*oo
= wp
->window
->options
;
4037 struct grid_cell gc
, mgc
, cgc
, mkgc
;
4040 u_int hsize
= screen_hsize(data
->backing
);
4042 style_apply(&gc
, oo
, "mode-style", NULL
);
4043 gc
.flags
|= GRID_FLAG_NOPALETTE
;
4044 style_apply(&mgc
, oo
, "copy-mode-match-style", NULL
);
4045 mgc
.flags
|= GRID_FLAG_NOPALETTE
;
4046 style_apply(&cgc
, oo
, "copy-mode-current-match-style", NULL
);
4047 cgc
.flags
|= GRID_FLAG_NOPALETTE
;
4048 style_apply(&mkgc
, oo
, "copy-mode-mark-style", NULL
);
4049 mkgc
.flags
|= GRID_FLAG_NOPALETTE
;
4051 if (py
== 0 && s
->rupper
< s
->rlower
&& !data
->hide_position
) {
4052 if (data
->searchmark
== NULL
) {
4053 if (data
->timeout
) {
4054 size
= xsnprintf(hdr
, sizeof hdr
,
4055 "(timed out) [%u/%u]", data
->oy
, hsize
);
4057 size
= xsnprintf(hdr
, sizeof hdr
,
4058 "[%u/%u]", data
->oy
, hsize
);
4061 if (data
->searchcount
== -1) {
4062 size
= xsnprintf(hdr
, sizeof hdr
,
4063 "[%u/%u]", data
->oy
, hsize
);
4065 size
= xsnprintf(hdr
, sizeof hdr
,
4066 "(%d%s results) [%u/%u]", data
->searchcount
,
4067 data
->searchmore
? "+" : "", data
->oy
,
4071 if (size
> screen_size_x(s
))
4072 size
= screen_size_x(s
);
4073 screen_write_cursormove(ctx
, screen_size_x(s
) - size
, 0, 0);
4074 screen_write_puts(ctx
, &gc
, "%s", hdr
);
4078 if (size
< screen_size_x(s
)) {
4079 window_copy_write_one(wme
, ctx
, py
, hsize
- data
->oy
+ py
,
4080 screen_size_x(s
) - size
, &mgc
, &cgc
, &mkgc
);
4083 if (py
== data
->cy
&& data
->cx
== screen_size_x(s
)) {
4084 screen_write_cursormove(ctx
, screen_size_x(s
) - 1, py
, 0);
4085 screen_write_putc(ctx
, &grid_default_cell
, '$');
4090 window_copy_write_lines(struct window_mode_entry
*wme
,
4091 struct screen_write_ctx
*ctx
, u_int py
, u_int ny
)
4095 for (yy
= py
; yy
< py
+ ny
; yy
++)
4096 window_copy_write_line(wme
, ctx
, py
);
4100 window_copy_redraw_selection(struct window_mode_entry
*wme
, u_int old_y
)
4102 struct window_copy_mode_data
*data
= wme
->data
;
4103 struct grid
*gd
= data
->backing
->grid
;
4104 u_int new_y
, start
, end
;
4107 if (old_y
<= new_y
) {
4116 * In word selection mode the first word on the line below the cursor
4117 * might be selected, so add this line to the redraw area.
4119 if (data
->selflag
== SEL_WORD
) {
4120 /* Last grid line in data coordinates. */
4121 if (end
< gd
->sy
+ data
->oy
- 1)
4124 window_copy_redraw_lines(wme
, start
, end
- start
+ 1);
4128 window_copy_redraw_lines(struct window_mode_entry
*wme
, u_int py
, u_int ny
)
4130 struct window_pane
*wp
= wme
->wp
;
4131 struct window_copy_mode_data
*data
= wme
->data
;
4132 struct screen_write_ctx ctx
;
4135 screen_write_start_pane(&ctx
, wp
, NULL
);
4136 for (i
= py
; i
< py
+ ny
; i
++)
4137 window_copy_write_line(wme
, &ctx
, i
);
4138 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
4139 screen_write_stop(&ctx
);
4143 window_copy_redraw_screen(struct window_mode_entry
*wme
)
4145 struct window_copy_mode_data
*data
= wme
->data
;
4147 window_copy_redraw_lines(wme
, 0, screen_size_y(&data
->screen
));
4151 window_copy_synchronize_cursor_end(struct window_mode_entry
*wme
, int begin
,
4154 struct window_copy_mode_data
*data
= wme
->data
;
4158 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4159 switch (data
->selflag
) {
4164 if (data
->dy
> yy
|| (data
->dy
== yy
&& data
->dx
> xx
)) {
4165 /* Right to left selection. */
4166 window_copy_cursor_previous_word_pos(wme
,
4167 data
->separators
, &xx
, &yy
);
4170 /* Reset the end. */
4171 data
->endselx
= data
->endselrx
;
4172 data
->endsely
= data
->endselry
;
4174 /* Left to right selection. */
4175 if (xx
>= window_copy_find_length(wme
, yy
) ||
4176 !window_copy_in_set(wme
, xx
+ 1, yy
, WHITESPACE
)) {
4177 window_copy_cursor_next_word_end_pos(wme
,
4178 data
->separators
, &xx
, &yy
);
4181 /* Reset the start. */
4182 data
->selx
= data
->selrx
;
4183 data
->sely
= data
->selry
;
4190 if (data
->dy
> yy
) {
4191 /* Right to left selection. */
4195 /* Reset the end. */
4196 data
->endselx
= data
->endselrx
;
4197 data
->endsely
= data
->endselry
;
4199 /* Left to right selection. */
4200 if (yy
< data
->endselry
)
4201 yy
= data
->endselry
;
4202 xx
= window_copy_find_length(wme
, yy
);
4204 /* Reset the start. */
4205 data
->selx
= data
->selrx
;
4206 data
->sely
= data
->selry
;
4222 window_copy_synchronize_cursor(struct window_mode_entry
*wme
, int no_reset
)
4224 struct window_copy_mode_data
*data
= wme
->data
;
4226 switch (data
->cursordrag
) {
4227 case CURSORDRAG_ENDSEL
:
4228 window_copy_synchronize_cursor_end(wme
, 0, no_reset
);
4230 case CURSORDRAG_SEL
:
4231 window_copy_synchronize_cursor_end(wme
, 1, no_reset
);
4233 case CURSORDRAG_NONE
:
4239 window_copy_update_cursor(struct window_mode_entry
*wme
, u_int cx
, u_int cy
)
4241 struct window_pane
*wp
= wme
->wp
;
4242 struct window_copy_mode_data
*data
= wme
->data
;
4243 struct screen
*s
= &data
->screen
;
4244 struct screen_write_ctx ctx
;
4245 u_int old_cx
, old_cy
;
4247 old_cx
= data
->cx
; old_cy
= data
->cy
;
4248 data
->cx
= cx
; data
->cy
= cy
;
4249 if (old_cx
== screen_size_x(s
))
4250 window_copy_redraw_lines(wme
, old_cy
, 1);
4251 if (data
->cx
== screen_size_x(s
))
4252 window_copy_redraw_lines(wme
, data
->cy
, 1);
4254 screen_write_start_pane(&ctx
, wp
, NULL
);
4255 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
4256 screen_write_stop(&ctx
);
4261 window_copy_start_selection(struct window_mode_entry
*wme
)
4263 struct window_copy_mode_data
*data
= wme
->data
;
4265 data
->selx
= data
->cx
;
4266 data
->sely
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4268 data
->endselx
= data
->selx
;
4269 data
->endsely
= data
->sely
;
4271 data
->cursordrag
= CURSORDRAG_ENDSEL
;
4273 window_copy_set_selection(wme
, 1, 0);
4277 window_copy_adjust_selection(struct window_mode_entry
*wme
, u_int
*selx
,
4280 struct window_copy_mode_data
*data
= wme
->data
;
4281 struct screen
*s
= &data
->screen
;
4288 ty
= screen_hsize(data
->backing
) - data
->oy
;
4290 relpos
= WINDOW_COPY_REL_POS_ABOVE
;
4291 if (!data
->rectflag
)
4294 } else if (sy
> ty
+ screen_size_y(s
) - 1) {
4295 relpos
= WINDOW_COPY_REL_POS_BELOW
;
4296 if (!data
->rectflag
)
4297 sx
= screen_size_x(s
) - 1;
4298 sy
= screen_size_y(s
) - 1;
4300 relpos
= WINDOW_COPY_REL_POS_ON_SCREEN
;
4310 window_copy_update_selection(struct window_mode_entry
*wme
, int may_redraw
,
4313 struct window_copy_mode_data
*data
= wme
->data
;
4314 struct screen
*s
= &data
->screen
;
4316 if (s
->sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
)
4318 return (window_copy_set_selection(wme
, may_redraw
, no_reset
));
4322 window_copy_set_selection(struct window_mode_entry
*wme
, int may_redraw
,
4325 struct window_pane
*wp
= wme
->wp
;
4326 struct window_copy_mode_data
*data
= wme
->data
;
4327 struct screen
*s
= &data
->screen
;
4328 struct options
*oo
= wp
->window
->options
;
4329 struct grid_cell gc
;
4330 u_int sx
, sy
, cy
, endsx
, endsy
;
4331 int startrelpos
, endrelpos
;
4333 window_copy_synchronize_cursor(wme
, no_reset
);
4335 /* Adjust the selection. */
4338 startrelpos
= window_copy_adjust_selection(wme
, &sx
, &sy
);
4340 /* Adjust the end of selection. */
4341 endsx
= data
->endselx
;
4342 endsy
= data
->endsely
;
4343 endrelpos
= window_copy_adjust_selection(wme
, &endsx
, &endsy
);
4345 /* Selection is outside of the current screen */
4346 if (startrelpos
== endrelpos
&&
4347 startrelpos
!= WINDOW_COPY_REL_POS_ON_SCREEN
) {
4348 screen_hide_selection(s
);
4352 /* Set colours and selection. */
4353 style_apply(&gc
, oo
, "mode-style", NULL
);
4354 gc
.flags
|= GRID_FLAG_NOPALETTE
;
4355 screen_set_selection(s
, sx
, sy
, endsx
, endsy
, data
->rectflag
,
4356 data
->modekeys
, &gc
);
4358 if (data
->rectflag
&& may_redraw
) {
4360 * Can't rely on the caller to redraw the right lines for
4361 * rectangle selection - find the highest line and the number
4362 * of lines, and redraw just past that in both directions
4365 if (data
->cursordrag
== CURSORDRAG_ENDSEL
) {
4367 window_copy_redraw_lines(wme
, sy
, cy
- sy
+ 1);
4369 window_copy_redraw_lines(wme
, cy
, sy
- cy
+ 1);
4372 window_copy_redraw_lines(wme
, endsy
,
4375 window_copy_redraw_lines(wme
, cy
,
4385 window_copy_get_selection(struct window_mode_entry
*wme
, size_t *len
)
4387 struct window_pane
*wp
= wme
->wp
;
4388 struct window_copy_mode_data
*data
= wme
->data
;
4389 struct screen
*s
= &data
->screen
;
4392 u_int i
, xx
, yy
, sx
, sy
, ex
, ey
, ey_last
;
4393 u_int firstsx
, lastex
, restex
, restsx
, selx
;
4396 if (data
->screen
.sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
) {
4397 buf
= window_copy_match_at_cursor(data
);
4411 * The selection extends from selx,sely to (adjusted) cx,cy on
4415 /* Find start and end. */
4418 if (yy
< data
->sely
|| (yy
== data
->sely
&& xx
< data
->selx
)) {
4420 ex
= data
->selx
; ey
= data
->sely
;
4422 sx
= data
->selx
; sy
= data
->sely
;
4426 /* Trim ex to end of line. */
4427 ey_last
= window_copy_find_length(wme
, ey
);
4432 * Deal with rectangle-copy if necessary; four situations: start of
4433 * first line (firstsx), end of last line (lastex), start (restsx) and
4434 * end (restex) of all other lines.
4436 xx
= screen_size_x(s
);
4439 * Behave according to mode-keys. If it is emacs, copy like emacs,
4440 * keeping the top-left-most character, and dropping the
4441 * bottom-right-most, regardless of copy direction. If it is vi, also
4442 * keep bottom-right-most character.
4444 keys
= options_get_number(wp
->window
->options
, "mode-keys");
4445 if (data
->rectflag
) {
4447 * Need to ignore the column with the cursor in it, which for
4448 * rectangular copy means knowing which side the cursor is on.
4450 if (data
->cursordrag
== CURSORDRAG_ENDSEL
)
4453 selx
= data
->endselx
;
4454 if (selx
< data
->cx
) {
4455 /* Selection start is on the left. */
4456 if (keys
== MODEKEY_EMACS
) {
4461 lastex
= data
->cx
+ 1;
4462 restex
= data
->cx
+ 1;
4467 /* Cursor is on the left. */
4474 if (keys
== MODEKEY_EMACS
)
4483 /* Copy the lines. */
4484 for (i
= sy
; i
<= ey
; i
++) {
4485 window_copy_copy_line(wme
, &buf
, &off
, i
,
4486 (i
== sy
? firstsx
: restsx
),
4487 (i
== ey
? lastex
: restex
));
4490 /* Don't bother if no data. */
4496 /* Remove final \n (unless at end in vi mode). */
4497 if (keys
== MODEKEY_EMACS
|| lastex
<= ey_last
) {
4498 if (~grid_get_line(data
->backing
->grid
, ey
)->flags
&
4499 GRID_LINE_WRAPPED
|| lastex
!= ey_last
)
4507 window_copy_copy_buffer(struct window_mode_entry
*wme
, const char *prefix
,
4508 void *buf
, size_t len
)
4510 struct window_pane
*wp
= wme
->wp
;
4511 struct screen_write_ctx ctx
;
4513 if (options_get_number(global_options
, "set-clipboard") != 0) {
4514 screen_write_start_pane(&ctx
, wp
, NULL
);
4515 screen_write_setselection(&ctx
, buf
, len
);
4516 screen_write_stop(&ctx
);
4517 notify_pane("pane-set-clipboard", wp
);
4520 paste_add(prefix
, buf
, len
);
4524 window_copy_pipe_run(struct window_mode_entry
*wme
, struct session
*s
,
4525 const char *cmd
, size_t *len
)
4530 buf
= window_copy_get_selection(wme
, len
);
4531 if (cmd
== NULL
|| *cmd
== '\0')
4532 cmd
= options_get_string(global_options
, "copy-command");
4533 if (cmd
!= NULL
&& *cmd
!= '\0') {
4534 job
= job_run(cmd
, 0, NULL
, s
, NULL
, NULL
, NULL
, NULL
, NULL
,
4535 JOB_NOWAIT
, -1, -1);
4536 bufferevent_write(job_get_event(job
), buf
, *len
);
4542 window_copy_pipe(struct window_mode_entry
*wme
, struct session
*s
,
4547 window_copy_pipe_run(wme
, s
, cmd
, &len
);
4551 window_copy_copy_pipe(struct window_mode_entry
*wme
, struct session
*s
,
4552 const char *prefix
, const char *cmd
)
4557 buf
= window_copy_pipe_run(wme
, s
, cmd
, &len
);
4559 window_copy_copy_buffer(wme
, prefix
, buf
, len
);
4563 window_copy_copy_selection(struct window_mode_entry
*wme
, const char *prefix
)
4568 buf
= window_copy_get_selection(wme
, &len
);
4570 window_copy_copy_buffer(wme
, prefix
, buf
, len
);
4574 window_copy_append_selection(struct window_mode_entry
*wme
)
4576 struct window_pane
*wp
= wme
->wp
;
4578 struct paste_buffer
*pb
;
4579 const char *bufdata
, *bufname
= NULL
;
4580 size_t len
, bufsize
;
4581 struct screen_write_ctx ctx
;
4583 buf
= window_copy_get_selection(wme
, &len
);
4587 if (options_get_number(global_options
, "set-clipboard") != 0) {
4588 screen_write_start_pane(&ctx
, wp
, NULL
);
4589 screen_write_setselection(&ctx
, buf
, len
);
4590 screen_write_stop(&ctx
);
4591 notify_pane("pane-set-clipboard", wp
);
4594 pb
= paste_get_top(&bufname
);
4596 bufdata
= paste_buffer_data(pb
, &bufsize
);
4597 buf
= xrealloc(buf
, len
+ bufsize
);
4598 memmove(buf
+ bufsize
, buf
, len
);
4599 memcpy(buf
, bufdata
, bufsize
);
4602 if (paste_set(buf
, len
, bufname
, NULL
) != 0)
4607 window_copy_copy_line(struct window_mode_entry
*wme
, char **buf
, size_t *off
,
4608 u_int sy
, u_int sx
, u_int ex
)
4610 struct window_copy_mode_data
*data
= wme
->data
;
4611 struct grid
*gd
= data
->backing
->grid
;
4612 struct grid_cell gc
;
4613 struct grid_line
*gl
;
4614 struct utf8_data ud
;
4615 u_int i
, xx
, wrapped
= 0;
4622 * Work out if the line was wrapped at the screen edge and all of it is
4625 gl
= grid_get_line(gd
, sy
);
4626 if (gl
->flags
& GRID_LINE_WRAPPED
&& gl
->cellsize
<= gd
->sx
)
4629 /* If the line was wrapped, don't strip spaces (use the full length). */
4633 xx
= window_copy_find_length(wme
, sy
);
4640 for (i
= sx
; i
< ex
; i
++) {
4641 grid_get_cell(gd
, i
, sy
, &gc
);
4642 if (gc
.flags
& GRID_FLAG_PADDING
)
4644 utf8_copy(&ud
, &gc
.data
);
4645 if (ud
.size
== 1 && (gc
.attr
& GRID_ATTR_CHARSET
)) {
4646 s
= tty_acs_get(NULL
, ud
.data
[0]);
4647 if (s
!= NULL
&& strlen(s
) <= sizeof ud
.data
) {
4648 ud
.size
= strlen(s
);
4649 memcpy(ud
.data
, s
, ud
.size
);
4653 *buf
= xrealloc(*buf
, (*off
) + ud
.size
);
4654 memcpy(*buf
+ *off
, ud
.data
, ud
.size
);
4659 /* Only add a newline if the line wasn't wrapped. */
4660 if (!wrapped
|| ex
!= xx
) {
4661 *buf
= xrealloc(*buf
, (*off
) + 1);
4662 (*buf
)[(*off
)++] = '\n';
4667 window_copy_clear_selection(struct window_mode_entry
*wme
)
4669 struct window_copy_mode_data
*data
= wme
->data
;
4672 screen_clear_selection(&data
->screen
);
4674 data
->cursordrag
= CURSORDRAG_NONE
;
4675 data
->lineflag
= LINE_SEL_NONE
;
4676 data
->selflag
= SEL_CHAR
;
4678 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4679 px
= window_copy_find_length(wme
, py
);
4681 window_copy_update_cursor(wme
, px
, data
->cy
);
4685 window_copy_in_set(struct window_mode_entry
*wme
, u_int px
, u_int py
,
4688 struct window_copy_mode_data
*data
= wme
->data
;
4689 struct grid_cell gc
;
4691 grid_get_cell(data
->backing
->grid
, px
, py
, &gc
);
4692 if (gc
.flags
& GRID_FLAG_PADDING
)
4694 return (utf8_cstrhas(set
, &gc
.data
));
4698 window_copy_find_length(struct window_mode_entry
*wme
, u_int py
)
4700 struct window_copy_mode_data
*data
= wme
->data
;
4702 return (grid_line_length(data
->backing
->grid
, py
));
4706 window_copy_cursor_start_of_line(struct window_mode_entry
*wme
)
4708 struct window_copy_mode_data
*data
= wme
->data
;
4709 struct screen
*back_s
= data
->backing
;
4710 struct grid_reader gr
;
4711 u_int px
, py
, oldy
, hsize
;
4714 hsize
= screen_hsize(back_s
);
4715 py
= hsize
+ data
->cy
- data
->oy
;
4718 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4719 grid_reader_cursor_start_of_line(&gr
, 1);
4720 grid_reader_get_cursor(&gr
, &px
, &py
);
4721 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
4725 window_copy_cursor_back_to_indentation(struct window_mode_entry
*wme
)
4727 struct window_copy_mode_data
*data
= wme
->data
;
4728 struct screen
*back_s
= data
->backing
;
4729 struct grid_reader gr
;
4730 u_int px
, py
, oldy
, hsize
;
4733 hsize
= screen_hsize(back_s
);
4734 py
= hsize
+ data
->cy
- data
->oy
;
4737 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4738 grid_reader_cursor_back_to_indentation(&gr
);
4739 grid_reader_get_cursor(&gr
, &px
, &py
);
4740 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
4744 window_copy_cursor_end_of_line(struct window_mode_entry
*wme
)
4746 struct window_copy_mode_data
*data
= wme
->data
;
4747 struct screen
*back_s
= data
->backing
;
4748 struct grid_reader gr
;
4749 u_int px
, py
, oldy
, hsize
;
4752 hsize
= screen_hsize(back_s
);
4753 py
= hsize
+ data
->cy
- data
->oy
;
4756 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4757 if (data
->screen
.sel
!= NULL
&& data
->rectflag
)
4758 grid_reader_cursor_end_of_line(&gr
, 1, 1);
4760 grid_reader_cursor_end_of_line(&gr
, 1, 0);
4761 grid_reader_get_cursor(&gr
, &px
, &py
);
4762 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
4763 data
->oy
, oldy
, px
, py
, 0);
4767 window_copy_other_end(struct window_mode_entry
*wme
)
4769 struct window_copy_mode_data
*data
= wme
->data
;
4770 struct screen
*s
= &data
->screen
;
4771 u_int selx
, sely
, cy
, yy
, hsize
;
4773 if (s
->sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
)
4776 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
4777 data
->lineflag
= LINE_SEL_RIGHT_LEFT
;
4778 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
4779 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
4781 switch (data
->cursordrag
) {
4782 case CURSORDRAG_NONE
:
4783 case CURSORDRAG_SEL
:
4784 data
->cursordrag
= CURSORDRAG_ENDSEL
;
4786 case CURSORDRAG_ENDSEL
:
4787 data
->cursordrag
= CURSORDRAG_SEL
;
4791 selx
= data
->endselx
;
4792 sely
= data
->endsely
;
4793 if (data
->cursordrag
== CURSORDRAG_SEL
) {
4799 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4803 hsize
= screen_hsize(data
->backing
);
4804 if (sely
< hsize
- data
->oy
) { /* above */
4805 data
->oy
= hsize
- sely
;
4807 } else if (sely
> hsize
- data
->oy
+ screen_size_y(s
)) { /* below */
4808 data
->oy
= hsize
- sely
+ screen_size_y(s
) - 1;
4809 data
->cy
= screen_size_y(s
) - 1;
4811 data
->cy
= cy
+ sely
- yy
;
4813 window_copy_update_selection(wme
, 1, 1);
4814 window_copy_redraw_screen(wme
);
4818 window_copy_cursor_left(struct window_mode_entry
*wme
)
4820 struct window_copy_mode_data
*data
= wme
->data
;
4821 struct screen
*back_s
= data
->backing
;
4822 struct grid_reader gr
;
4823 u_int px
, py
, oldy
, hsize
;
4826 hsize
= screen_hsize(back_s
);
4827 py
= hsize
+ data
->cy
- data
->oy
;
4830 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4831 grid_reader_cursor_left(&gr
, 1);
4832 grid_reader_get_cursor(&gr
, &px
, &py
);
4833 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
4837 window_copy_cursor_right(struct window_mode_entry
*wme
, int all
)
4839 struct window_copy_mode_data
*data
= wme
->data
;
4840 struct screen
*back_s
= data
->backing
;
4841 struct grid_reader gr
;
4842 u_int px
, py
, oldy
, hsize
;
4845 hsize
= screen_hsize(back_s
);
4846 py
= hsize
+ data
->cy
- data
->oy
;
4849 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4850 grid_reader_cursor_right(&gr
, 1, all
);
4851 grid_reader_get_cursor(&gr
, &px
, &py
);
4852 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
4853 data
->oy
, oldy
, px
, py
, 0);
4857 window_copy_cursor_up(struct window_mode_entry
*wme
, int scroll_only
)
4859 struct window_copy_mode_data
*data
= wme
->data
;
4860 struct screen
*s
= &data
->screen
;
4861 u_int ox
, oy
, px
, py
;
4864 norectsel
= data
->screen
.sel
== NULL
|| !data
->rectflag
;
4865 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4866 ox
= window_copy_find_length(wme
, oy
);
4867 if (norectsel
&& data
->cx
!= ox
) {
4868 data
->lastcx
= data
->cx
;
4872 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
&& oy
== data
->sely
)
4873 window_copy_other_end(wme
);
4875 if (scroll_only
|| data
->cy
== 0) {
4877 data
->cx
= data
->lastcx
;
4878 window_copy_scroll_down(wme
, 1);
4880 if (data
->cy
== screen_size_y(s
) - 1)
4881 window_copy_redraw_lines(wme
, data
->cy
, 1);
4883 window_copy_redraw_lines(wme
, data
->cy
, 2);
4887 window_copy_update_cursor(wme
, data
->lastcx
,
4890 window_copy_update_cursor(wme
, data
->cx
, data
->cy
- 1);
4891 if (window_copy_update_selection(wme
, 1, 0)) {
4892 if (data
->cy
== screen_size_y(s
) - 1)
4893 window_copy_redraw_lines(wme
, data
->cy
, 1);
4895 window_copy_redraw_lines(wme
, data
->cy
, 2);
4900 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4901 px
= window_copy_find_length(wme
, py
);
4902 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
4905 window_copy_update_cursor(wme
, px
, data
->cy
);
4906 if (window_copy_update_selection(wme
, 1, 0))
4907 window_copy_redraw_lines(wme
, data
->cy
, 1);
4911 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
4913 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4915 px
= screen_size_x(data
->backing
);
4917 px
= window_copy_find_length(wme
, py
);
4918 window_copy_update_cursor(wme
, px
, data
->cy
);
4919 if (window_copy_update_selection(wme
, 1, 0))
4920 window_copy_redraw_lines(wme
, data
->cy
, 1);
4922 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
4924 window_copy_update_cursor(wme
, 0, data
->cy
);
4925 if (window_copy_update_selection(wme
, 1, 0))
4926 window_copy_redraw_lines(wme
, data
->cy
, 1);
4931 window_copy_cursor_down(struct window_mode_entry
*wme
, int scroll_only
)
4933 struct window_copy_mode_data
*data
= wme
->data
;
4934 struct screen
*s
= &data
->screen
;
4935 u_int ox
, oy
, px
, py
;
4938 norectsel
= data
->screen
.sel
== NULL
|| !data
->rectflag
;
4939 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4940 ox
= window_copy_find_length(wme
, oy
);
4941 if (norectsel
&& data
->cx
!= ox
) {
4942 data
->lastcx
= data
->cx
;
4946 if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
&& oy
== data
->endsely
)
4947 window_copy_other_end(wme
);
4949 if (scroll_only
|| data
->cy
== screen_size_y(s
) - 1) {
4951 data
->cx
= data
->lastcx
;
4952 window_copy_scroll_up(wme
, 1);
4953 if (scroll_only
&& data
->cy
> 0)
4954 window_copy_redraw_lines(wme
, data
->cy
- 1, 2);
4957 window_copy_update_cursor(wme
, data
->lastcx
,
4960 window_copy_update_cursor(wme
, data
->cx
, data
->cy
+ 1);
4961 if (window_copy_update_selection(wme
, 1, 0))
4962 window_copy_redraw_lines(wme
, data
->cy
- 1, 2);
4966 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4967 px
= window_copy_find_length(wme
, py
);
4968 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
4971 window_copy_update_cursor(wme
, px
, data
->cy
);
4972 if (window_copy_update_selection(wme
, 1, 0))
4973 window_copy_redraw_lines(wme
, data
->cy
, 1);
4977 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
4979 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4981 px
= screen_size_x(data
->backing
);
4983 px
= window_copy_find_length(wme
, py
);
4984 window_copy_update_cursor(wme
, px
, data
->cy
);
4985 if (window_copy_update_selection(wme
, 1, 0))
4986 window_copy_redraw_lines(wme
, data
->cy
, 1);
4988 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
4990 window_copy_update_cursor(wme
, 0, data
->cy
);
4991 if (window_copy_update_selection(wme
, 1, 0))
4992 window_copy_redraw_lines(wme
, data
->cy
, 1);
4997 window_copy_cursor_jump(struct window_mode_entry
*wme
)
4999 struct window_copy_mode_data
*data
= wme
->data
;
5000 struct screen
*back_s
= data
->backing
;
5001 struct grid_reader gr
;
5002 u_int px
, py
, oldy
, hsize
;
5005 hsize
= screen_hsize(back_s
);
5006 py
= hsize
+ data
->cy
- data
->oy
;
5009 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5010 if (grid_reader_cursor_jump(&gr
, data
->jumpchar
)) {
5011 grid_reader_get_cursor(&gr
, &px
, &py
);
5012 window_copy_acquire_cursor_down(wme
, hsize
,
5013 screen_size_y(back_s
), data
->oy
, oldy
, px
, py
, 0);
5018 window_copy_cursor_jump_back(struct window_mode_entry
*wme
)
5020 struct window_copy_mode_data
*data
= wme
->data
;
5021 struct screen
*back_s
= data
->backing
;
5022 struct grid_reader gr
;
5023 u_int px
, py
, oldy
, hsize
;
5026 hsize
= screen_hsize(back_s
);
5027 py
= hsize
+ data
->cy
- data
->oy
;
5030 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5031 grid_reader_cursor_left(&gr
, 0);
5032 if (grid_reader_cursor_jump_back(&gr
, data
->jumpchar
)) {
5033 grid_reader_get_cursor(&gr
, &px
, &py
);
5034 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
,
5040 window_copy_cursor_jump_to(struct window_mode_entry
*wme
)
5042 struct window_copy_mode_data
*data
= wme
->data
;
5043 struct screen
*back_s
= data
->backing
;
5044 struct grid_reader gr
;
5045 u_int px
, py
, oldy
, hsize
;
5048 hsize
= screen_hsize(back_s
);
5049 py
= hsize
+ data
->cy
- data
->oy
;
5052 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5053 if (grid_reader_cursor_jump(&gr
, data
->jumpchar
)) {
5054 grid_reader_cursor_left(&gr
, 1);
5055 grid_reader_get_cursor(&gr
, &px
, &py
);
5056 window_copy_acquire_cursor_down(wme
, hsize
,
5057 screen_size_y(back_s
), data
->oy
, oldy
, px
, py
, 0);
5062 window_copy_cursor_jump_to_back(struct window_mode_entry
*wme
)
5064 struct window_copy_mode_data
*data
= wme
->data
;
5065 struct screen
*back_s
= data
->backing
;
5066 struct grid_reader gr
;
5067 u_int px
, py
, oldy
, hsize
;
5070 hsize
= screen_hsize(back_s
);
5071 py
= hsize
+ data
->cy
- data
->oy
;
5074 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5075 grid_reader_cursor_left(&gr
, 0);
5076 grid_reader_cursor_left(&gr
, 0);
5077 if (grid_reader_cursor_jump_back(&gr
, data
->jumpchar
)) {
5078 grid_reader_cursor_right(&gr
, 1, 0);
5079 grid_reader_get_cursor(&gr
, &px
, &py
);
5080 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
,
5086 window_copy_cursor_next_word(struct window_mode_entry
*wme
,
5087 const char *separators
)
5089 struct window_copy_mode_data
*data
= wme
->data
;
5090 struct screen
*back_s
= data
->backing
;
5091 struct grid_reader gr
;
5092 u_int px
, py
, oldy
, hsize
;
5095 hsize
= screen_hsize(back_s
);
5096 py
= hsize
+ data
->cy
- data
->oy
;
5099 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5100 grid_reader_cursor_next_word(&gr
, separators
);
5101 grid_reader_get_cursor(&gr
, &px
, &py
);
5102 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
5103 data
->oy
, oldy
, px
, py
, 0);
5106 /* Compute the next place where a word ends. */
5108 window_copy_cursor_next_word_end_pos(struct window_mode_entry
*wme
,
5109 const char *separators
, u_int
*ppx
, u_int
*ppy
)
5111 struct window_pane
*wp
= wme
->wp
;
5112 struct window_copy_mode_data
*data
= wme
->data
;
5113 struct options
*oo
= wp
->window
->options
;
5114 struct screen
*back_s
= data
->backing
;
5115 struct grid_reader gr
;
5116 u_int px
, py
, hsize
;
5119 hsize
= screen_hsize(back_s
);
5120 py
= hsize
+ data
->cy
- data
->oy
;
5122 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5123 if (options_get_number(oo
, "mode-keys") == MODEKEY_VI
) {
5124 if (!grid_reader_in_set(&gr
, WHITESPACE
))
5125 grid_reader_cursor_right(&gr
, 0, 0);
5126 grid_reader_cursor_next_word_end(&gr
, separators
);
5127 grid_reader_cursor_left(&gr
, 1);
5129 grid_reader_cursor_next_word_end(&gr
, separators
);
5130 grid_reader_get_cursor(&gr
, &px
, &py
);
5135 /* Move to the next place where a word ends. */
5137 window_copy_cursor_next_word_end(struct window_mode_entry
*wme
,
5138 const char *separators
, int no_reset
)
5140 struct window_pane
*wp
= wme
->wp
;
5141 struct window_copy_mode_data
*data
= wme
->data
;
5142 struct options
*oo
= wp
->window
->options
;
5143 struct screen
*back_s
= data
->backing
;
5144 struct grid_reader gr
;
5145 u_int px
, py
, oldy
, hsize
;
5148 hsize
= screen_hsize(back_s
);
5149 py
= hsize
+ data
->cy
- data
->oy
;
5152 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5153 if (options_get_number(oo
, "mode-keys") == MODEKEY_VI
) {
5154 if (!grid_reader_in_set(&gr
, WHITESPACE
))
5155 grid_reader_cursor_right(&gr
, 0, 0);
5156 grid_reader_cursor_next_word_end(&gr
, separators
);
5157 grid_reader_cursor_left(&gr
, 1);
5159 grid_reader_cursor_next_word_end(&gr
, separators
);
5160 grid_reader_get_cursor(&gr
, &px
, &py
);
5161 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
5162 data
->oy
, oldy
, px
, py
, no_reset
);
5165 /* Compute the previous place where a word begins. */
5167 window_copy_cursor_previous_word_pos(struct window_mode_entry
*wme
,
5168 const char *separators
, u_int
*ppx
, u_int
*ppy
)
5170 struct window_copy_mode_data
*data
= wme
->data
;
5171 struct screen
*back_s
= data
->backing
;
5172 struct grid_reader gr
;
5173 u_int px
, py
, hsize
;
5176 hsize
= screen_hsize(back_s
);
5177 py
= hsize
+ data
->cy
- data
->oy
;
5179 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5180 grid_reader_cursor_previous_word(&gr
, separators
, /* already= */ 0,
5181 /* stop_at_eol= */ 1);
5182 grid_reader_get_cursor(&gr
, &px
, &py
);
5187 /* Move to the previous place where a word begins. */
5189 window_copy_cursor_previous_word(struct window_mode_entry
*wme
,
5190 const char *separators
, int already
)
5192 struct window_copy_mode_data
*data
= wme
->data
;
5193 struct window
*w
= wme
->wp
->window
;
5194 struct screen
*back_s
= data
->backing
;
5195 struct grid_reader gr
;
5196 u_int px
, py
, oldy
, hsize
;
5199 if (options_get_number(w
->options
, "mode-keys") == MODEKEY_EMACS
)
5205 hsize
= screen_hsize(back_s
);
5206 py
= hsize
+ data
->cy
- data
->oy
;
5209 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5210 grid_reader_cursor_previous_word(&gr
, separators
, already
, stop_at_eol
);
5211 grid_reader_get_cursor(&gr
, &px
, &py
);
5212 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
5216 window_copy_scroll_up(struct window_mode_entry
*wme
, u_int ny
)
5218 struct window_pane
*wp
= wme
->wp
;
5219 struct window_copy_mode_data
*data
= wme
->data
;
5220 struct screen
*s
= &data
->screen
;
5221 struct screen_write_ctx ctx
;
5229 if (data
->searchmark
!= NULL
&& !data
->timeout
)
5230 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
5231 window_copy_update_selection(wme
, 0, 0);
5233 screen_write_start_pane(&ctx
, wp
, NULL
);
5234 screen_write_cursormove(&ctx
, 0, 0, 0);
5235 screen_write_deleteline(&ctx
, ny
, 8);
5236 window_copy_write_lines(wme
, &ctx
, screen_size_y(s
) - ny
, ny
);
5237 window_copy_write_line(wme
, &ctx
, 0);
5238 if (screen_size_y(s
) > 1)
5239 window_copy_write_line(wme
, &ctx
, 1);
5240 if (screen_size_y(s
) > 3)
5241 window_copy_write_line(wme
, &ctx
, screen_size_y(s
) - 2);
5242 if (s
->sel
!= NULL
&& screen_size_y(s
) > ny
)
5243 window_copy_write_line(wme
, &ctx
, screen_size_y(s
) - ny
- 1);
5244 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
5245 screen_write_stop(&ctx
);
5249 window_copy_scroll_down(struct window_mode_entry
*wme
, u_int ny
)
5251 struct window_pane
*wp
= wme
->wp
;
5252 struct window_copy_mode_data
*data
= wme
->data
;
5253 struct screen
*s
= &data
->screen
;
5254 struct screen_write_ctx ctx
;
5256 if (ny
> screen_hsize(data
->backing
))
5259 if (data
->oy
> screen_hsize(data
->backing
) - ny
)
5260 ny
= screen_hsize(data
->backing
) - data
->oy
;
5265 if (data
->searchmark
!= NULL
&& !data
->timeout
)
5266 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
5267 window_copy_update_selection(wme
, 0, 0);
5269 screen_write_start_pane(&ctx
, wp
, NULL
);
5270 screen_write_cursormove(&ctx
, 0, 0, 0);
5271 screen_write_insertline(&ctx
, ny
, 8);
5272 window_copy_write_lines(wme
, &ctx
, 0, ny
);
5273 if (s
->sel
!= NULL
&& screen_size_y(s
) > ny
)
5274 window_copy_write_line(wme
, &ctx
, ny
);
5275 else if (ny
== 1) /* nuke position */
5276 window_copy_write_line(wme
, &ctx
, 1);
5277 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
5278 screen_write_stop(&ctx
);
5282 window_copy_rectangle_set(struct window_mode_entry
*wme
, int rectflag
)
5284 struct window_copy_mode_data
*data
= wme
->data
;
5287 data
->rectflag
= rectflag
;
5289 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5290 px
= window_copy_find_length(wme
, py
);
5292 window_copy_update_cursor(wme
, px
, data
->cy
);
5294 window_copy_update_selection(wme
, 1, 0);
5295 window_copy_redraw_screen(wme
);
5299 window_copy_move_mouse(struct mouse_event
*m
)
5301 struct window_pane
*wp
;
5302 struct window_mode_entry
*wme
;
5305 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5308 wme
= TAILQ_FIRST(&wp
->modes
);
5311 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5314 if (cmd_mouse_at(wp
, m
, &x
, &y
, 0) != 0)
5317 window_copy_update_cursor(wme
, x
, y
);
5321 window_copy_start_drag(struct client
*c
, struct mouse_event
*m
)
5323 struct window_pane
*wp
;
5324 struct window_mode_entry
*wme
;
5325 struct window_copy_mode_data
*data
;
5331 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5334 wme
= TAILQ_FIRST(&wp
->modes
);
5337 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5340 if (cmd_mouse_at(wp
, m
, &x
, &y
, 1) != 0)
5343 c
->tty
.mouse_drag_update
= window_copy_drag_update
;
5344 c
->tty
.mouse_drag_release
= window_copy_drag_release
;
5347 yg
= screen_hsize(data
->backing
) + y
- data
->oy
;
5348 if (x
< data
->selrx
|| x
> data
->endselrx
|| yg
!= data
->selry
)
5349 data
->selflag
= SEL_CHAR
;
5350 switch (data
->selflag
) {
5352 if (data
->separators
!= NULL
) {
5353 window_copy_update_cursor(wme
, x
, y
);
5354 window_copy_cursor_previous_word_pos(wme
,
5355 data
->separators
, &x
, &y
);
5356 y
-= screen_hsize(data
->backing
) - data
->oy
;
5358 window_copy_update_cursor(wme
, x
, y
);
5361 window_copy_update_cursor(wme
, 0, y
);
5364 window_copy_update_cursor(wme
, x
, y
);
5365 window_copy_start_selection(wme
);
5369 window_copy_redraw_screen(wme
);
5370 window_copy_drag_update(c
, m
);
5374 window_copy_drag_update(struct client
*c
, struct mouse_event
*m
)
5376 struct window_pane
*wp
;
5377 struct window_mode_entry
*wme
;
5378 struct window_copy_mode_data
*data
;
5379 u_int x
, y
, old_cx
, old_cy
;
5380 struct timeval tv
= {
5381 .tv_usec
= WINDOW_COPY_DRAG_REPEAT_TIME
5387 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5390 wme
= TAILQ_FIRST(&wp
->modes
);
5393 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5397 evtimer_del(&data
->dragtimer
);
5399 if (cmd_mouse_at(wp
, m
, &x
, &y
, 0) != 0)
5404 window_copy_update_cursor(wme
, x
, y
);
5405 if (window_copy_update_selection(wme
, 1, 0))
5406 window_copy_redraw_selection(wme
, old_cy
);
5407 if (old_cy
!= data
->cy
|| old_cx
== data
->cx
) {
5409 evtimer_add(&data
->dragtimer
, &tv
);
5410 window_copy_cursor_up(wme
, 1);
5411 } else if (y
== screen_size_y(&data
->screen
) - 1) {
5412 evtimer_add(&data
->dragtimer
, &tv
);
5413 window_copy_cursor_down(wme
, 1);
5419 window_copy_drag_release(struct client
*c
, struct mouse_event
*m
)
5421 struct window_pane
*wp
;
5422 struct window_mode_entry
*wme
;
5423 struct window_copy_mode_data
*data
;
5428 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5431 wme
= TAILQ_FIRST(&wp
->modes
);
5434 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5438 evtimer_del(&data
->dragtimer
);
5442 window_copy_jump_to_mark(struct window_mode_entry
*wme
)
5444 struct window_copy_mode_data
*data
= wme
->data
;
5448 tmy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5449 data
->cx
= data
->mx
;
5450 if (data
->my
< screen_hsize(data
->backing
)) {
5452 data
->oy
= screen_hsize(data
->backing
) - data
->my
;
5454 data
->cy
= data
->my
- screen_hsize(data
->backing
);
5460 window_copy_update_selection(wme
, 0, 0);
5461 window_copy_redraw_screen(wme
);
5464 /* Scroll up if the cursor went off the visible screen. */
5466 window_copy_acquire_cursor_up(struct window_mode_entry
*wme
, u_int hsize
,
5467 u_int oy
, u_int oldy
, u_int px
, u_int py
)
5469 u_int cy
, yy
, ny
, nd
;
5482 window_copy_cursor_up(wme
, 1);
5485 window_copy_update_cursor(wme
, px
, cy
);
5486 if (window_copy_update_selection(wme
, 1, 0))
5487 window_copy_redraw_lines(wme
, cy
, nd
);
5490 /* Scroll down if the cursor went off the visible screen. */
5492 window_copy_acquire_cursor_down(struct window_mode_entry
*wme
, u_int hsize
,
5493 u_int sy
, u_int oy
, u_int oldy
, u_int px
, u_int py
, int no_reset
)
5495 u_int cy
, yy
, ny
, nd
;
5497 cy
= py
- hsize
+ oy
;
5508 window_copy_cursor_down(wme
, 1);
5512 window_copy_update_cursor(wme
, px
, yy
);
5514 window_copy_update_cursor(wme
, px
, cy
);
5515 if (window_copy_update_selection(wme
, 1, no_reset
))
5516 window_copy_redraw_lines(wme
, oldy
, nd
);