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_toggle_position(struct window_copy_cmd_state
*cs
)
1278 struct window_mode_entry
*wme
= cs
->wme
;
1279 struct window_copy_mode_data
*data
= wme
->data
;
1281 data
->hide_position
= !data
->hide_position
;
1282 return (WINDOW_COPY_CMD_REDRAW
);
1285 static enum window_copy_cmd_action
1286 window_copy_cmd_history_bottom(struct window_copy_cmd_state
*cs
)
1288 struct window_mode_entry
*wme
= cs
->wme
;
1289 struct window_copy_mode_data
*data
= wme
->data
;
1290 struct screen
*s
= data
->backing
;
1293 oy
= screen_hsize(s
) + data
->cy
- data
->oy
;
1294 if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
&& oy
== data
->endsely
)
1295 window_copy_other_end(wme
);
1297 data
->cy
= screen_size_y(&data
->screen
) - 1;
1298 data
->cx
= window_copy_find_length(wme
, screen_hsize(s
) + data
->cy
);
1301 if (data
->searchmark
!= NULL
&& !data
->timeout
)
1302 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
1303 window_copy_update_selection(wme
, 1, 0);
1304 return (WINDOW_COPY_CMD_REDRAW
);
1307 static enum window_copy_cmd_action
1308 window_copy_cmd_history_top(struct window_copy_cmd_state
*cs
)
1310 struct window_mode_entry
*wme
= cs
->wme
;
1311 struct window_copy_mode_data
*data
= wme
->data
;
1314 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1315 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
&& oy
== data
->sely
)
1316 window_copy_other_end(wme
);
1320 data
->oy
= screen_hsize(data
->backing
);
1322 if (data
->searchmark
!= NULL
&& !data
->timeout
)
1323 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
1324 window_copy_update_selection(wme
, 1, 0);
1325 return (WINDOW_COPY_CMD_REDRAW
);
1328 static enum window_copy_cmd_action
1329 window_copy_cmd_jump_again(struct window_copy_cmd_state
*cs
)
1331 struct window_mode_entry
*wme
= cs
->wme
;
1332 struct window_copy_mode_data
*data
= wme
->data
;
1333 u_int np
= wme
->prefix
;
1335 switch (data
->jumptype
) {
1336 case WINDOW_COPY_JUMPFORWARD
:
1337 for (; np
!= 0; np
--)
1338 window_copy_cursor_jump(wme
);
1340 case WINDOW_COPY_JUMPBACKWARD
:
1341 for (; np
!= 0; np
--)
1342 window_copy_cursor_jump_back(wme
);
1344 case WINDOW_COPY_JUMPTOFORWARD
:
1345 for (; np
!= 0; np
--)
1346 window_copy_cursor_jump_to(wme
);
1348 case WINDOW_COPY_JUMPTOBACKWARD
:
1349 for (; np
!= 0; np
--)
1350 window_copy_cursor_jump_to_back(wme
);
1353 return (WINDOW_COPY_CMD_NOTHING
);
1356 static enum window_copy_cmd_action
1357 window_copy_cmd_jump_reverse(struct window_copy_cmd_state
*cs
)
1359 struct window_mode_entry
*wme
= cs
->wme
;
1360 struct window_copy_mode_data
*data
= wme
->data
;
1361 u_int np
= wme
->prefix
;
1363 switch (data
->jumptype
) {
1364 case WINDOW_COPY_JUMPFORWARD
:
1365 for (; np
!= 0; np
--)
1366 window_copy_cursor_jump_back(wme
);
1368 case WINDOW_COPY_JUMPBACKWARD
:
1369 for (; np
!= 0; np
--)
1370 window_copy_cursor_jump(wme
);
1372 case WINDOW_COPY_JUMPTOFORWARD
:
1373 for (; np
!= 0; np
--)
1374 window_copy_cursor_jump_to_back(wme
);
1376 case WINDOW_COPY_JUMPTOBACKWARD
:
1377 for (; np
!= 0; np
--)
1378 window_copy_cursor_jump_to(wme
);
1381 return (WINDOW_COPY_CMD_NOTHING
);
1384 static enum window_copy_cmd_action
1385 window_copy_cmd_middle_line(struct window_copy_cmd_state
*cs
)
1387 struct window_mode_entry
*wme
= cs
->wme
;
1388 struct window_copy_mode_data
*data
= wme
->data
;
1391 data
->cy
= (screen_size_y(&data
->screen
) - 1) / 2;
1393 window_copy_update_selection(wme
, 1, 0);
1394 return (WINDOW_COPY_CMD_REDRAW
);
1397 static enum window_copy_cmd_action
1398 window_copy_cmd_previous_matching_bracket(struct window_copy_cmd_state
*cs
)
1400 struct window_mode_entry
*wme
= cs
->wme
;
1401 u_int np
= wme
->prefix
;
1402 struct window_copy_mode_data
*data
= wme
->data
;
1403 struct screen
*s
= data
->backing
;
1404 char open
[] = "{[(", close
[] = "}])";
1405 char tried
, found
, start
, *cp
;
1406 u_int px
, py
, xx
, n
;
1407 struct grid_cell gc
;
1410 for (; np
!= 0; np
--) {
1411 /* Get cursor position and line length. */
1413 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1414 xx
= window_copy_find_length(wme
, py
);
1419 * Get the current character. If not on a bracket, try the
1420 * previous. If still not, then behave like previous-word.
1424 grid_get_cell(s
->grid
, px
, py
, &gc
);
1425 if (gc
.data
.size
!= 1 || (gc
.flags
& GRID_FLAG_PADDING
))
1428 found
= *gc
.data
.data
;
1429 cp
= strchr(close
, found
);
1432 if (data
->modekeys
== MODEKEY_EMACS
) {
1433 if (!tried
&& px
> 0) {
1438 window_copy_cursor_previous_word(wme
, close
, 1);
1442 start
= open
[cp
- close
];
1444 /* Walk backward until the matching bracket is reached. */
1455 xx
= window_copy_find_length(wme
, py
);
1456 } while (xx
== 0 && py
> 0);
1457 if (xx
== 0 && py
== 0) {
1465 grid_get_cell(s
->grid
, px
, py
, &gc
);
1466 if (gc
.data
.size
== 1 &&
1467 (~gc
.flags
& GRID_FLAG_PADDING
)) {
1468 if (*gc
.data
.data
== found
)
1470 else if (*gc
.data
.data
== start
)
1475 /* Move the cursor to the found location if any. */
1477 window_copy_scroll_to(wme
, px
, py
, 0);
1480 return (WINDOW_COPY_CMD_NOTHING
);
1483 static enum window_copy_cmd_action
1484 window_copy_cmd_next_matching_bracket(struct window_copy_cmd_state
*cs
)
1486 struct window_mode_entry
*wme
= cs
->wme
;
1487 u_int np
= wme
->prefix
;
1488 struct window_copy_mode_data
*data
= wme
->data
;
1489 struct screen
*s
= data
->backing
;
1490 char open
[] = "{[(", close
[] = "}])";
1491 char tried
, found
, end
, *cp
;
1492 u_int px
, py
, xx
, yy
, sx
, sy
, n
;
1493 struct grid_cell gc
;
1495 struct grid_line
*gl
;
1497 for (; np
!= 0; np
--) {
1498 /* Get cursor position and line length. */
1500 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1501 xx
= window_copy_find_length(wme
, py
);
1502 yy
= screen_hsize(s
) + screen_size_y(s
) - 1;
1507 * Get the current character. If not on a bracket, try the
1508 * next. If still not, then behave like next-word.
1512 grid_get_cell(s
->grid
, px
, py
, &gc
);
1513 if (gc
.data
.size
!= 1 || (gc
.flags
& GRID_FLAG_PADDING
))
1516 found
= *gc
.data
.data
;
1519 * In vi mode, attempt to move to previous bracket if a
1520 * closing bracket is found first. If this fails,
1521 * return to the original cursor position.
1523 cp
= strchr(close
, found
);
1524 if (cp
!= NULL
&& data
->modekeys
== MODEKEY_VI
) {
1526 sy
= screen_hsize(s
) + data
->cy
- data
->oy
;
1528 window_copy_scroll_to(wme
, px
, py
, 0);
1529 window_copy_cmd_previous_matching_bracket(cs
);
1532 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1533 grid_get_cell(s
->grid
, px
, py
, &gc
);
1534 if (gc
.data
.size
== 1 &&
1535 (~gc
.flags
& GRID_FLAG_PADDING
) &&
1536 strchr(close
, *gc
.data
.data
) != NULL
)
1537 window_copy_scroll_to(wme
, sx
, sy
, 0);
1541 cp
= strchr(open
, found
);
1544 if (data
->modekeys
== MODEKEY_EMACS
) {
1545 if (!tried
&& px
<= xx
) {
1550 window_copy_cursor_next_word_end(wme
, open
, 0);
1553 /* For vi, continue searching for bracket until EOL. */
1557 gl
= grid_get_line(s
->grid
, py
);
1558 if (~gl
->flags
& GRID_LINE_WRAPPED
)
1560 if (gl
->cellsize
> s
->grid
->sx
)
1564 xx
= window_copy_find_length(wme
, py
);
1569 end
= close
[cp
- open
];
1571 /* Walk forward until the matching bracket is reached. */
1582 xx
= window_copy_find_length(wme
, py
);
1586 grid_get_cell(s
->grid
, px
, py
, &gc
);
1587 if (gc
.data
.size
== 1 &&
1588 (~gc
.flags
& GRID_FLAG_PADDING
)) {
1589 if (*gc
.data
.data
== found
)
1591 else if (*gc
.data
.data
== end
)
1596 /* Move the cursor to the found location if any. */
1598 window_copy_scroll_to(wme
, px
, py
, 0);
1601 return (WINDOW_COPY_CMD_NOTHING
);
1604 static enum window_copy_cmd_action
1605 window_copy_cmd_next_paragraph(struct window_copy_cmd_state
*cs
)
1607 struct window_mode_entry
*wme
= cs
->wme
;
1608 u_int np
= wme
->prefix
;
1610 for (; np
!= 0; np
--)
1611 window_copy_next_paragraph(wme
);
1612 return (WINDOW_COPY_CMD_NOTHING
);
1615 static enum window_copy_cmd_action
1616 window_copy_cmd_next_space(struct window_copy_cmd_state
*cs
)
1618 struct window_mode_entry
*wme
= cs
->wme
;
1619 u_int np
= wme
->prefix
;
1621 for (; np
!= 0; np
--)
1622 window_copy_cursor_next_word(wme
, "");
1623 return (WINDOW_COPY_CMD_NOTHING
);
1626 static enum window_copy_cmd_action
1627 window_copy_cmd_next_space_end(struct window_copy_cmd_state
*cs
)
1629 struct window_mode_entry
*wme
= cs
->wme
;
1630 u_int np
= wme
->prefix
;
1632 for (; np
!= 0; np
--)
1633 window_copy_cursor_next_word_end(wme
, "", 0);
1634 return (WINDOW_COPY_CMD_NOTHING
);
1637 static enum window_copy_cmd_action
1638 window_copy_cmd_next_word(struct window_copy_cmd_state
*cs
)
1640 struct window_mode_entry
*wme
= cs
->wme
;
1641 u_int np
= wme
->prefix
;
1642 const char *separators
;
1644 separators
= options_get_string(cs
->s
->options
, "word-separators");
1646 for (; np
!= 0; np
--)
1647 window_copy_cursor_next_word(wme
, separators
);
1648 return (WINDOW_COPY_CMD_NOTHING
);
1651 static enum window_copy_cmd_action
1652 window_copy_cmd_next_word_end(struct window_copy_cmd_state
*cs
)
1654 struct window_mode_entry
*wme
= cs
->wme
;
1655 u_int np
= wme
->prefix
;
1656 const char *separators
;
1658 separators
= options_get_string(cs
->s
->options
, "word-separators");
1660 for (; np
!= 0; np
--)
1661 window_copy_cursor_next_word_end(wme
, separators
, 0);
1662 return (WINDOW_COPY_CMD_NOTHING
);
1665 static enum window_copy_cmd_action
1666 window_copy_cmd_other_end(struct window_copy_cmd_state
*cs
)
1668 struct window_mode_entry
*wme
= cs
->wme
;
1669 u_int np
= wme
->prefix
;
1670 struct window_copy_mode_data
*data
= wme
->data
;
1672 data
->selflag
= SEL_CHAR
;
1674 window_copy_other_end(wme
);
1675 return (WINDOW_COPY_CMD_NOTHING
);
1678 static enum window_copy_cmd_action
1679 window_copy_cmd_page_down(struct window_copy_cmd_state
*cs
)
1681 struct window_mode_entry
*wme
= cs
->wme
;
1682 struct window_copy_mode_data
*data
= wme
->data
;
1683 u_int np
= wme
->prefix
;
1685 for (; np
!= 0; np
--) {
1686 if (window_copy_pagedown(wme
, 0, data
->scroll_exit
))
1687 return (WINDOW_COPY_CMD_CANCEL
);
1689 return (WINDOW_COPY_CMD_NOTHING
);
1692 static enum window_copy_cmd_action
1693 window_copy_cmd_page_down_and_cancel(struct window_copy_cmd_state
*cs
)
1695 struct window_mode_entry
*wme
= cs
->wme
;
1696 u_int np
= wme
->prefix
;
1698 for (; np
!= 0; np
--) {
1699 if (window_copy_pagedown(wme
, 0, 1))
1700 return (WINDOW_COPY_CMD_CANCEL
);
1702 return (WINDOW_COPY_CMD_NOTHING
);
1705 static enum window_copy_cmd_action
1706 window_copy_cmd_page_up(struct window_copy_cmd_state
*cs
)
1708 struct window_mode_entry
*wme
= cs
->wme
;
1709 u_int np
= wme
->prefix
;
1711 for (; np
!= 0; np
--)
1712 window_copy_pageup1(wme
, 0);
1713 return (WINDOW_COPY_CMD_NOTHING
);
1716 static enum window_copy_cmd_action
1717 window_copy_cmd_previous_paragraph(struct window_copy_cmd_state
*cs
)
1719 struct window_mode_entry
*wme
= cs
->wme
;
1720 u_int np
= wme
->prefix
;
1722 for (; np
!= 0; np
--)
1723 window_copy_previous_paragraph(wme
);
1724 return (WINDOW_COPY_CMD_NOTHING
);
1727 static enum window_copy_cmd_action
1728 window_copy_cmd_previous_space(struct window_copy_cmd_state
*cs
)
1730 struct window_mode_entry
*wme
= cs
->wme
;
1731 u_int np
= wme
->prefix
;
1733 for (; np
!= 0; np
--)
1734 window_copy_cursor_previous_word(wme
, "", 1);
1735 return (WINDOW_COPY_CMD_NOTHING
);
1738 static enum window_copy_cmd_action
1739 window_copy_cmd_previous_word(struct window_copy_cmd_state
*cs
)
1741 struct window_mode_entry
*wme
= cs
->wme
;
1742 u_int np
= wme
->prefix
;
1743 const char *separators
;
1745 separators
= options_get_string(cs
->s
->options
, "word-separators");
1747 for (; np
!= 0; np
--)
1748 window_copy_cursor_previous_word(wme
, separators
, 1);
1749 return (WINDOW_COPY_CMD_NOTHING
);
1752 static enum window_copy_cmd_action
1753 window_copy_cmd_rectangle_on(struct window_copy_cmd_state
*cs
)
1755 struct window_mode_entry
*wme
= cs
->wme
;
1756 struct window_copy_mode_data
*data
= wme
->data
;
1758 data
->lineflag
= LINE_SEL_NONE
;
1759 window_copy_rectangle_set(wme
, 1);
1761 return (WINDOW_COPY_CMD_NOTHING
);
1764 static enum window_copy_cmd_action
1765 window_copy_cmd_rectangle_off(struct window_copy_cmd_state
*cs
)
1767 struct window_mode_entry
*wme
= cs
->wme
;
1768 struct window_copy_mode_data
*data
= wme
->data
;
1770 data
->lineflag
= LINE_SEL_NONE
;
1771 window_copy_rectangle_set(wme
, 0);
1773 return (WINDOW_COPY_CMD_NOTHING
);
1776 static enum window_copy_cmd_action
1777 window_copy_cmd_rectangle_toggle(struct window_copy_cmd_state
*cs
)
1779 struct window_mode_entry
*wme
= cs
->wme
;
1780 struct window_copy_mode_data
*data
= wme
->data
;
1782 data
->lineflag
= LINE_SEL_NONE
;
1783 window_copy_rectangle_set(wme
, !data
->rectflag
);
1785 return (WINDOW_COPY_CMD_NOTHING
);
1788 static enum window_copy_cmd_action
1789 window_copy_cmd_scroll_down(struct window_copy_cmd_state
*cs
)
1791 struct window_mode_entry
*wme
= cs
->wme
;
1792 struct window_copy_mode_data
*data
= wme
->data
;
1793 u_int np
= wme
->prefix
;
1795 for (; np
!= 0; np
--)
1796 window_copy_cursor_down(wme
, 1);
1797 if (data
->scroll_exit
&& data
->oy
== 0)
1798 return (WINDOW_COPY_CMD_CANCEL
);
1799 return (WINDOW_COPY_CMD_NOTHING
);
1802 static enum window_copy_cmd_action
1803 window_copy_cmd_scroll_down_and_cancel(struct window_copy_cmd_state
*cs
)
1805 struct window_mode_entry
*wme
= cs
->wme
;
1806 struct window_copy_mode_data
*data
= wme
->data
;
1807 u_int np
= wme
->prefix
;
1809 for (; np
!= 0; np
--)
1810 window_copy_cursor_down(wme
, 1);
1812 return (WINDOW_COPY_CMD_CANCEL
);
1813 return (WINDOW_COPY_CMD_NOTHING
);
1816 static enum window_copy_cmd_action
1817 window_copy_cmd_scroll_up(struct window_copy_cmd_state
*cs
)
1819 struct window_mode_entry
*wme
= cs
->wme
;
1820 u_int np
= wme
->prefix
;
1822 for (; np
!= 0; np
--)
1823 window_copy_cursor_up(wme
, 1);
1824 return (WINDOW_COPY_CMD_NOTHING
);
1827 static enum window_copy_cmd_action
1828 window_copy_cmd_search_again(struct window_copy_cmd_state
*cs
)
1830 struct window_mode_entry
*wme
= cs
->wme
;
1831 struct window_copy_mode_data
*data
= wme
->data
;
1832 u_int np
= wme
->prefix
;
1834 if (data
->searchtype
== WINDOW_COPY_SEARCHUP
) {
1835 for (; np
!= 0; np
--)
1836 window_copy_search_up(wme
, data
->searchregex
);
1837 } else if (data
->searchtype
== WINDOW_COPY_SEARCHDOWN
) {
1838 for (; np
!= 0; np
--)
1839 window_copy_search_down(wme
, data
->searchregex
);
1841 return (WINDOW_COPY_CMD_NOTHING
);
1844 static enum window_copy_cmd_action
1845 window_copy_cmd_search_reverse(struct window_copy_cmd_state
*cs
)
1847 struct window_mode_entry
*wme
= cs
->wme
;
1848 struct window_copy_mode_data
*data
= wme
->data
;
1849 u_int np
= wme
->prefix
;
1851 if (data
->searchtype
== WINDOW_COPY_SEARCHUP
) {
1852 for (; np
!= 0; np
--)
1853 window_copy_search_down(wme
, data
->searchregex
);
1854 } else if (data
->searchtype
== WINDOW_COPY_SEARCHDOWN
) {
1855 for (; np
!= 0; np
--)
1856 window_copy_search_up(wme
, data
->searchregex
);
1858 return (WINDOW_COPY_CMD_NOTHING
);
1861 static enum window_copy_cmd_action
1862 window_copy_cmd_select_line(struct window_copy_cmd_state
*cs
)
1864 struct window_mode_entry
*wme
= cs
->wme
;
1865 struct window_copy_mode_data
*data
= wme
->data
;
1866 u_int np
= wme
->prefix
;
1868 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
1870 data
->selflag
= SEL_LINE
;
1871 data
->dx
= data
->cx
;
1872 data
->dy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1874 window_copy_cursor_start_of_line(wme
);
1875 data
->selrx
= data
->cx
;
1876 data
->selry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1877 data
->endselry
= data
->selry
;
1878 window_copy_start_selection(wme
);
1879 window_copy_cursor_end_of_line(wme
);
1880 data
->endselry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1881 data
->endselrx
= window_copy_find_length(wme
, data
->endselry
);
1882 for (; np
> 1; np
--) {
1883 window_copy_cursor_down(wme
, 0);
1884 window_copy_cursor_end_of_line(wme
);
1887 return (WINDOW_COPY_CMD_REDRAW
);
1890 static enum window_copy_cmd_action
1891 window_copy_cmd_select_word(struct window_copy_cmd_state
*cs
)
1893 struct window_mode_entry
*wme
= cs
->wme
;
1894 struct options
*session_options
= cs
->s
->options
;
1895 struct window_copy_mode_data
*data
= wme
->data
;
1896 u_int px
, py
, nextx
, nexty
;
1898 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
1900 data
->selflag
= SEL_WORD
;
1901 data
->dx
= data
->cx
;
1902 data
->dy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1904 data
->separators
= options_get_string(session_options
,
1906 window_copy_cursor_previous_word(wme
, data
->separators
, 0);
1908 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1911 window_copy_start_selection(wme
);
1913 /* Handle single character words. */
1916 if (grid_get_line(data
->backing
->grid
, nexty
)->flags
&
1917 GRID_LINE_WRAPPED
&& nextx
> screen_size_x(data
->backing
) - 1) {
1921 if (px
>= window_copy_find_length(wme
, py
) ||
1922 !window_copy_in_set(wme
, nextx
, nexty
, WHITESPACE
))
1923 window_copy_cursor_next_word_end(wme
, data
->separators
, 1);
1925 window_copy_update_cursor(wme
, px
, data
->cy
);
1926 if (window_copy_update_selection(wme
, 1, 1))
1927 window_copy_redraw_lines(wme
, data
->cy
, 1);
1929 data
->endselrx
= data
->cx
;
1930 data
->endselry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1931 if (data
->dy
> data
->endselry
) {
1932 data
->dy
= data
->endselry
;
1933 data
->dx
= data
->endselrx
;
1934 } else if (data
->dx
> data
->endselrx
)
1935 data
->dx
= data
->endselrx
;
1937 return (WINDOW_COPY_CMD_REDRAW
);
1940 static enum window_copy_cmd_action
1941 window_copy_cmd_set_mark(struct window_copy_cmd_state
*cs
)
1943 struct window_copy_mode_data
*data
= cs
->wme
->data
;
1945 data
->mx
= data
->cx
;
1946 data
->my
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1948 return (WINDOW_COPY_CMD_REDRAW
);
1951 static enum window_copy_cmd_action
1952 window_copy_cmd_start_of_line(struct window_copy_cmd_state
*cs
)
1954 struct window_mode_entry
*wme
= cs
->wme
;
1956 window_copy_cursor_start_of_line(wme
);
1957 return (WINDOW_COPY_CMD_NOTHING
);
1960 static enum window_copy_cmd_action
1961 window_copy_cmd_top_line(struct window_copy_cmd_state
*cs
)
1963 struct window_mode_entry
*wme
= cs
->wme
;
1964 struct window_copy_mode_data
*data
= wme
->data
;
1969 window_copy_update_selection(wme
, 1, 0);
1970 return (WINDOW_COPY_CMD_REDRAW
);
1973 static enum window_copy_cmd_action
1974 window_copy_cmd_copy_pipe_no_clear(struct window_copy_cmd_state
*cs
)
1976 struct window_mode_entry
*wme
= cs
->wme
;
1977 struct client
*c
= cs
->c
;
1978 struct session
*s
= cs
->s
;
1979 struct winlink
*wl
= cs
->wl
;
1980 struct window_pane
*wp
= wme
->wp
;
1981 char *command
= NULL
, *prefix
= NULL
;
1982 const char *arg1
= args_string(cs
->args
, 1);
1983 const char *arg2
= args_string(cs
->args
, 2);
1986 prefix
= format_single(NULL
, arg2
, c
, s
, wl
, wp
);
1988 if (s
!= NULL
&& arg1
!= NULL
&& *arg1
!= '\0')
1989 command
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1990 window_copy_copy_pipe(wme
, s
, prefix
, command
);
1994 return (WINDOW_COPY_CMD_NOTHING
);
1997 static enum window_copy_cmd_action
1998 window_copy_cmd_copy_pipe(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_REDRAW
);
2007 static enum window_copy_cmd_action
2008 window_copy_cmd_copy_pipe_and_cancel(struct window_copy_cmd_state
*cs
)
2010 struct window_mode_entry
*wme
= cs
->wme
;
2012 window_copy_cmd_copy_pipe_no_clear(cs
);
2013 window_copy_clear_selection(wme
);
2014 return (WINDOW_COPY_CMD_CANCEL
);
2017 static enum window_copy_cmd_action
2018 window_copy_cmd_pipe_no_clear(struct window_copy_cmd_state
*cs
)
2020 struct window_mode_entry
*wme
= cs
->wme
;
2021 struct client
*c
= cs
->c
;
2022 struct session
*s
= cs
->s
;
2023 struct winlink
*wl
= cs
->wl
;
2024 struct window_pane
*wp
= wme
->wp
;
2025 char *command
= NULL
;
2026 const char *arg1
= args_string(cs
->args
, 1);
2028 if (s
!= NULL
&& arg1
!= NULL
&& *arg1
!= '\0')
2029 command
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
2030 window_copy_pipe(wme
, s
, command
);
2033 return (WINDOW_COPY_CMD_NOTHING
);
2036 static enum window_copy_cmd_action
2037 window_copy_cmd_pipe(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_REDRAW
);
2046 static enum window_copy_cmd_action
2047 window_copy_cmd_pipe_and_cancel(struct window_copy_cmd_state
*cs
)
2049 struct window_mode_entry
*wme
= cs
->wme
;
2051 window_copy_cmd_pipe_no_clear(cs
);
2052 window_copy_clear_selection(wme
);
2053 return (WINDOW_COPY_CMD_CANCEL
);
2056 static enum window_copy_cmd_action
2057 window_copy_cmd_goto_line(struct window_copy_cmd_state
*cs
)
2059 struct window_mode_entry
*wme
= cs
->wme
;
2060 const char *arg1
= args_string(cs
->args
, 1);
2063 window_copy_goto_line(wme
, arg1
);
2064 return (WINDOW_COPY_CMD_NOTHING
);
2067 static enum window_copy_cmd_action
2068 window_copy_cmd_jump_backward(struct window_copy_cmd_state
*cs
)
2070 struct window_mode_entry
*wme
= cs
->wme
;
2071 struct window_copy_mode_data
*data
= wme
->data
;
2072 u_int np
= wme
->prefix
;
2073 const char *arg1
= args_string(cs
->args
, 1);
2075 if (*arg1
!= '\0') {
2076 data
->jumptype
= WINDOW_COPY_JUMPBACKWARD
;
2077 free(data
->jumpchar
);
2078 data
->jumpchar
= utf8_fromcstr(arg1
);
2079 for (; np
!= 0; np
--)
2080 window_copy_cursor_jump_back(wme
);
2082 return (WINDOW_COPY_CMD_NOTHING
);
2085 static enum window_copy_cmd_action
2086 window_copy_cmd_jump_forward(struct window_copy_cmd_state
*cs
)
2088 struct window_mode_entry
*wme
= cs
->wme
;
2089 struct window_copy_mode_data
*data
= wme
->data
;
2090 u_int np
= wme
->prefix
;
2091 const char *arg1
= args_string(cs
->args
, 1);
2093 if (*arg1
!= '\0') {
2094 data
->jumptype
= WINDOW_COPY_JUMPFORWARD
;
2095 free(data
->jumpchar
);
2096 data
->jumpchar
= utf8_fromcstr(arg1
);
2097 for (; np
!= 0; np
--)
2098 window_copy_cursor_jump(wme
);
2100 return (WINDOW_COPY_CMD_NOTHING
);
2103 static enum window_copy_cmd_action
2104 window_copy_cmd_jump_to_backward(struct window_copy_cmd_state
*cs
)
2106 struct window_mode_entry
*wme
= cs
->wme
;
2107 struct window_copy_mode_data
*data
= wme
->data
;
2108 u_int np
= wme
->prefix
;
2109 const char *arg1
= args_string(cs
->args
, 1);
2111 if (*arg1
!= '\0') {
2112 data
->jumptype
= WINDOW_COPY_JUMPTOBACKWARD
;
2113 free(data
->jumpchar
);
2114 data
->jumpchar
= utf8_fromcstr(arg1
);
2115 for (; np
!= 0; np
--)
2116 window_copy_cursor_jump_to_back(wme
);
2118 return (WINDOW_COPY_CMD_NOTHING
);
2121 static enum window_copy_cmd_action
2122 window_copy_cmd_jump_to_forward(struct window_copy_cmd_state
*cs
)
2124 struct window_mode_entry
*wme
= cs
->wme
;
2125 struct window_copy_mode_data
*data
= wme
->data
;
2126 u_int np
= wme
->prefix
;
2127 const char *arg1
= args_string(cs
->args
, 1);
2129 if (*arg1
!= '\0') {
2130 data
->jumptype
= WINDOW_COPY_JUMPTOFORWARD
;
2131 free(data
->jumpchar
);
2132 data
->jumpchar
= utf8_fromcstr(arg1
);
2133 for (; np
!= 0; np
--)
2134 window_copy_cursor_jump_to(wme
);
2136 return (WINDOW_COPY_CMD_NOTHING
);
2139 static enum window_copy_cmd_action
2140 window_copy_cmd_jump_to_mark(struct window_copy_cmd_state
*cs
)
2142 struct window_mode_entry
*wme
= cs
->wme
;
2144 window_copy_jump_to_mark(wme
);
2145 return (WINDOW_COPY_CMD_NOTHING
);
2148 static enum window_copy_cmd_action
2149 window_copy_cmd_search_backward(struct window_copy_cmd_state
*cs
)
2151 struct window_mode_entry
*wme
= cs
->wme
;
2152 struct window_copy_mode_data
*data
= wme
->data
;
2153 u_int np
= wme
->prefix
;
2155 if (!window_copy_expand_search_string(cs
))
2156 return (WINDOW_COPY_CMD_NOTHING
);
2158 if (data
->searchstr
!= NULL
) {
2159 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2160 data
->searchregex
= 1;
2162 for (; np
!= 0; np
--)
2163 window_copy_search_up(wme
, 1);
2165 return (WINDOW_COPY_CMD_NOTHING
);
2168 static enum window_copy_cmd_action
2169 window_copy_cmd_search_backward_text(struct window_copy_cmd_state
*cs
)
2171 struct window_mode_entry
*wme
= cs
->wme
;
2172 struct window_copy_mode_data
*data
= wme
->data
;
2173 u_int np
= wme
->prefix
;
2175 if (!window_copy_expand_search_string(cs
))
2176 return (WINDOW_COPY_CMD_NOTHING
);
2178 if (data
->searchstr
!= NULL
) {
2179 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2180 data
->searchregex
= 0;
2182 for (; np
!= 0; np
--)
2183 window_copy_search_up(wme
, 0);
2185 return (WINDOW_COPY_CMD_NOTHING
);
2188 static enum window_copy_cmd_action
2189 window_copy_cmd_search_forward(struct window_copy_cmd_state
*cs
)
2191 struct window_mode_entry
*wme
= cs
->wme
;
2192 struct window_copy_mode_data
*data
= wme
->data
;
2193 u_int np
= wme
->prefix
;
2195 if (!window_copy_expand_search_string(cs
))
2196 return (WINDOW_COPY_CMD_NOTHING
);
2198 if (data
->searchstr
!= NULL
) {
2199 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2200 data
->searchregex
= 1;
2202 for (; np
!= 0; np
--)
2203 window_copy_search_down(wme
, 1);
2205 return (WINDOW_COPY_CMD_NOTHING
);
2208 static enum window_copy_cmd_action
2209 window_copy_cmd_search_forward_text(struct window_copy_cmd_state
*cs
)
2211 struct window_mode_entry
*wme
= cs
->wme
;
2212 struct window_copy_mode_data
*data
= wme
->data
;
2213 u_int np
= wme
->prefix
;
2215 if (!window_copy_expand_search_string(cs
))
2216 return (WINDOW_COPY_CMD_NOTHING
);
2218 if (data
->searchstr
!= NULL
) {
2219 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2220 data
->searchregex
= 0;
2222 for (; np
!= 0; np
--)
2223 window_copy_search_down(wme
, 0);
2225 return (WINDOW_COPY_CMD_NOTHING
);
2228 static enum window_copy_cmd_action
2229 window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state
*cs
)
2231 struct window_mode_entry
*wme
= cs
->wme
;
2232 struct window_copy_mode_data
*data
= wme
->data
;
2233 const char *arg1
= args_string(cs
->args
, 1);
2234 const char *ss
= data
->searchstr
;
2236 enum window_copy_cmd_action action
= WINDOW_COPY_CMD_NOTHING
;
2240 log_debug("%s: %s", __func__
, arg1
);
2243 if (data
->searchx
== -1 || data
->searchy
== -1) {
2244 data
->searchx
= data
->cx
;
2245 data
->searchy
= data
->cy
;
2246 data
->searcho
= data
->oy
;
2247 } else if (ss
!= NULL
&& strcmp(arg1
, ss
) != 0) {
2248 data
->cx
= data
->searchx
;
2249 data
->cy
= data
->searchy
;
2250 data
->oy
= data
->searcho
;
2251 action
= WINDOW_COPY_CMD_REDRAW
;
2253 if (*arg1
== '\0') {
2254 window_copy_clear_marks(wme
);
2255 return (WINDOW_COPY_CMD_REDRAW
);
2260 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2261 data
->searchregex
= 0;
2262 free(data
->searchstr
);
2263 data
->searchstr
= xstrdup(arg1
);
2264 if (!window_copy_search_up(wme
, 0)) {
2265 window_copy_clear_marks(wme
);
2266 return (WINDOW_COPY_CMD_REDRAW
);
2270 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2271 data
->searchregex
= 0;
2272 free(data
->searchstr
);
2273 data
->searchstr
= xstrdup(arg1
);
2274 if (!window_copy_search_down(wme
, 0)) {
2275 window_copy_clear_marks(wme
);
2276 return (WINDOW_COPY_CMD_REDRAW
);
2283 static enum window_copy_cmd_action
2284 window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state
*cs
)
2286 struct window_mode_entry
*wme
= cs
->wme
;
2287 struct window_copy_mode_data
*data
= wme
->data
;
2288 const char *arg1
= args_string(cs
->args
, 1);
2289 const char *ss
= data
->searchstr
;
2291 enum window_copy_cmd_action action
= WINDOW_COPY_CMD_NOTHING
;
2295 log_debug("%s: %s", __func__
, arg1
);
2298 if (data
->searchx
== -1 || data
->searchy
== -1) {
2299 data
->searchx
= data
->cx
;
2300 data
->searchy
= data
->cy
;
2301 data
->searcho
= data
->oy
;
2302 } else if (ss
!= NULL
&& strcmp(arg1
, ss
) != 0) {
2303 data
->cx
= data
->searchx
;
2304 data
->cy
= data
->searchy
;
2305 data
->oy
= data
->searcho
;
2306 action
= WINDOW_COPY_CMD_REDRAW
;
2308 if (*arg1
== '\0') {
2309 window_copy_clear_marks(wme
);
2310 return (WINDOW_COPY_CMD_REDRAW
);
2315 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2316 data
->searchregex
= 0;
2317 free(data
->searchstr
);
2318 data
->searchstr
= xstrdup(arg1
);
2319 if (!window_copy_search_down(wme
, 0)) {
2320 window_copy_clear_marks(wme
);
2321 return (WINDOW_COPY_CMD_REDRAW
);
2325 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2326 data
->searchregex
= 0;
2327 free(data
->searchstr
);
2328 data
->searchstr
= xstrdup(arg1
);
2329 if (!window_copy_search_up(wme
, 0)) {
2330 window_copy_clear_marks(wme
);
2331 return (WINDOW_COPY_CMD_REDRAW
);
2337 static enum window_copy_cmd_action
2338 window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state
*cs
)
2340 struct window_mode_entry
*wme
= cs
->wme
;
2341 struct window_pane
*wp
= wme
->swp
;
2342 struct window_copy_mode_data
*data
= wme
->data
;
2345 return (WINDOW_COPY_CMD_NOTHING
);
2347 screen_free(data
->backing
);
2348 free(data
->backing
);
2349 data
->backing
= window_copy_clone_screen(&wp
->base
, &data
->screen
, NULL
, NULL
, wme
->swp
!= wme
->wp
);
2351 window_copy_size_changed(wme
);
2352 return (WINDOW_COPY_CMD_REDRAW
);
2355 static const struct {
2356 const char *command
;
2359 enum window_copy_cmd_clear clear
;
2360 enum window_copy_cmd_action (*f
)(struct window_copy_cmd_state
*);
2361 } window_copy_cmd_table
[] = {
2362 { .command
= "append-selection",
2365 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2366 .f
= window_copy_cmd_append_selection
2368 { .command
= "append-selection-and-cancel",
2371 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2372 .f
= window_copy_cmd_append_selection_and_cancel
2374 { .command
= "back-to-indentation",
2377 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2378 .f
= window_copy_cmd_back_to_indentation
2380 { .command
= "begin-selection",
2383 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2384 .f
= window_copy_cmd_begin_selection
2386 { .command
= "bottom-line",
2389 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2390 .f
= window_copy_cmd_bottom_line
2392 { .command
= "cancel",
2395 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2396 .f
= window_copy_cmd_cancel
2398 { .command
= "clear-selection",
2401 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2402 .f
= window_copy_cmd_clear_selection
2404 { .command
= "copy-end-of-line",
2407 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2408 .f
= window_copy_cmd_copy_end_of_line
2410 { .command
= "copy-end-of-line-and-cancel",
2413 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2414 .f
= window_copy_cmd_copy_end_of_line_and_cancel
2416 { .command
= "copy-pipe-end-of-line",
2419 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2420 .f
= window_copy_cmd_copy_pipe_end_of_line
2422 { .command
= "copy-pipe-end-of-line-and-cancel",
2425 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2426 .f
= window_copy_cmd_copy_pipe_end_of_line_and_cancel
2428 { .command
= "copy-line",
2431 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2432 .f
= window_copy_cmd_copy_line
2434 { .command
= "copy-line-and-cancel",
2437 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2438 .f
= window_copy_cmd_copy_line_and_cancel
2440 { .command
= "copy-pipe-line",
2443 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2444 .f
= window_copy_cmd_copy_pipe_line
2446 { .command
= "copy-pipe-line-and-cancel",
2449 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2450 .f
= window_copy_cmd_copy_pipe_line_and_cancel
2452 { .command
= "copy-pipe-no-clear",
2455 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2456 .f
= window_copy_cmd_copy_pipe_no_clear
2458 { .command
= "copy-pipe",
2461 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2462 .f
= window_copy_cmd_copy_pipe
2464 { .command
= "copy-pipe-and-cancel",
2467 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2468 .f
= window_copy_cmd_copy_pipe_and_cancel
2470 { .command
= "copy-selection-no-clear",
2473 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2474 .f
= window_copy_cmd_copy_selection_no_clear
2476 { .command
= "copy-selection",
2479 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2480 .f
= window_copy_cmd_copy_selection
2482 { .command
= "copy-selection-and-cancel",
2485 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2486 .f
= window_copy_cmd_copy_selection_and_cancel
2488 { .command
= "cursor-down",
2491 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2492 .f
= window_copy_cmd_cursor_down
2494 { .command
= "cursor-down-and-cancel",
2497 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2498 .f
= window_copy_cmd_cursor_down_and_cancel
2500 { .command
= "cursor-left",
2503 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2504 .f
= window_copy_cmd_cursor_left
2506 { .command
= "cursor-right",
2509 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2510 .f
= window_copy_cmd_cursor_right
2512 { .command
= "cursor-up",
2515 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2516 .f
= window_copy_cmd_cursor_up
2518 { .command
= "end-of-line",
2521 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2522 .f
= window_copy_cmd_end_of_line
2524 { .command
= "goto-line",
2527 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2528 .f
= window_copy_cmd_goto_line
2530 { .command
= "halfpage-down",
2533 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2534 .f
= window_copy_cmd_halfpage_down
2536 { .command
= "halfpage-down-and-cancel",
2539 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2540 .f
= window_copy_cmd_halfpage_down_and_cancel
2542 { .command
= "halfpage-up",
2545 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2546 .f
= window_copy_cmd_halfpage_up
2548 { .command
= "history-bottom",
2551 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2552 .f
= window_copy_cmd_history_bottom
2554 { .command
= "history-top",
2557 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2558 .f
= window_copy_cmd_history_top
2560 { .command
= "jump-again",
2563 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2564 .f
= window_copy_cmd_jump_again
2566 { .command
= "jump-backward",
2569 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2570 .f
= window_copy_cmd_jump_backward
2572 { .command
= "jump-forward",
2575 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2576 .f
= window_copy_cmd_jump_forward
2578 { .command
= "jump-reverse",
2581 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2582 .f
= window_copy_cmd_jump_reverse
2584 { .command
= "jump-to-backward",
2587 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2588 .f
= window_copy_cmd_jump_to_backward
2590 { .command
= "jump-to-forward",
2593 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2594 .f
= window_copy_cmd_jump_to_forward
2596 { .command
= "jump-to-mark",
2599 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2600 .f
= window_copy_cmd_jump_to_mark
2602 { .command
= "middle-line",
2605 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2606 .f
= window_copy_cmd_middle_line
2608 { .command
= "next-matching-bracket",
2611 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2612 .f
= window_copy_cmd_next_matching_bracket
2614 { .command
= "next-paragraph",
2617 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2618 .f
= window_copy_cmd_next_paragraph
2620 { .command
= "next-space",
2623 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2624 .f
= window_copy_cmd_next_space
2626 { .command
= "next-space-end",
2629 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2630 .f
= window_copy_cmd_next_space_end
2632 { .command
= "next-word",
2635 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2636 .f
= window_copy_cmd_next_word
2638 { .command
= "next-word-end",
2641 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2642 .f
= window_copy_cmd_next_word_end
2644 { .command
= "other-end",
2647 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2648 .f
= window_copy_cmd_other_end
2650 { .command
= "page-down",
2653 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2654 .f
= window_copy_cmd_page_down
2656 { .command
= "page-down-and-cancel",
2659 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2660 .f
= window_copy_cmd_page_down_and_cancel
2662 { .command
= "page-up",
2665 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2666 .f
= window_copy_cmd_page_up
2668 { .command
= "pipe-no-clear",
2671 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2672 .f
= window_copy_cmd_pipe_no_clear
2674 { .command
= "pipe",
2677 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2678 .f
= window_copy_cmd_pipe
2680 { .command
= "pipe-and-cancel",
2683 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2684 .f
= window_copy_cmd_pipe_and_cancel
2686 { .command
= "previous-matching-bracket",
2689 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2690 .f
= window_copy_cmd_previous_matching_bracket
2692 { .command
= "previous-paragraph",
2695 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2696 .f
= window_copy_cmd_previous_paragraph
2698 { .command
= "previous-space",
2701 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2702 .f
= window_copy_cmd_previous_space
2704 { .command
= "previous-word",
2707 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2708 .f
= window_copy_cmd_previous_word
2710 { .command
= "rectangle-on",
2713 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2714 .f
= window_copy_cmd_rectangle_on
2716 { .command
= "rectangle-off",
2719 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2720 .f
= window_copy_cmd_rectangle_off
2722 { .command
= "rectangle-toggle",
2725 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2726 .f
= window_copy_cmd_rectangle_toggle
2728 { .command
= "refresh-from-pane",
2731 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2732 .f
= window_copy_cmd_refresh_from_pane
2734 { .command
= "scroll-down",
2737 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2738 .f
= window_copy_cmd_scroll_down
2740 { .command
= "scroll-down-and-cancel",
2743 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2744 .f
= window_copy_cmd_scroll_down_and_cancel
2746 { .command
= "scroll-up",
2749 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2750 .f
= window_copy_cmd_scroll_up
2752 { .command
= "search-again",
2755 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2756 .f
= window_copy_cmd_search_again
2758 { .command
= "search-backward",
2761 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2762 .f
= window_copy_cmd_search_backward
2764 { .command
= "search-backward-text",
2767 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2768 .f
= window_copy_cmd_search_backward_text
2770 { .command
= "search-backward-incremental",
2773 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2774 .f
= window_copy_cmd_search_backward_incremental
2776 { .command
= "search-forward",
2779 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2780 .f
= window_copy_cmd_search_forward
2782 { .command
= "search-forward-text",
2785 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2786 .f
= window_copy_cmd_search_forward_text
2788 { .command
= "search-forward-incremental",
2791 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2792 .f
= window_copy_cmd_search_forward_incremental
2794 { .command
= "search-reverse",
2797 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2798 .f
= window_copy_cmd_search_reverse
2800 { .command
= "select-line",
2803 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2804 .f
= window_copy_cmd_select_line
2806 { .command
= "select-word",
2809 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2810 .f
= window_copy_cmd_select_word
2812 { .command
= "set-mark",
2815 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2816 .f
= window_copy_cmd_set_mark
2818 { .command
= "start-of-line",
2821 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2822 .f
= window_copy_cmd_start_of_line
2824 { .command
= "stop-selection",
2827 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2828 .f
= window_copy_cmd_stop_selection
2830 { .command
= "toggle-position",
2833 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2834 .f
= window_copy_cmd_toggle_position
2836 { .command
= "top-line",
2839 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2840 .f
= window_copy_cmd_top_line
2845 window_copy_command(struct window_mode_entry
*wme
, struct client
*c
,
2846 struct session
*s
, struct winlink
*wl
, struct args
*args
,
2847 struct mouse_event
*m
)
2849 struct window_copy_mode_data
*data
= wme
->data
;
2850 struct window_copy_cmd_state cs
;
2851 enum window_copy_cmd_action action
;
2852 enum window_copy_cmd_clear clear
= WINDOW_COPY_CMD_CLEAR_NEVER
;
2853 const char *command
;
2854 u_int i
, count
= args_count(args
);
2859 command
= args_string(args
, 0);
2861 if (m
!= NULL
&& m
->valid
&& !MOUSE_WHEEL(m
->b
))
2862 window_copy_move_mouse(m
);
2872 action
= WINDOW_COPY_CMD_NOTHING
;
2873 for (i
= 0; i
< nitems(window_copy_cmd_table
); i
++) {
2874 if (strcmp(window_copy_cmd_table
[i
].command
, command
) == 0) {
2875 if (count
- 1 < window_copy_cmd_table
[i
].minargs
||
2876 count
- 1 > window_copy_cmd_table
[i
].maxargs
)
2878 clear
= window_copy_cmd_table
[i
].clear
;
2879 action
= window_copy_cmd_table
[i
].f(&cs
);
2884 if (strncmp(command
, "search-", 7) != 0 && data
->searchmark
!= NULL
) {
2885 keys
= options_get_number(wme
->wp
->window
->options
, "mode-keys");
2886 if (clear
== WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
&&
2888 clear
= WINDOW_COPY_CMD_CLEAR_NEVER
;
2889 if (clear
!= WINDOW_COPY_CMD_CLEAR_NEVER
) {
2890 window_copy_clear_marks(wme
);
2891 data
->searchx
= data
->searchy
= -1;
2893 if (action
== WINDOW_COPY_CMD_NOTHING
)
2894 action
= WINDOW_COPY_CMD_REDRAW
;
2898 if (action
== WINDOW_COPY_CMD_CANCEL
)
2899 window_pane_reset_mode(wme
->wp
);
2900 else if (action
== WINDOW_COPY_CMD_REDRAW
)
2901 window_copy_redraw_screen(wme
);
2905 window_copy_scroll_to(struct window_mode_entry
*wme
, u_int px
, u_int py
,
2908 struct window_copy_mode_data
*data
= wme
->data
;
2909 struct grid
*gd
= data
->backing
->grid
;
2914 if (py
>= gd
->hsize
- data
->oy
&& py
< gd
->hsize
- data
->oy
+ gd
->sy
)
2915 data
->cy
= py
- (gd
->hsize
- data
->oy
);
2921 } else if (py
> gd
->hsize
+ gd
->sy
- gap
) {
2923 data
->cy
= py
- gd
->hsize
;
2925 offset
= py
+ gap
- gd
->sy
;
2926 data
->cy
= py
- offset
;
2928 data
->oy
= gd
->hsize
- offset
;
2931 if (!no_redraw
&& data
->searchmark
!= NULL
&& !data
->timeout
)
2932 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
2933 window_copy_update_selection(wme
, 1, 0);
2935 window_copy_redraw_screen(wme
);
2939 window_copy_search_compare(struct grid
*gd
, u_int px
, u_int py
,
2940 struct grid
*sgd
, u_int spx
, int cis
)
2942 struct grid_cell gc
, sgc
;
2943 const struct utf8_data
*ud
, *sud
;
2945 grid_get_cell(gd
, px
, py
, &gc
);
2947 grid_get_cell(sgd
, spx
, 0, &sgc
);
2950 if (ud
->size
!= sud
->size
|| ud
->width
!= sud
->width
)
2953 if (cis
&& ud
->size
== 1)
2954 return (tolower(ud
->data
[0]) == sud
->data
[0]);
2956 return (memcmp(ud
->data
, sud
->data
, ud
->size
) == 0);
2960 window_copy_search_lr(struct grid
*gd
, struct grid
*sgd
, u_int
*ppx
, u_int py
,
2961 u_int first
, u_int last
, int cis
)
2963 u_int ax
, bx
, px
, pywrap
, endline
;
2965 struct grid_line
*gl
;
2967 endline
= gd
->hsize
+ gd
->sy
- 1;
2968 for (ax
= first
; ax
< last
; ax
++) {
2969 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
2973 while (px
>= gd
->sx
&& pywrap
< endline
) {
2974 gl
= grid_get_line(gd
, pywrap
);
2975 if (~gl
->flags
& GRID_LINE_WRAPPED
)
2980 /* We have run off the end of the grid. */
2983 matched
= window_copy_search_compare(gd
, px
, pywrap
,
2988 if (bx
== sgd
->sx
) {
2997 window_copy_search_rl(struct grid
*gd
,
2998 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
, int cis
)
3000 u_int ax
, bx
, px
, pywrap
, endline
;
3002 struct grid_line
*gl
;
3004 endline
= gd
->hsize
+ gd
->sy
- 1;
3005 for (ax
= last
; ax
> first
; ax
--) {
3006 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
3010 while (px
>= gd
->sx
&& pywrap
< endline
) {
3011 gl
= grid_get_line(gd
, pywrap
);
3012 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3017 /* We have run off the end of the grid. */
3020 matched
= window_copy_search_compare(gd
, px
, pywrap
,
3025 if (bx
== sgd
->sx
) {
3034 window_copy_search_lr_regex(struct grid
*gd
, u_int
*ppx
, u_int
*psx
, u_int py
,
3035 u_int first
, u_int last
, regex_t
*reg
)
3038 u_int endline
, foundx
, foundy
, len
, pywrap
, size
= 1;
3040 regmatch_t regmatch
;
3041 struct grid_line
*gl
;
3044 * This can happen during search if the last match was the last
3045 * character on a line.
3050 /* Set flags for regex search. */
3052 eflags
|= REG_NOTBOL
;
3054 /* Need to look at the entire string. */
3055 buf
= xmalloc(size
);
3057 buf
= window_copy_stringify(gd
, py
, first
, gd
->sx
, buf
, &size
);
3058 len
= gd
->sx
- first
;
3059 endline
= gd
->hsize
+ gd
->sy
- 1;
3061 while (buf
!= NULL
&& pywrap
<= endline
) {
3062 gl
= grid_get_line(gd
, pywrap
);
3063 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3066 buf
= window_copy_stringify(gd
, pywrap
, 0, gd
->sx
, buf
, &size
);
3070 if (regexec(reg
, buf
, 1, ®match
, eflags
) == 0 &&
3071 regmatch
.rm_so
!= regmatch
.rm_eo
) {
3074 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3075 buf
+ regmatch
.rm_so
);
3076 if (foundy
== py
&& foundx
< last
) {
3078 len
-= foundx
- first
;
3079 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3080 buf
+ regmatch
.rm_eo
);
3082 while (foundy
> py
) {
3099 window_copy_search_rl_regex(struct grid
*gd
, u_int
*ppx
, u_int
*psx
, u_int py
,
3100 u_int first
, u_int last
, regex_t
*reg
)
3103 u_int endline
, len
, pywrap
, size
= 1;
3105 struct grid_line
*gl
;
3107 /* Set flags for regex search. */
3109 eflags
|= REG_NOTBOL
;
3111 /* Need to look at the entire string. */
3112 buf
= xmalloc(size
);
3114 buf
= window_copy_stringify(gd
, py
, first
, gd
->sx
, buf
, &size
);
3115 len
= gd
->sx
- first
;
3116 endline
= gd
->hsize
+ gd
->sy
- 1;
3118 while (buf
!= NULL
&& (pywrap
<= endline
)) {
3119 gl
= grid_get_line(gd
, pywrap
);
3120 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3123 buf
= window_copy_stringify(gd
, pywrap
, 0, gd
->sx
, buf
, &size
);
3127 if (window_copy_last_regex(gd
, py
, first
, last
, len
, ppx
, psx
, buf
,
3141 window_copy_cellstring(const struct grid_line
*gl
, u_int px
, size_t *size
,
3144 static struct utf8_data ud
;
3145 struct grid_cell_entry
*gce
;
3148 if (px
>= gl
->cellsize
) {
3154 gce
= &gl
->celldata
[px
];
3155 if (gce
->flags
& GRID_FLAG_PADDING
) {
3160 if (~gce
->flags
& GRID_FLAG_EXTENDED
) {
3163 return (&gce
->data
.data
);
3166 utf8_to_data(gl
->extddata
[gce
->offset
].data
, &ud
);
3175 copy
= xmalloc(ud
.size
);
3176 memcpy(copy
, ud
.data
, ud
.size
);
3180 /* Find last match in given range. */
3182 window_copy_last_regex(struct grid
*gd
, u_int py
, u_int first
, u_int last
,
3183 u_int len
, u_int
*ppx
, u_int
*psx
, const char *buf
, const regex_t
*preg
,
3186 u_int foundx
, foundy
, oldx
, px
= 0, savepx
, savesx
= 0;
3187 regmatch_t regmatch
;
3192 while (regexec(preg
, buf
+ px
, 1, ®match
, eflags
) == 0) {
3193 if (regmatch
.rm_so
== regmatch
.rm_eo
)
3195 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3196 buf
+ px
+ regmatch
.rm_so
);
3197 if (foundy
> py
|| foundx
>= last
)
3199 len
-= foundx
- oldx
;
3201 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3202 buf
+ px
+ regmatch
.rm_eo
);
3203 if (foundy
> py
|| foundx
>= last
) {
3206 while (foundy
> py
) {
3213 savesx
= foundx
- savepx
;
3217 px
+= regmatch
.rm_eo
;
3231 /* Stringify line and append to input buffer. Caller frees. */
3233 window_copy_stringify(struct grid
*gd
, u_int py
, u_int first
, u_int last
,
3234 char *buf
, u_int
*size
)
3236 u_int ax
, bx
, newsize
= *size
;
3237 const struct grid_line
*gl
;
3239 size_t bufsize
= 1024, dlen
;
3242 while (bufsize
< newsize
)
3244 buf
= xrealloc(buf
, bufsize
);
3246 gl
= grid_peek_line(gd
, py
);
3248 for (ax
= first
; ax
< last
; ax
++) {
3249 d
= window_copy_cellstring(gl
, ax
, &dlen
, &allocated
);
3251 while (bufsize
< newsize
) {
3253 buf
= xrealloc(buf
, bufsize
);
3258 memcpy(buf
+ bx
, d
, dlen
);
3264 buf
[newsize
- 1] = '\0';
3270 /* Map start of C string containing UTF-8 data to grid cell position. */
3272 window_copy_cstrtocellpos(struct grid
*gd
, u_int ncells
, u_int
*ppx
, u_int
*ppy
,
3275 u_int cell
, ccell
, px
, pywrap
, pos
, len
;
3277 const struct grid_line
*gl
;
3286 /* Populate the array of cell data. */
3287 cells
= xreallocarray(NULL
, ncells
, sizeof cells
[0]);
3291 gl
= grid_peek_line(gd
, pywrap
);
3292 while (cell
< ncells
) {
3293 cells
[cell
].d
= window_copy_cellstring(gl
, px
,
3294 &cells
[cell
].dlen
, &cells
[cell
].allocated
);
3300 gl
= grid_peek_line(gd
, pywrap
);
3304 /* Locate starting cell. */
3307 while (cell
< ncells
) {
3311 while (ccell
< ncells
) {
3312 if (str
[pos
] == '\0') {
3317 dlen
= cells
[ccell
].dlen
;
3319 if (str
[pos
] != *d
) {
3325 if (dlen
> len
- pos
)
3327 if (memcmp(str
+ pos
, d
, dlen
) != 0) {
3340 /* If not found this will be one past the end. */
3343 while (px
>= gd
->sx
) {
3351 /* Free cell data. */
3352 for (cell
= 0; cell
< ncells
; cell
++) {
3353 if (cells
[cell
].allocated
)
3354 free((void *)cells
[cell
].d
);
3360 window_copy_move_left(struct screen
*s
, u_int
*fx
, u_int
*fy
, int wrapflag
)
3362 if (*fx
== 0) { /* left */
3363 if (*fy
== 0) { /* top */
3365 *fx
= screen_size_x(s
) - 1;
3366 *fy
= screen_hsize(s
) + screen_size_y(s
) - 1;
3370 *fx
= screen_size_x(s
) - 1;
3377 window_copy_move_right(struct screen
*s
, u_int
*fx
, u_int
*fy
, int wrapflag
)
3379 if (*fx
== screen_size_x(s
) - 1) { /* right */
3380 if (*fy
== screen_hsize(s
) + screen_size_y(s
) - 1) { /* bottom */
3394 window_copy_is_lowercase(const char *ptr
)
3396 while (*ptr
!= '\0') {
3397 if (*ptr
!= tolower((u_char
)*ptr
))
3405 * Handle backward wrapped regex searches with overlapping matches. In this case
3406 * find the longest overlapping match from previous wrapped lines.
3409 window_copy_search_back_overlap(struct grid
*gd
, regex_t
*preg
, u_int
*ppx
,
3410 u_int
*psx
, u_int
*ppy
, u_int endline
)
3412 u_int endx
, endy
, oldendx
, oldendy
, px
, py
, sx
;
3415 oldendx
= *ppx
+ *psx
;
3417 while (oldendx
> gd
->sx
- 1) {
3425 while (found
&& px
== 0 && py
- 1 > endline
&&
3426 grid_get_line(gd
, py
- 2)->flags
& GRID_LINE_WRAPPED
&&
3427 endx
== oldendx
&& endy
== oldendy
) {
3429 found
= window_copy_search_rl_regex(gd
, &px
, &sx
, py
- 1, 0,
3434 while (endx
> gd
->sx
- 1) {
3438 if (endx
== oldendx
&& endy
== oldendy
) {
3447 * Search for text stored in sgd starting from position fx,fy up to endline. If
3448 * found, jump to it. If cis then ignore case. The direction is 0 for searching
3449 * up, down otherwise. If wrap then go to begin/end of grid and try again if
3453 window_copy_search_jump(struct window_mode_entry
*wme
, struct grid
*gd
,
3454 struct grid
*sgd
, u_int fx
, u_int fy
, u_int endline
, int cis
, int wrap
,
3455 int direction
, int regex
)
3457 u_int i
, px
, sx
, ssize
= 1;
3458 int found
= 0, cflags
= REG_EXTENDED
;
3463 sbuf
= xmalloc(ssize
);
3465 sbuf
= window_copy_stringify(sgd
, 0, 0, sgd
->sx
, sbuf
, &ssize
);
3467 cflags
|= REG_ICASE
;
3468 if (regcomp(®
, sbuf
, cflags
) != 0) {
3476 for (i
= fy
; i
<= endline
; i
++) {
3478 found
= window_copy_search_lr_regex(gd
,
3479 &px
, &sx
, i
, fx
, gd
->sx
, ®
);
3481 found
= window_copy_search_lr(gd
, sgd
,
3482 &px
, i
, fx
, gd
->sx
, cis
);
3489 for (i
= fy
+ 1; endline
< i
; i
--) {
3491 found
= window_copy_search_rl_regex(gd
,
3492 &px
, &sx
, i
- 1, 0, fx
+ 1, ®
);
3494 window_copy_search_back_overlap(gd
,
3495 ®
, &px
, &sx
, &i
, endline
);
3498 found
= window_copy_search_rl(gd
, sgd
,
3499 &px
, i
- 1, 0, fx
+ 1, cis
);
3512 window_copy_scroll_to(wme
, px
, i
, 1);
3516 return (window_copy_search_jump(wme
, gd
, sgd
,
3517 direction
? 0 : gd
->sx
- 1,
3518 direction
? 0 : gd
->hsize
+ gd
->sy
- 1, fy
, cis
, 0,
3525 window_copy_move_after_search_mark(struct window_copy_mode_data
*data
,
3526 u_int
*fx
, u_int
*fy
, int wrapflag
)
3528 struct screen
*s
= data
->backing
;
3531 if (window_copy_search_mark_at(data
, *fx
, *fy
, &start
) == 0 &&
3532 data
->searchmark
[start
] != 0) {
3533 while (window_copy_search_mark_at(data
, *fx
, *fy
, &at
) == 0) {
3534 if (data
->searchmark
[at
] != data
->searchmark
[start
])
3536 /* Stop if not wrapping and at the end of the grid. */
3538 *fx
== screen_size_x(s
) - 1 &&
3539 *fy
== screen_hsize(s
) + screen_size_y(s
) - 1)
3542 window_copy_move_right(s
, fx
, fy
, wrapflag
);
3548 * Search in for text searchstr. If direction is 0 then search up, otherwise
3552 window_copy_search(struct window_mode_entry
*wme
, int direction
, int regex
)
3554 struct window_pane
*wp
= wme
->wp
;
3555 struct window_copy_mode_data
*data
= wme
->data
;
3556 struct screen
*s
= data
->backing
, ss
;
3557 struct screen_write_ctx ctx
;
3558 struct grid
*gd
= s
->grid
;
3559 const char *str
= data
->searchstr
;
3560 u_int at
, endline
, fx
, fy
, start
;
3561 int cis
, found
, keys
, visible_only
;
3564 if (regex
&& str
[strcspn(str
, "^$*+()?[].\\")] == '\0')
3567 data
->searchdirection
= direction
;
3572 if (data
->searchall
|| wp
->searchstr
== NULL
||
3573 wp
->searchregex
!= regex
) {
3575 data
->searchall
= 0;
3577 visible_only
= (strcmp(wp
->searchstr
, str
) == 0);
3578 free(wp
->searchstr
);
3579 wp
->searchstr
= xstrdup(str
);
3580 wp
->searchregex
= regex
;
3583 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3585 screen_init(&ss
, screen_write_strlen("%s", str
), 1, 0);
3586 screen_write_start(&ctx
, &ss
);
3587 screen_write_nputs(&ctx
, -1, &grid_default_cell
, "%s", str
);
3588 screen_write_stop(&ctx
);
3590 wrapflag
= options_get_number(wp
->window
->options
, "wrap-search");
3591 cis
= window_copy_is_lowercase(str
);
3593 keys
= options_get_number(wp
->window
->options
, "mode-keys");
3597 * Behave according to mode-keys. If it is emacs, search forward
3598 * leaves the cursor after the match. If it is vi, the cursor
3599 * remains at the beginning of the match, regardless of
3600 * direction, which means that we need to start the next search
3601 * after the term the cursor is currently on when searching
3604 if (keys
== MODEKEY_VI
) {
3605 if (data
->searchmark
!= NULL
)
3606 window_copy_move_after_search_mark(data
, &fx
,
3610 * When there are no search marks, start the
3611 * search after the current cursor position.
3613 window_copy_move_right(s
, &fx
, &fy
, wrapflag
);
3616 endline
= gd
->hsize
+ gd
->sy
- 1;
3619 window_copy_move_left(s
, &fx
, &fy
, wrapflag
);
3623 found
= window_copy_search_jump(wme
, gd
, ss
.grid
, fx
, fy
, endline
, cis
,
3624 wrapflag
, direction
, regex
);
3626 window_copy_search_marks(wme
, &ss
, regex
, visible_only
);
3628 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3631 * When searching forward, if the cursor is not at the beginning
3632 * of the mark, search again.
3635 window_copy_search_mark_at(data
, fx
, fy
, &at
) == 0 &&
3637 data
->searchmark
[at
] == data
->searchmark
[at
- 1]) {
3638 window_copy_move_after_search_mark(data
, &fx
, &fy
,
3640 window_copy_search_jump(wme
, gd
, ss
.grid
, fx
,
3641 fy
, endline
, cis
, wrapflag
, direction
,
3644 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3649 * When in Emacs mode, position the cursor just after
3652 if (keys
== MODEKEY_EMACS
) {
3653 window_copy_move_after_search_mark(data
, &fx
,
3656 data
->cy
= fy
- screen_hsize(data
->backing
) +
3662 * When searching backward, position the cursor at the
3663 * beginning of the mark.
3665 if (window_copy_search_mark_at(data
, fx
, fy
,
3667 while (window_copy_search_mark_at(data
, fx
, fy
,
3669 data
->searchmark
[at
] ==
3670 data
->searchmark
[start
]) {
3673 screen_hsize(data
->backing
) +
3678 window_copy_move_left(s
, &fx
, &fy
, 0);
3683 window_copy_redraw_screen(wme
);
3690 window_copy_visible_lines(struct window_copy_mode_data
*data
, u_int
*start
,
3693 struct grid
*gd
= data
->backing
->grid
;
3694 const struct grid_line
*gl
;
3696 for (*start
= gd
->hsize
- data
->oy
; *start
> 0; (*start
)--) {
3697 gl
= grid_peek_line(gd
, (*start
) - 1);
3698 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3701 *end
= gd
->hsize
- data
->oy
+ gd
->sy
;
3705 window_copy_search_mark_at(struct window_copy_mode_data
*data
, u_int px
,
3706 u_int py
, u_int
*at
)
3708 struct screen
*s
= data
->backing
;
3709 struct grid
*gd
= s
->grid
;
3711 if (py
< gd
->hsize
- data
->oy
)
3713 if (py
> gd
->hsize
- data
->oy
+ gd
->sy
- 1)
3715 *at
= ((py
- (gd
->hsize
- data
->oy
)) * gd
->sx
) + px
;
3720 window_copy_search_marks(struct window_mode_entry
*wme
, struct screen
*ssp
,
3721 int regex
, int visible_only
)
3723 struct window_copy_mode_data
*data
= wme
->data
;
3724 struct screen
*s
= data
->backing
, ss
;
3725 struct screen_write_ctx ctx
;
3726 struct grid
*gd
= s
->grid
;
3727 int found
, cis
, stopped
= 0;
3728 int cflags
= REG_EXTENDED
;
3729 u_int px
, py
, i
, b
, nfound
= 0, width
;
3730 u_int ssize
= 1, start
, end
;
3733 uint64_t stop
= 0, tstart
, t
;
3736 width
= screen_write_strlen("%s", data
->searchstr
);
3737 screen_init(&ss
, width
, 1, 0);
3738 screen_write_start(&ctx
, &ss
);
3739 screen_write_nputs(&ctx
, -1, &grid_default_cell
, "%s",
3741 screen_write_stop(&ctx
);
3744 width
= screen_size_x(ssp
);
3746 cis
= window_copy_is_lowercase(data
->searchstr
);
3749 sbuf
= xmalloc(ssize
);
3751 sbuf
= window_copy_stringify(ssp
->grid
, 0, 0, ssp
->grid
->sx
,
3754 cflags
|= REG_ICASE
;
3755 if (regcomp(®
, sbuf
, cflags
) != 0) {
3761 tstart
= get_timer();
3764 window_copy_visible_lines(data
, &start
, &end
);
3767 end
= gd
->hsize
+ gd
->sy
;
3768 stop
= get_timer() + WINDOW_COPY_SEARCH_ALL_TIMEOUT
;
3772 free(data
->searchmark
);
3773 data
->searchmark
= xcalloc(gd
->sx
, gd
->sy
);
3774 data
->searchgen
= 1;
3776 for (py
= start
; py
< end
; py
++) {
3780 found
= window_copy_search_lr_regex(gd
,
3781 &px
, &width
, py
, px
, gd
->sx
, ®
);
3785 found
= window_copy_search_lr(gd
, ssp
->grid
,
3786 &px
, py
, px
, gd
->sx
, cis
);
3792 if (window_copy_search_mark_at(data
, px
, py
, &b
) == 0) {
3793 if (b
+ width
> gd
->sx
* gd
->sy
)
3794 width
= (gd
->sx
* gd
->sy
) - b
;
3795 for (i
= b
; i
< b
+ width
; i
++) {
3796 if (data
->searchmark
[i
] != 0)
3798 data
->searchmark
[i
] = data
->searchgen
;
3800 if (data
->searchgen
== UCHAR_MAX
)
3801 data
->searchgen
= 1;
3809 if (t
- tstart
> WINDOW_COPY_SEARCH_TIMEOUT
) {
3813 if (stop
!= 0 && t
> stop
) {
3818 if (data
->timeout
) {
3819 window_copy_clear_marks(wme
);
3823 if (stopped
&& stop
!= 0) {
3824 /* Try again but just the visible context. */
3825 window_copy_visible_lines(data
, &start
, &end
);
3830 if (!visible_only
) {
3833 data
->searchcount
= 1000;
3834 else if (nfound
> 100)
3835 data
->searchcount
= 100;
3836 else if (nfound
> 10)
3837 data
->searchcount
= 10;
3839 data
->searchcount
= -1;
3840 data
->searchmore
= 1;
3842 data
->searchcount
= nfound
;
3843 data
->searchmore
= 0;
3856 window_copy_clear_marks(struct window_mode_entry
*wme
)
3858 struct window_copy_mode_data
*data
= wme
->data
;
3860 free(data
->searchmark
);
3861 data
->searchmark
= NULL
;
3865 window_copy_search_up(struct window_mode_entry
*wme
, int regex
)
3867 return (window_copy_search(wme
, 0, regex
));
3871 window_copy_search_down(struct window_mode_entry
*wme
, int regex
)
3873 return (window_copy_search(wme
, 1, regex
));
3877 window_copy_goto_line(struct window_mode_entry
*wme
, const char *linestr
)
3879 struct window_copy_mode_data
*data
= wme
->data
;
3883 lineno
= strtonum(linestr
, -1, INT_MAX
, &errstr
);
3886 if (lineno
< 0 || (u_int
)lineno
> screen_hsize(data
->backing
))
3887 lineno
= screen_hsize(data
->backing
);
3890 window_copy_update_selection(wme
, 1, 0);
3891 window_copy_redraw_screen(wme
);
3895 window_copy_match_start_end(struct window_copy_mode_data
*data
, u_int at
,
3896 u_int
*start
, u_int
*end
)
3898 struct grid
*gd
= data
->backing
->grid
;
3899 u_int last
= (gd
->sy
* gd
->sx
) - 1;
3900 u_char mark
= data
->searchmark
[at
];
3903 while (*start
!= 0 && data
->searchmark
[*start
] == mark
)
3905 if (data
->searchmark
[*start
] != mark
)
3907 while (*end
!= last
&& data
->searchmark
[*end
] == mark
)
3909 if (data
->searchmark
[*end
] != mark
)
3914 window_copy_match_at_cursor(struct window_copy_mode_data
*data
)
3916 struct grid
*gd
= data
->backing
->grid
;
3917 struct grid_cell gc
;
3918 u_int at
, start
, end
, cy
, px
, py
;
3919 u_int sx
= screen_size_x(data
->backing
);
3923 if (data
->searchmark
== NULL
)
3926 cy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3927 if (window_copy_search_mark_at(data
, data
->cx
, cy
, &at
) != 0)
3929 if (data
->searchmark
[at
] == 0) {
3930 /* Allow one position after the match. */
3931 if (at
== 0 || data
->searchmark
[--at
] == 0)
3934 window_copy_match_start_end(data
, at
, &start
, &end
);
3937 * Cells will not be set in the marked array unless they are valid text
3938 * and wrapping will be taken care of, so we can just copy.
3940 for (at
= start
; at
<= end
; at
++) {
3942 px
= at
- (py
* sx
);
3944 grid_get_cell(gd
, px
, gd
->hsize
+ py
- data
->oy
, &gc
);
3945 buf
= xrealloc(buf
, len
+ gc
.data
.size
+ 1);
3946 memcpy(buf
+ len
, gc
.data
.data
, gc
.data
.size
);
3947 len
+= gc
.data
.size
;
3955 window_copy_update_style(struct window_mode_entry
*wme
, u_int fx
, u_int fy
,
3956 struct grid_cell
*gc
, const struct grid_cell
*mgc
,
3957 const struct grid_cell
*cgc
, const struct grid_cell
*mkgc
)
3959 struct window_pane
*wp
= wme
->wp
;
3960 struct window_copy_mode_data
*data
= wme
->data
;
3961 u_int mark
, start
, end
, cy
, cursor
, current
;
3962 int inv
= 0, found
= 0;
3965 if (data
->showmark
&& fy
== data
->my
) {
3966 gc
->attr
= mkgc
->attr
;
3979 if (data
->searchmark
== NULL
)
3982 if (window_copy_search_mark_at(data
, fx
, fy
, ¤t
) != 0)
3984 mark
= data
->searchmark
[current
];
3988 cy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3989 if (window_copy_search_mark_at(data
, data
->cx
, cy
, &cursor
) == 0) {
3990 keys
= options_get_number(wp
->window
->options
, "mode-keys");
3992 keys
== MODEKEY_EMACS
&&
3993 data
->searchdirection
) {
3994 if (data
->searchmark
[cursor
- 1] == mark
) {
3998 } else if (data
->searchmark
[cursor
] == mark
)
4001 window_copy_match_start_end(data
, cursor
, &start
, &end
);
4002 if (current
>= start
&& current
<= end
) {
4003 gc
->attr
= cgc
->attr
;
4017 gc
->attr
= mgc
->attr
;
4029 window_copy_write_one(struct window_mode_entry
*wme
,
4030 struct screen_write_ctx
*ctx
, u_int py
, u_int fy
, u_int nx
,
4031 const struct grid_cell
*mgc
, const struct grid_cell
*cgc
,
4032 const struct grid_cell
*mkgc
)
4034 struct window_copy_mode_data
*data
= wme
->data
;
4035 struct grid
*gd
= data
->backing
->grid
;
4036 struct grid_cell gc
;
4039 screen_write_cursormove(ctx
, 0, py
, 0);
4040 for (fx
= 0; fx
< nx
; fx
++) {
4041 grid_get_cell(gd
, fx
, fy
, &gc
);
4042 if (fx
+ gc
.data
.width
<= nx
) {
4043 window_copy_update_style(wme
, fx
, fy
, &gc
, mgc
, cgc
,
4045 screen_write_cell(ctx
, &gc
);
4051 window_copy_write_line(struct window_mode_entry
*wme
,
4052 struct screen_write_ctx
*ctx
, u_int py
)
4054 struct window_pane
*wp
= wme
->wp
;
4055 struct window_copy_mode_data
*data
= wme
->data
;
4056 struct screen
*s
= &data
->screen
;
4057 struct options
*oo
= wp
->window
->options
;
4058 struct grid_cell gc
, mgc
, cgc
, mkgc
;
4061 u_int hsize
= screen_hsize(data
->backing
);
4063 style_apply(&gc
, oo
, "mode-style", NULL
);
4064 gc
.flags
|= GRID_FLAG_NOPALETTE
;
4065 style_apply(&mgc
, oo
, "copy-mode-match-style", NULL
);
4066 mgc
.flags
|= GRID_FLAG_NOPALETTE
;
4067 style_apply(&cgc
, oo
, "copy-mode-current-match-style", NULL
);
4068 cgc
.flags
|= GRID_FLAG_NOPALETTE
;
4069 style_apply(&mkgc
, oo
, "copy-mode-mark-style", NULL
);
4070 mkgc
.flags
|= GRID_FLAG_NOPALETTE
;
4072 if (py
== 0 && s
->rupper
< s
->rlower
&& !data
->hide_position
) {
4073 if (data
->searchmark
== NULL
) {
4074 if (data
->timeout
) {
4075 size
= xsnprintf(hdr
, sizeof hdr
,
4076 "(timed out) [%u/%u]", data
->oy
, hsize
);
4078 size
= xsnprintf(hdr
, sizeof hdr
,
4079 "[%u/%u]", data
->oy
, hsize
);
4082 if (data
->searchcount
== -1) {
4083 size
= xsnprintf(hdr
, sizeof hdr
,
4084 "[%u/%u]", data
->oy
, hsize
);
4086 size
= xsnprintf(hdr
, sizeof hdr
,
4087 "(%d%s results) [%u/%u]", data
->searchcount
,
4088 data
->searchmore
? "+" : "", data
->oy
,
4092 if (size
> screen_size_x(s
))
4093 size
= screen_size_x(s
);
4094 screen_write_cursormove(ctx
, screen_size_x(s
) - size
, 0, 0);
4095 screen_write_puts(ctx
, &gc
, "%s", hdr
);
4099 if (size
< screen_size_x(s
)) {
4100 window_copy_write_one(wme
, ctx
, py
, hsize
- data
->oy
+ py
,
4101 screen_size_x(s
) - size
, &mgc
, &cgc
, &mkgc
);
4104 if (py
== data
->cy
&& data
->cx
== screen_size_x(s
)) {
4105 screen_write_cursormove(ctx
, screen_size_x(s
) - 1, py
, 0);
4106 screen_write_putc(ctx
, &grid_default_cell
, '$');
4111 window_copy_write_lines(struct window_mode_entry
*wme
,
4112 struct screen_write_ctx
*ctx
, u_int py
, u_int ny
)
4116 for (yy
= py
; yy
< py
+ ny
; yy
++)
4117 window_copy_write_line(wme
, ctx
, py
);
4121 window_copy_redraw_selection(struct window_mode_entry
*wme
, u_int old_y
)
4123 struct window_copy_mode_data
*data
= wme
->data
;
4124 struct grid
*gd
= data
->backing
->grid
;
4125 u_int new_y
, start
, end
;
4128 if (old_y
<= new_y
) {
4137 * In word selection mode the first word on the line below the cursor
4138 * might be selected, so add this line to the redraw area.
4140 if (data
->selflag
== SEL_WORD
) {
4141 /* Last grid line in data coordinates. */
4142 if (end
< gd
->sy
+ data
->oy
- 1)
4145 window_copy_redraw_lines(wme
, start
, end
- start
+ 1);
4149 window_copy_redraw_lines(struct window_mode_entry
*wme
, u_int py
, u_int ny
)
4151 struct window_pane
*wp
= wme
->wp
;
4152 struct window_copy_mode_data
*data
= wme
->data
;
4153 struct screen_write_ctx ctx
;
4156 screen_write_start_pane(&ctx
, wp
, NULL
);
4157 for (i
= py
; i
< py
+ ny
; i
++)
4158 window_copy_write_line(wme
, &ctx
, i
);
4159 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
4160 screen_write_stop(&ctx
);
4164 window_copy_redraw_screen(struct window_mode_entry
*wme
)
4166 struct window_copy_mode_data
*data
= wme
->data
;
4168 window_copy_redraw_lines(wme
, 0, screen_size_y(&data
->screen
));
4172 window_copy_synchronize_cursor_end(struct window_mode_entry
*wme
, int begin
,
4175 struct window_copy_mode_data
*data
= wme
->data
;
4179 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4180 switch (data
->selflag
) {
4185 if (data
->dy
> yy
|| (data
->dy
== yy
&& data
->dx
> xx
)) {
4186 /* Right to left selection. */
4187 window_copy_cursor_previous_word_pos(wme
,
4188 data
->separators
, &xx
, &yy
);
4191 /* Reset the end. */
4192 data
->endselx
= data
->endselrx
;
4193 data
->endsely
= data
->endselry
;
4195 /* Left to right selection. */
4196 if (xx
>= window_copy_find_length(wme
, yy
) ||
4197 !window_copy_in_set(wme
, xx
+ 1, yy
, WHITESPACE
)) {
4198 window_copy_cursor_next_word_end_pos(wme
,
4199 data
->separators
, &xx
, &yy
);
4202 /* Reset the start. */
4203 data
->selx
= data
->selrx
;
4204 data
->sely
= data
->selry
;
4211 if (data
->dy
> yy
) {
4212 /* Right to left selection. */
4216 /* Reset the end. */
4217 data
->endselx
= data
->endselrx
;
4218 data
->endsely
= data
->endselry
;
4220 /* Left to right selection. */
4221 if (yy
< data
->endselry
)
4222 yy
= data
->endselry
;
4223 xx
= window_copy_find_length(wme
, yy
);
4225 /* Reset the start. */
4226 data
->selx
= data
->selrx
;
4227 data
->sely
= data
->selry
;
4243 window_copy_synchronize_cursor(struct window_mode_entry
*wme
, int no_reset
)
4245 struct window_copy_mode_data
*data
= wme
->data
;
4247 switch (data
->cursordrag
) {
4248 case CURSORDRAG_ENDSEL
:
4249 window_copy_synchronize_cursor_end(wme
, 0, no_reset
);
4251 case CURSORDRAG_SEL
:
4252 window_copy_synchronize_cursor_end(wme
, 1, no_reset
);
4254 case CURSORDRAG_NONE
:
4260 window_copy_update_cursor(struct window_mode_entry
*wme
, u_int cx
, u_int cy
)
4262 struct window_pane
*wp
= wme
->wp
;
4263 struct window_copy_mode_data
*data
= wme
->data
;
4264 struct screen
*s
= &data
->screen
;
4265 struct screen_write_ctx ctx
;
4266 u_int old_cx
, old_cy
;
4268 old_cx
= data
->cx
; old_cy
= data
->cy
;
4269 data
->cx
= cx
; data
->cy
= cy
;
4270 if (old_cx
== screen_size_x(s
))
4271 window_copy_redraw_lines(wme
, old_cy
, 1);
4272 if (data
->cx
== screen_size_x(s
))
4273 window_copy_redraw_lines(wme
, data
->cy
, 1);
4275 screen_write_start_pane(&ctx
, wp
, NULL
);
4276 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
4277 screen_write_stop(&ctx
);
4282 window_copy_start_selection(struct window_mode_entry
*wme
)
4284 struct window_copy_mode_data
*data
= wme
->data
;
4286 data
->selx
= data
->cx
;
4287 data
->sely
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4289 data
->endselx
= data
->selx
;
4290 data
->endsely
= data
->sely
;
4292 data
->cursordrag
= CURSORDRAG_ENDSEL
;
4294 window_copy_set_selection(wme
, 1, 0);
4298 window_copy_adjust_selection(struct window_mode_entry
*wme
, u_int
*selx
,
4301 struct window_copy_mode_data
*data
= wme
->data
;
4302 struct screen
*s
= &data
->screen
;
4309 ty
= screen_hsize(data
->backing
) - data
->oy
;
4311 relpos
= WINDOW_COPY_REL_POS_ABOVE
;
4312 if (!data
->rectflag
)
4315 } else if (sy
> ty
+ screen_size_y(s
) - 1) {
4316 relpos
= WINDOW_COPY_REL_POS_BELOW
;
4317 if (!data
->rectflag
)
4318 sx
= screen_size_x(s
) - 1;
4319 sy
= screen_size_y(s
) - 1;
4321 relpos
= WINDOW_COPY_REL_POS_ON_SCREEN
;
4331 window_copy_update_selection(struct window_mode_entry
*wme
, int may_redraw
,
4334 struct window_copy_mode_data
*data
= wme
->data
;
4335 struct screen
*s
= &data
->screen
;
4337 if (s
->sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
)
4339 return (window_copy_set_selection(wme
, may_redraw
, no_reset
));
4343 window_copy_set_selection(struct window_mode_entry
*wme
, int may_redraw
,
4346 struct window_pane
*wp
= wme
->wp
;
4347 struct window_copy_mode_data
*data
= wme
->data
;
4348 struct screen
*s
= &data
->screen
;
4349 struct options
*oo
= wp
->window
->options
;
4350 struct grid_cell gc
;
4351 u_int sx
, sy
, cy
, endsx
, endsy
;
4352 int startrelpos
, endrelpos
;
4354 window_copy_synchronize_cursor(wme
, no_reset
);
4356 /* Adjust the selection. */
4359 startrelpos
= window_copy_adjust_selection(wme
, &sx
, &sy
);
4361 /* Adjust the end of selection. */
4362 endsx
= data
->endselx
;
4363 endsy
= data
->endsely
;
4364 endrelpos
= window_copy_adjust_selection(wme
, &endsx
, &endsy
);
4366 /* Selection is outside of the current screen */
4367 if (startrelpos
== endrelpos
&&
4368 startrelpos
!= WINDOW_COPY_REL_POS_ON_SCREEN
) {
4369 screen_hide_selection(s
);
4373 /* Set colours and selection. */
4374 style_apply(&gc
, oo
, "mode-style", NULL
);
4375 gc
.flags
|= GRID_FLAG_NOPALETTE
;
4376 screen_set_selection(s
, sx
, sy
, endsx
, endsy
, data
->rectflag
,
4377 data
->modekeys
, &gc
);
4379 if (data
->rectflag
&& may_redraw
) {
4381 * Can't rely on the caller to redraw the right lines for
4382 * rectangle selection - find the highest line and the number
4383 * of lines, and redraw just past that in both directions
4386 if (data
->cursordrag
== CURSORDRAG_ENDSEL
) {
4388 window_copy_redraw_lines(wme
, sy
, cy
- sy
+ 1);
4390 window_copy_redraw_lines(wme
, cy
, sy
- cy
+ 1);
4393 window_copy_redraw_lines(wme
, endsy
,
4396 window_copy_redraw_lines(wme
, cy
,
4406 window_copy_get_selection(struct window_mode_entry
*wme
, size_t *len
)
4408 struct window_pane
*wp
= wme
->wp
;
4409 struct window_copy_mode_data
*data
= wme
->data
;
4410 struct screen
*s
= &data
->screen
;
4413 u_int i
, xx
, yy
, sx
, sy
, ex
, ey
, ey_last
;
4414 u_int firstsx
, lastex
, restex
, restsx
, selx
;
4417 if (data
->screen
.sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
) {
4418 buf
= window_copy_match_at_cursor(data
);
4432 * The selection extends from selx,sely to (adjusted) cx,cy on
4436 /* Find start and end. */
4439 if (yy
< data
->sely
|| (yy
== data
->sely
&& xx
< data
->selx
)) {
4441 ex
= data
->selx
; ey
= data
->sely
;
4443 sx
= data
->selx
; sy
= data
->sely
;
4447 /* Trim ex to end of line. */
4448 ey_last
= window_copy_find_length(wme
, ey
);
4453 * Deal with rectangle-copy if necessary; four situations: start of
4454 * first line (firstsx), end of last line (lastex), start (restsx) and
4455 * end (restex) of all other lines.
4457 xx
= screen_size_x(s
);
4460 * Behave according to mode-keys. If it is emacs, copy like emacs,
4461 * keeping the top-left-most character, and dropping the
4462 * bottom-right-most, regardless of copy direction. If it is vi, also
4463 * keep bottom-right-most character.
4465 keys
= options_get_number(wp
->window
->options
, "mode-keys");
4466 if (data
->rectflag
) {
4468 * Need to ignore the column with the cursor in it, which for
4469 * rectangular copy means knowing which side the cursor is on.
4471 if (data
->cursordrag
== CURSORDRAG_ENDSEL
)
4474 selx
= data
->endselx
;
4475 if (selx
< data
->cx
) {
4476 /* Selection start is on the left. */
4477 if (keys
== MODEKEY_EMACS
) {
4482 lastex
= data
->cx
+ 1;
4483 restex
= data
->cx
+ 1;
4488 /* Cursor is on the left. */
4495 if (keys
== MODEKEY_EMACS
)
4504 /* Copy the lines. */
4505 for (i
= sy
; i
<= ey
; i
++) {
4506 window_copy_copy_line(wme
, &buf
, &off
, i
,
4507 (i
== sy
? firstsx
: restsx
),
4508 (i
== ey
? lastex
: restex
));
4511 /* Don't bother if no data. */
4517 /* Remove final \n (unless at end in vi mode). */
4518 if (keys
== MODEKEY_EMACS
|| lastex
<= ey_last
) {
4519 if (~grid_get_line(data
->backing
->grid
, ey
)->flags
&
4520 GRID_LINE_WRAPPED
|| lastex
!= ey_last
)
4528 window_copy_copy_buffer(struct window_mode_entry
*wme
, const char *prefix
,
4529 void *buf
, size_t len
)
4531 struct window_pane
*wp
= wme
->wp
;
4532 struct screen_write_ctx ctx
;
4534 if (options_get_number(global_options
, "set-clipboard") != 0) {
4535 screen_write_start_pane(&ctx
, wp
, NULL
);
4536 screen_write_setselection(&ctx
, buf
, len
);
4537 screen_write_stop(&ctx
);
4538 notify_pane("pane-set-clipboard", wp
);
4541 paste_add(prefix
, buf
, len
);
4545 window_copy_pipe_run(struct window_mode_entry
*wme
, struct session
*s
,
4546 const char *cmd
, size_t *len
)
4551 buf
= window_copy_get_selection(wme
, len
);
4552 if (cmd
== NULL
|| *cmd
== '\0')
4553 cmd
= options_get_string(global_options
, "copy-command");
4554 if (cmd
!= NULL
&& *cmd
!= '\0') {
4555 job
= job_run(cmd
, 0, NULL
, NULL
, s
, NULL
, NULL
, NULL
, NULL
,
4556 NULL
, JOB_NOWAIT
, -1, -1);
4557 bufferevent_write(job_get_event(job
), buf
, *len
);
4563 window_copy_pipe(struct window_mode_entry
*wme
, struct session
*s
,
4568 window_copy_pipe_run(wme
, s
, cmd
, &len
);
4572 window_copy_copy_pipe(struct window_mode_entry
*wme
, struct session
*s
,
4573 const char *prefix
, const char *cmd
)
4578 buf
= window_copy_pipe_run(wme
, s
, cmd
, &len
);
4580 window_copy_copy_buffer(wme
, prefix
, buf
, len
);
4584 window_copy_copy_selection(struct window_mode_entry
*wme
, const char *prefix
)
4589 buf
= window_copy_get_selection(wme
, &len
);
4591 window_copy_copy_buffer(wme
, prefix
, buf
, len
);
4595 window_copy_append_selection(struct window_mode_entry
*wme
)
4597 struct window_pane
*wp
= wme
->wp
;
4599 struct paste_buffer
*pb
;
4600 const char *bufdata
, *bufname
= NULL
;
4601 size_t len
, bufsize
;
4602 struct screen_write_ctx ctx
;
4604 buf
= window_copy_get_selection(wme
, &len
);
4608 if (options_get_number(global_options
, "set-clipboard") != 0) {
4609 screen_write_start_pane(&ctx
, wp
, NULL
);
4610 screen_write_setselection(&ctx
, buf
, len
);
4611 screen_write_stop(&ctx
);
4612 notify_pane("pane-set-clipboard", wp
);
4615 pb
= paste_get_top(&bufname
);
4617 bufdata
= paste_buffer_data(pb
, &bufsize
);
4618 buf
= xrealloc(buf
, len
+ bufsize
);
4619 memmove(buf
+ bufsize
, buf
, len
);
4620 memcpy(buf
, bufdata
, bufsize
);
4623 if (paste_set(buf
, len
, bufname
, NULL
) != 0)
4628 window_copy_copy_line(struct window_mode_entry
*wme
, char **buf
, size_t *off
,
4629 u_int sy
, u_int sx
, u_int ex
)
4631 struct window_copy_mode_data
*data
= wme
->data
;
4632 struct grid
*gd
= data
->backing
->grid
;
4633 struct grid_cell gc
;
4634 struct grid_line
*gl
;
4635 struct utf8_data ud
;
4636 u_int i
, xx
, wrapped
= 0;
4643 * Work out if the line was wrapped at the screen edge and all of it is
4646 gl
= grid_get_line(gd
, sy
);
4647 if (gl
->flags
& GRID_LINE_WRAPPED
&& gl
->cellsize
<= gd
->sx
)
4650 /* If the line was wrapped, don't strip spaces (use the full length). */
4654 xx
= window_copy_find_length(wme
, sy
);
4661 for (i
= sx
; i
< ex
; i
++) {
4662 grid_get_cell(gd
, i
, sy
, &gc
);
4663 if (gc
.flags
& GRID_FLAG_PADDING
)
4665 utf8_copy(&ud
, &gc
.data
);
4666 if (ud
.size
== 1 && (gc
.attr
& GRID_ATTR_CHARSET
)) {
4667 s
= tty_acs_get(NULL
, ud
.data
[0]);
4668 if (s
!= NULL
&& strlen(s
) <= sizeof ud
.data
) {
4669 ud
.size
= strlen(s
);
4670 memcpy(ud
.data
, s
, ud
.size
);
4674 *buf
= xrealloc(*buf
, (*off
) + ud
.size
);
4675 memcpy(*buf
+ *off
, ud
.data
, ud
.size
);
4680 /* Only add a newline if the line wasn't wrapped. */
4681 if (!wrapped
|| ex
!= xx
) {
4682 *buf
= xrealloc(*buf
, (*off
) + 1);
4683 (*buf
)[(*off
)++] = '\n';
4688 window_copy_clear_selection(struct window_mode_entry
*wme
)
4690 struct window_copy_mode_data
*data
= wme
->data
;
4693 screen_clear_selection(&data
->screen
);
4695 data
->cursordrag
= CURSORDRAG_NONE
;
4696 data
->lineflag
= LINE_SEL_NONE
;
4697 data
->selflag
= SEL_CHAR
;
4699 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4700 px
= window_copy_find_length(wme
, py
);
4702 window_copy_update_cursor(wme
, px
, data
->cy
);
4706 window_copy_in_set(struct window_mode_entry
*wme
, u_int px
, u_int py
,
4709 struct window_copy_mode_data
*data
= wme
->data
;
4710 struct grid_cell gc
;
4712 grid_get_cell(data
->backing
->grid
, px
, py
, &gc
);
4713 if (gc
.flags
& GRID_FLAG_PADDING
)
4715 return (utf8_cstrhas(set
, &gc
.data
));
4719 window_copy_find_length(struct window_mode_entry
*wme
, u_int py
)
4721 struct window_copy_mode_data
*data
= wme
->data
;
4723 return (grid_line_length(data
->backing
->grid
, py
));
4727 window_copy_cursor_start_of_line(struct window_mode_entry
*wme
)
4729 struct window_copy_mode_data
*data
= wme
->data
;
4730 struct screen
*back_s
= data
->backing
;
4731 struct grid_reader gr
;
4732 u_int px
, py
, oldy
, hsize
;
4735 hsize
= screen_hsize(back_s
);
4736 py
= hsize
+ data
->cy
- data
->oy
;
4739 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4740 grid_reader_cursor_start_of_line(&gr
, 1);
4741 grid_reader_get_cursor(&gr
, &px
, &py
);
4742 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
4746 window_copy_cursor_back_to_indentation(struct window_mode_entry
*wme
)
4748 struct window_copy_mode_data
*data
= wme
->data
;
4749 struct screen
*back_s
= data
->backing
;
4750 struct grid_reader gr
;
4751 u_int px
, py
, oldy
, hsize
;
4754 hsize
= screen_hsize(back_s
);
4755 py
= hsize
+ data
->cy
- data
->oy
;
4758 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4759 grid_reader_cursor_back_to_indentation(&gr
);
4760 grid_reader_get_cursor(&gr
, &px
, &py
);
4761 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
4765 window_copy_cursor_end_of_line(struct window_mode_entry
*wme
)
4767 struct window_copy_mode_data
*data
= wme
->data
;
4768 struct screen
*back_s
= data
->backing
;
4769 struct grid_reader gr
;
4770 u_int px
, py
, oldy
, hsize
;
4773 hsize
= screen_hsize(back_s
);
4774 py
= hsize
+ data
->cy
- data
->oy
;
4777 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4778 if (data
->screen
.sel
!= NULL
&& data
->rectflag
)
4779 grid_reader_cursor_end_of_line(&gr
, 1, 1);
4781 grid_reader_cursor_end_of_line(&gr
, 1, 0);
4782 grid_reader_get_cursor(&gr
, &px
, &py
);
4783 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
4784 data
->oy
, oldy
, px
, py
, 0);
4788 window_copy_other_end(struct window_mode_entry
*wme
)
4790 struct window_copy_mode_data
*data
= wme
->data
;
4791 struct screen
*s
= &data
->screen
;
4792 u_int selx
, sely
, cy
, yy
, hsize
;
4794 if (s
->sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
)
4797 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
4798 data
->lineflag
= LINE_SEL_RIGHT_LEFT
;
4799 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
4800 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
4802 switch (data
->cursordrag
) {
4803 case CURSORDRAG_NONE
:
4804 case CURSORDRAG_SEL
:
4805 data
->cursordrag
= CURSORDRAG_ENDSEL
;
4807 case CURSORDRAG_ENDSEL
:
4808 data
->cursordrag
= CURSORDRAG_SEL
;
4812 selx
= data
->endselx
;
4813 sely
= data
->endsely
;
4814 if (data
->cursordrag
== CURSORDRAG_SEL
) {
4820 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4824 hsize
= screen_hsize(data
->backing
);
4825 if (sely
< hsize
- data
->oy
) { /* above */
4826 data
->oy
= hsize
- sely
;
4828 } else if (sely
> hsize
- data
->oy
+ screen_size_y(s
)) { /* below */
4829 data
->oy
= hsize
- sely
+ screen_size_y(s
) - 1;
4830 data
->cy
= screen_size_y(s
) - 1;
4832 data
->cy
= cy
+ sely
- yy
;
4834 window_copy_update_selection(wme
, 1, 1);
4835 window_copy_redraw_screen(wme
);
4839 window_copy_cursor_left(struct window_mode_entry
*wme
)
4841 struct window_copy_mode_data
*data
= wme
->data
;
4842 struct screen
*back_s
= data
->backing
;
4843 struct grid_reader gr
;
4844 u_int px
, py
, oldy
, hsize
;
4847 hsize
= screen_hsize(back_s
);
4848 py
= hsize
+ data
->cy
- data
->oy
;
4851 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4852 grid_reader_cursor_left(&gr
, 1);
4853 grid_reader_get_cursor(&gr
, &px
, &py
);
4854 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
4858 window_copy_cursor_right(struct window_mode_entry
*wme
, int all
)
4860 struct window_copy_mode_data
*data
= wme
->data
;
4861 struct screen
*back_s
= data
->backing
;
4862 struct grid_reader gr
;
4863 u_int px
, py
, oldy
, hsize
;
4866 hsize
= screen_hsize(back_s
);
4867 py
= hsize
+ data
->cy
- data
->oy
;
4870 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4871 grid_reader_cursor_right(&gr
, 1, all
);
4872 grid_reader_get_cursor(&gr
, &px
, &py
);
4873 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
4874 data
->oy
, oldy
, px
, py
, 0);
4878 window_copy_cursor_up(struct window_mode_entry
*wme
, int scroll_only
)
4880 struct window_copy_mode_data
*data
= wme
->data
;
4881 struct screen
*s
= &data
->screen
;
4882 u_int ox
, oy
, px
, py
;
4885 norectsel
= data
->screen
.sel
== NULL
|| !data
->rectflag
;
4886 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4887 ox
= window_copy_find_length(wme
, oy
);
4888 if (norectsel
&& data
->cx
!= ox
) {
4889 data
->lastcx
= data
->cx
;
4893 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
&& oy
== data
->sely
)
4894 window_copy_other_end(wme
);
4896 if (scroll_only
|| data
->cy
== 0) {
4898 data
->cx
= data
->lastcx
;
4899 window_copy_scroll_down(wme
, 1);
4901 if (data
->cy
== screen_size_y(s
) - 1)
4902 window_copy_redraw_lines(wme
, data
->cy
, 1);
4904 window_copy_redraw_lines(wme
, data
->cy
, 2);
4908 window_copy_update_cursor(wme
, data
->lastcx
,
4911 window_copy_update_cursor(wme
, data
->cx
, data
->cy
- 1);
4912 if (window_copy_update_selection(wme
, 1, 0)) {
4913 if (data
->cy
== screen_size_y(s
) - 1)
4914 window_copy_redraw_lines(wme
, data
->cy
, 1);
4916 window_copy_redraw_lines(wme
, data
->cy
, 2);
4921 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4922 px
= window_copy_find_length(wme
, py
);
4923 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
4926 window_copy_update_cursor(wme
, px
, data
->cy
);
4927 if (window_copy_update_selection(wme
, 1, 0))
4928 window_copy_redraw_lines(wme
, data
->cy
, 1);
4932 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
4934 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4936 px
= screen_size_x(data
->backing
);
4938 px
= window_copy_find_length(wme
, py
);
4939 window_copy_update_cursor(wme
, px
, data
->cy
);
4940 if (window_copy_update_selection(wme
, 1, 0))
4941 window_copy_redraw_lines(wme
, data
->cy
, 1);
4943 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
4945 window_copy_update_cursor(wme
, 0, data
->cy
);
4946 if (window_copy_update_selection(wme
, 1, 0))
4947 window_copy_redraw_lines(wme
, data
->cy
, 1);
4952 window_copy_cursor_down(struct window_mode_entry
*wme
, int scroll_only
)
4954 struct window_copy_mode_data
*data
= wme
->data
;
4955 struct screen
*s
= &data
->screen
;
4956 u_int ox
, oy
, px
, py
;
4959 norectsel
= data
->screen
.sel
== NULL
|| !data
->rectflag
;
4960 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4961 ox
= window_copy_find_length(wme
, oy
);
4962 if (norectsel
&& data
->cx
!= ox
) {
4963 data
->lastcx
= data
->cx
;
4967 if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
&& oy
== data
->endsely
)
4968 window_copy_other_end(wme
);
4970 if (scroll_only
|| data
->cy
== screen_size_y(s
) - 1) {
4972 data
->cx
= data
->lastcx
;
4973 window_copy_scroll_up(wme
, 1);
4974 if (scroll_only
&& data
->cy
> 0)
4975 window_copy_redraw_lines(wme
, data
->cy
- 1, 2);
4978 window_copy_update_cursor(wme
, data
->lastcx
,
4981 window_copy_update_cursor(wme
, data
->cx
, data
->cy
+ 1);
4982 if (window_copy_update_selection(wme
, 1, 0))
4983 window_copy_redraw_lines(wme
, data
->cy
- 1, 2);
4987 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4988 px
= window_copy_find_length(wme
, py
);
4989 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
4992 window_copy_update_cursor(wme
, px
, data
->cy
);
4993 if (window_copy_update_selection(wme
, 1, 0))
4994 window_copy_redraw_lines(wme
, data
->cy
, 1);
4998 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
5000 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5002 px
= screen_size_x(data
->backing
);
5004 px
= window_copy_find_length(wme
, py
);
5005 window_copy_update_cursor(wme
, px
, data
->cy
);
5006 if (window_copy_update_selection(wme
, 1, 0))
5007 window_copy_redraw_lines(wme
, data
->cy
, 1);
5009 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
5011 window_copy_update_cursor(wme
, 0, data
->cy
);
5012 if (window_copy_update_selection(wme
, 1, 0))
5013 window_copy_redraw_lines(wme
, data
->cy
, 1);
5018 window_copy_cursor_jump(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 if (grid_reader_cursor_jump(&gr
, data
->jumpchar
)) {
5032 grid_reader_get_cursor(&gr
, &px
, &py
);
5033 window_copy_acquire_cursor_down(wme
, hsize
,
5034 screen_size_y(back_s
), data
->oy
, oldy
, px
, py
, 0);
5039 window_copy_cursor_jump_back(struct window_mode_entry
*wme
)
5041 struct window_copy_mode_data
*data
= wme
->data
;
5042 struct screen
*back_s
= data
->backing
;
5043 struct grid_reader gr
;
5044 u_int px
, py
, oldy
, hsize
;
5047 hsize
= screen_hsize(back_s
);
5048 py
= hsize
+ data
->cy
- data
->oy
;
5051 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5052 grid_reader_cursor_left(&gr
, 0);
5053 if (grid_reader_cursor_jump_back(&gr
, data
->jumpchar
)) {
5054 grid_reader_get_cursor(&gr
, &px
, &py
);
5055 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
,
5061 window_copy_cursor_jump_to(struct window_mode_entry
*wme
)
5063 struct window_copy_mode_data
*data
= wme
->data
;
5064 struct screen
*back_s
= data
->backing
;
5065 struct grid_reader gr
;
5066 u_int px
, py
, oldy
, hsize
;
5069 hsize
= screen_hsize(back_s
);
5070 py
= hsize
+ data
->cy
- data
->oy
;
5073 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5074 if (grid_reader_cursor_jump(&gr
, data
->jumpchar
)) {
5075 grid_reader_cursor_left(&gr
, 1);
5076 grid_reader_get_cursor(&gr
, &px
, &py
);
5077 window_copy_acquire_cursor_down(wme
, hsize
,
5078 screen_size_y(back_s
), data
->oy
, oldy
, px
, py
, 0);
5083 window_copy_cursor_jump_to_back(struct window_mode_entry
*wme
)
5085 struct window_copy_mode_data
*data
= wme
->data
;
5086 struct screen
*back_s
= data
->backing
;
5087 struct grid_reader gr
;
5088 u_int px
, py
, oldy
, hsize
;
5091 hsize
= screen_hsize(back_s
);
5092 py
= hsize
+ data
->cy
- data
->oy
;
5095 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5096 grid_reader_cursor_left(&gr
, 0);
5097 grid_reader_cursor_left(&gr
, 0);
5098 if (grid_reader_cursor_jump_back(&gr
, data
->jumpchar
)) {
5099 grid_reader_cursor_right(&gr
, 1, 0);
5100 grid_reader_get_cursor(&gr
, &px
, &py
);
5101 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
,
5107 window_copy_cursor_next_word(struct window_mode_entry
*wme
,
5108 const char *separators
)
5110 struct window_copy_mode_data
*data
= wme
->data
;
5111 struct screen
*back_s
= data
->backing
;
5112 struct grid_reader gr
;
5113 u_int px
, py
, oldy
, hsize
;
5116 hsize
= screen_hsize(back_s
);
5117 py
= hsize
+ data
->cy
- data
->oy
;
5120 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5121 grid_reader_cursor_next_word(&gr
, separators
);
5122 grid_reader_get_cursor(&gr
, &px
, &py
);
5123 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
5124 data
->oy
, oldy
, px
, py
, 0);
5127 /* Compute the next place where a word ends. */
5129 window_copy_cursor_next_word_end_pos(struct window_mode_entry
*wme
,
5130 const char *separators
, u_int
*ppx
, u_int
*ppy
)
5132 struct window_pane
*wp
= wme
->wp
;
5133 struct window_copy_mode_data
*data
= wme
->data
;
5134 struct options
*oo
= wp
->window
->options
;
5135 struct screen
*back_s
= data
->backing
;
5136 struct grid_reader gr
;
5137 u_int px
, py
, hsize
;
5140 hsize
= screen_hsize(back_s
);
5141 py
= hsize
+ data
->cy
- data
->oy
;
5143 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5144 if (options_get_number(oo
, "mode-keys") == MODEKEY_VI
) {
5145 if (!grid_reader_in_set(&gr
, WHITESPACE
))
5146 grid_reader_cursor_right(&gr
, 0, 0);
5147 grid_reader_cursor_next_word_end(&gr
, separators
);
5148 grid_reader_cursor_left(&gr
, 1);
5150 grid_reader_cursor_next_word_end(&gr
, separators
);
5151 grid_reader_get_cursor(&gr
, &px
, &py
);
5156 /* Move to the next place where a word ends. */
5158 window_copy_cursor_next_word_end(struct window_mode_entry
*wme
,
5159 const char *separators
, int no_reset
)
5161 struct window_pane
*wp
= wme
->wp
;
5162 struct window_copy_mode_data
*data
= wme
->data
;
5163 struct options
*oo
= wp
->window
->options
;
5164 struct screen
*back_s
= data
->backing
;
5165 struct grid_reader gr
;
5166 u_int px
, py
, oldy
, hsize
;
5169 hsize
= screen_hsize(back_s
);
5170 py
= hsize
+ data
->cy
- data
->oy
;
5173 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5174 if (options_get_number(oo
, "mode-keys") == MODEKEY_VI
) {
5175 if (!grid_reader_in_set(&gr
, WHITESPACE
))
5176 grid_reader_cursor_right(&gr
, 0, 0);
5177 grid_reader_cursor_next_word_end(&gr
, separators
);
5178 grid_reader_cursor_left(&gr
, 1);
5180 grid_reader_cursor_next_word_end(&gr
, separators
);
5181 grid_reader_get_cursor(&gr
, &px
, &py
);
5182 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
5183 data
->oy
, oldy
, px
, py
, no_reset
);
5186 /* Compute the previous place where a word begins. */
5188 window_copy_cursor_previous_word_pos(struct window_mode_entry
*wme
,
5189 const char *separators
, u_int
*ppx
, u_int
*ppy
)
5191 struct window_copy_mode_data
*data
= wme
->data
;
5192 struct screen
*back_s
= data
->backing
;
5193 struct grid_reader gr
;
5194 u_int px
, py
, hsize
;
5197 hsize
= screen_hsize(back_s
);
5198 py
= hsize
+ data
->cy
- data
->oy
;
5200 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5201 grid_reader_cursor_previous_word(&gr
, separators
, /* already= */ 0,
5202 /* stop_at_eol= */ 1);
5203 grid_reader_get_cursor(&gr
, &px
, &py
);
5208 /* Move to the previous place where a word begins. */
5210 window_copy_cursor_previous_word(struct window_mode_entry
*wme
,
5211 const char *separators
, int already
)
5213 struct window_copy_mode_data
*data
= wme
->data
;
5214 struct window
*w
= wme
->wp
->window
;
5215 struct screen
*back_s
= data
->backing
;
5216 struct grid_reader gr
;
5217 u_int px
, py
, oldy
, hsize
;
5220 if (options_get_number(w
->options
, "mode-keys") == MODEKEY_EMACS
)
5226 hsize
= screen_hsize(back_s
);
5227 py
= hsize
+ data
->cy
- data
->oy
;
5230 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5231 grid_reader_cursor_previous_word(&gr
, separators
, already
, stop_at_eol
);
5232 grid_reader_get_cursor(&gr
, &px
, &py
);
5233 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
5237 window_copy_scroll_up(struct window_mode_entry
*wme
, u_int ny
)
5239 struct window_pane
*wp
= wme
->wp
;
5240 struct window_copy_mode_data
*data
= wme
->data
;
5241 struct screen
*s
= &data
->screen
;
5242 struct screen_write_ctx ctx
;
5250 if (data
->searchmark
!= NULL
&& !data
->timeout
)
5251 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
5252 window_copy_update_selection(wme
, 0, 0);
5254 screen_write_start_pane(&ctx
, wp
, NULL
);
5255 screen_write_cursormove(&ctx
, 0, 0, 0);
5256 screen_write_deleteline(&ctx
, ny
, 8);
5257 window_copy_write_lines(wme
, &ctx
, screen_size_y(s
) - ny
, ny
);
5258 window_copy_write_line(wme
, &ctx
, 0);
5259 if (screen_size_y(s
) > 1)
5260 window_copy_write_line(wme
, &ctx
, 1);
5261 if (screen_size_y(s
) > 3)
5262 window_copy_write_line(wme
, &ctx
, screen_size_y(s
) - 2);
5263 if (s
->sel
!= NULL
&& screen_size_y(s
) > ny
)
5264 window_copy_write_line(wme
, &ctx
, screen_size_y(s
) - ny
- 1);
5265 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
5266 screen_write_stop(&ctx
);
5270 window_copy_scroll_down(struct window_mode_entry
*wme
, u_int ny
)
5272 struct window_pane
*wp
= wme
->wp
;
5273 struct window_copy_mode_data
*data
= wme
->data
;
5274 struct screen
*s
= &data
->screen
;
5275 struct screen_write_ctx ctx
;
5277 if (ny
> screen_hsize(data
->backing
))
5280 if (data
->oy
> screen_hsize(data
->backing
) - ny
)
5281 ny
= screen_hsize(data
->backing
) - data
->oy
;
5286 if (data
->searchmark
!= NULL
&& !data
->timeout
)
5287 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
5288 window_copy_update_selection(wme
, 0, 0);
5290 screen_write_start_pane(&ctx
, wp
, NULL
);
5291 screen_write_cursormove(&ctx
, 0, 0, 0);
5292 screen_write_insertline(&ctx
, ny
, 8);
5293 window_copy_write_lines(wme
, &ctx
, 0, ny
);
5294 if (s
->sel
!= NULL
&& screen_size_y(s
) > ny
)
5295 window_copy_write_line(wme
, &ctx
, ny
);
5296 else if (ny
== 1) /* nuke position */
5297 window_copy_write_line(wme
, &ctx
, 1);
5298 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
5299 screen_write_stop(&ctx
);
5303 window_copy_rectangle_set(struct window_mode_entry
*wme
, int rectflag
)
5305 struct window_copy_mode_data
*data
= wme
->data
;
5308 data
->rectflag
= rectflag
;
5310 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5311 px
= window_copy_find_length(wme
, py
);
5313 window_copy_update_cursor(wme
, px
, data
->cy
);
5315 window_copy_update_selection(wme
, 1, 0);
5316 window_copy_redraw_screen(wme
);
5320 window_copy_move_mouse(struct mouse_event
*m
)
5322 struct window_pane
*wp
;
5323 struct window_mode_entry
*wme
;
5326 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5329 wme
= TAILQ_FIRST(&wp
->modes
);
5332 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5335 if (cmd_mouse_at(wp
, m
, &x
, &y
, 0) != 0)
5338 window_copy_update_cursor(wme
, x
, y
);
5342 window_copy_start_drag(struct client
*c
, struct mouse_event
*m
)
5344 struct window_pane
*wp
;
5345 struct window_mode_entry
*wme
;
5346 struct window_copy_mode_data
*data
;
5352 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5355 wme
= TAILQ_FIRST(&wp
->modes
);
5358 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5361 if (cmd_mouse_at(wp
, m
, &x
, &y
, 1) != 0)
5364 c
->tty
.mouse_drag_update
= window_copy_drag_update
;
5365 c
->tty
.mouse_drag_release
= window_copy_drag_release
;
5368 yg
= screen_hsize(data
->backing
) + y
- data
->oy
;
5369 if (x
< data
->selrx
|| x
> data
->endselrx
|| yg
!= data
->selry
)
5370 data
->selflag
= SEL_CHAR
;
5371 switch (data
->selflag
) {
5373 if (data
->separators
!= NULL
) {
5374 window_copy_update_cursor(wme
, x
, y
);
5375 window_copy_cursor_previous_word_pos(wme
,
5376 data
->separators
, &x
, &y
);
5377 y
-= screen_hsize(data
->backing
) - data
->oy
;
5379 window_copy_update_cursor(wme
, x
, y
);
5382 window_copy_update_cursor(wme
, 0, y
);
5385 window_copy_update_cursor(wme
, x
, y
);
5386 window_copy_start_selection(wme
);
5390 window_copy_redraw_screen(wme
);
5391 window_copy_drag_update(c
, m
);
5395 window_copy_drag_update(struct client
*c
, struct mouse_event
*m
)
5397 struct window_pane
*wp
;
5398 struct window_mode_entry
*wme
;
5399 struct window_copy_mode_data
*data
;
5400 u_int x
, y
, old_cx
, old_cy
;
5401 struct timeval tv
= {
5402 .tv_usec
= WINDOW_COPY_DRAG_REPEAT_TIME
5408 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5411 wme
= TAILQ_FIRST(&wp
->modes
);
5414 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5418 evtimer_del(&data
->dragtimer
);
5420 if (cmd_mouse_at(wp
, m
, &x
, &y
, 0) != 0)
5425 window_copy_update_cursor(wme
, x
, y
);
5426 if (window_copy_update_selection(wme
, 1, 0))
5427 window_copy_redraw_selection(wme
, old_cy
);
5428 if (old_cy
!= data
->cy
|| old_cx
== data
->cx
) {
5430 evtimer_add(&data
->dragtimer
, &tv
);
5431 window_copy_cursor_up(wme
, 1);
5432 } else if (y
== screen_size_y(&data
->screen
) - 1) {
5433 evtimer_add(&data
->dragtimer
, &tv
);
5434 window_copy_cursor_down(wme
, 1);
5440 window_copy_drag_release(struct client
*c
, struct mouse_event
*m
)
5442 struct window_pane
*wp
;
5443 struct window_mode_entry
*wme
;
5444 struct window_copy_mode_data
*data
;
5449 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5452 wme
= TAILQ_FIRST(&wp
->modes
);
5455 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5459 evtimer_del(&data
->dragtimer
);
5463 window_copy_jump_to_mark(struct window_mode_entry
*wme
)
5465 struct window_copy_mode_data
*data
= wme
->data
;
5469 tmy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5470 data
->cx
= data
->mx
;
5471 if (data
->my
< screen_hsize(data
->backing
)) {
5473 data
->oy
= screen_hsize(data
->backing
) - data
->my
;
5475 data
->cy
= data
->my
- screen_hsize(data
->backing
);
5481 window_copy_update_selection(wme
, 0, 0);
5482 window_copy_redraw_screen(wme
);
5485 /* Scroll up if the cursor went off the visible screen. */
5487 window_copy_acquire_cursor_up(struct window_mode_entry
*wme
, u_int hsize
,
5488 u_int oy
, u_int oldy
, u_int px
, u_int py
)
5490 u_int cy
, yy
, ny
, nd
;
5503 window_copy_cursor_up(wme
, 1);
5506 window_copy_update_cursor(wme
, px
, cy
);
5507 if (window_copy_update_selection(wme
, 1, 0))
5508 window_copy_redraw_lines(wme
, cy
, nd
);
5511 /* Scroll down if the cursor went off the visible screen. */
5513 window_copy_acquire_cursor_down(struct window_mode_entry
*wme
, u_int hsize
,
5514 u_int sy
, u_int oy
, u_int oldy
, u_int px
, u_int py
, int no_reset
)
5516 u_int cy
, yy
, ny
, nd
;
5518 cy
= py
- hsize
+ oy
;
5529 window_copy_cursor_down(wme
, 1);
5533 window_copy_update_cursor(wme
, px
, yy
);
5535 window_copy_update_cursor(wme
, px
, cy
);
5536 if (window_copy_update_selection(wme
, 1, no_reset
))
5537 window_copy_redraw_lines(wme
, oldy
, nd
);