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_pagedown1(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_cursor_prompt(struct window_mode_entry
*, int,
136 static void window_copy_scroll_up(struct window_mode_entry
*, u_int
);
137 static void window_copy_scroll_down(struct window_mode_entry
*, u_int
);
138 static void window_copy_rectangle_set(struct window_mode_entry
*, int);
139 static void window_copy_move_mouse(struct mouse_event
*);
140 static void window_copy_drag_update(struct client
*, struct mouse_event
*);
141 static void window_copy_drag_release(struct client
*, struct mouse_event
*);
142 static void window_copy_jump_to_mark(struct window_mode_entry
*);
143 static void window_copy_acquire_cursor_up(struct window_mode_entry
*,
144 u_int
, u_int
, u_int
, u_int
, u_int
);
145 static void window_copy_acquire_cursor_down(struct window_mode_entry
*,
146 u_int
, u_int
, u_int
, u_int
, u_int
, u_int
, int);
148 const struct window_mode window_copy_mode
= {
151 .init
= window_copy_init
,
152 .free
= window_copy_free
,
153 .resize
= window_copy_resize
,
154 .key_table
= window_copy_key_table
,
155 .command
= window_copy_command
,
156 .formats
= window_copy_formats
,
159 const struct window_mode window_view_mode
= {
162 .init
= window_copy_view_init
,
163 .free
= window_copy_free
,
164 .resize
= window_copy_resize
,
165 .key_table
= window_copy_key_table
,
166 .command
= window_copy_command
,
167 .formats
= window_copy_formats
,
172 WINDOW_COPY_SEARCHUP
,
173 WINDOW_COPY_SEARCHDOWN
,
174 WINDOW_COPY_JUMPFORWARD
,
175 WINDOW_COPY_JUMPBACKWARD
,
176 WINDOW_COPY_JUMPTOFORWARD
,
177 WINDOW_COPY_JUMPTOBACKWARD
,
181 WINDOW_COPY_REL_POS_ABOVE
,
182 WINDOW_COPY_REL_POS_ON_SCREEN
,
183 WINDOW_COPY_REL_POS_BELOW
,
186 enum window_copy_cmd_action
{
187 WINDOW_COPY_CMD_NOTHING
,
188 WINDOW_COPY_CMD_REDRAW
,
189 WINDOW_COPY_CMD_CANCEL
,
192 enum window_copy_cmd_clear
{
193 WINDOW_COPY_CMD_CLEAR_ALWAYS
,
194 WINDOW_COPY_CMD_CLEAR_NEVER
,
195 WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
198 struct window_copy_cmd_state
{
199 struct window_mode_entry
*wme
;
201 struct mouse_event
*m
;
209 * Copy mode's visible screen (the "screen" field) is filled from one of two
210 * sources: the original contents of the pane (used when we actually enter via
211 * the "copy-mode" command, to copy the contents of the current pane), or else
212 * a series of lines containing the output from an output-writing tmux command
213 * (such as any of the "show-*" or "list-*" commands).
215 * In either case, the full content of the copy-mode grid is pointed at by the
216 * "backing" field, and is copied into "screen" as needed (that is, when
217 * scrolling occurs). When copy-mode is backed by a pane, backing points
218 * directly at that pane's screen structure (&wp->base); when backed by a list
219 * of output-lines from a command, it points at a newly-allocated screen
220 * structure (which is deallocated when the mode ends).
222 struct window_copy_mode_data
{
223 struct screen screen
;
225 struct screen
*backing
;
226 int backing_written
; /* backing display started */
227 struct screen
*writing
;
228 struct input_ctx
*ictx
;
230 int viewmode
; /* view mode entered */
232 u_int oy
; /* number of lines scrolled up */
234 u_int selx
; /* beginning of selection */
237 u_int endselx
; /* end of selection */
241 CURSORDRAG_NONE
, /* selection is independent of cursor */
242 CURSORDRAG_ENDSEL
, /* end is synchronized with cursor */
243 CURSORDRAG_SEL
, /* start is synchronized with cursor */
251 } lineflag
; /* line selection mode */
252 int rectflag
; /* in rectangle copy mode? */
253 int scroll_exit
; /* exit on scroll to end? */
254 int hide_position
; /* hide position marker */
257 SEL_CHAR
, /* select one char at a time */
258 SEL_WORD
, /* select one word at a time */
259 SEL_LINE
, /* select one line at a time */
262 const char *separators
; /* word separators */
264 u_int dx
; /* drag start position */
267 u_int selrx
; /* selection reset positions */
275 u_int lastcx
; /* position in last line w/ content */
276 u_int lastsx
; /* size of last line w/ content */
278 u_int mx
; /* mark position */
295 int timeout
; /* search has timed out */
296 #define WINDOW_COPY_SEARCH_TIMEOUT 10000
297 #define WINDOW_COPY_SEARCH_ALL_TIMEOUT 200
298 #define WINDOW_COPY_SEARCH_MAX_LINE 2000
301 struct utf8_data
*jumpchar
;
303 struct event dragtimer
;
304 #define WINDOW_COPY_DRAG_REPEAT_TIME 50000
308 window_copy_scroll_timer(__unused
int fd
, __unused
short events
, void *arg
)
310 struct window_mode_entry
*wme
= arg
;
311 struct window_pane
*wp
= wme
->wp
;
312 struct window_copy_mode_data
*data
= wme
->data
;
313 struct timeval tv
= {
314 .tv_usec
= WINDOW_COPY_DRAG_REPEAT_TIME
317 evtimer_del(&data
->dragtimer
);
319 if (TAILQ_FIRST(&wp
->modes
) != wme
)
323 evtimer_add(&data
->dragtimer
, &tv
);
324 window_copy_cursor_up(wme
, 1);
325 } else if (data
->cy
== screen_size_y(&data
->screen
) - 1) {
326 evtimer_add(&data
->dragtimer
, &tv
);
327 window_copy_cursor_down(wme
, 1);
331 static struct screen
*
332 window_copy_clone_screen(struct screen
*src
, struct screen
*hint
, u_int
*cx
,
336 const struct grid_line
*gl
;
340 dst
= xcalloc(1, sizeof *dst
);
342 sy
= screen_hsize(src
) + screen_size_y(src
);
344 while (sy
> screen_hsize(src
)) {
345 gl
= grid_peek_line(src
->grid
, sy
- 1);
346 if (gl
->cellused
!= 0)
351 log_debug("%s: target screen is %ux%u, source %ux%u", __func__
,
352 screen_size_x(src
), sy
, screen_size_x(hint
),
353 screen_hsize(src
) + screen_size_y(src
));
354 screen_init(dst
, screen_size_x(src
), sy
, screen_hlimit(src
));
357 * Ensure history is on for the backing grid so lines are not deleted
360 dst
->grid
->flags
|= GRID_HISTORY
;
361 grid_duplicate_lines(dst
->grid
, 0, src
->grid
, 0, sy
);
363 dst
->grid
->sy
= sy
- screen_hsize(src
);
364 dst
->grid
->hsize
= screen_hsize(src
);
365 dst
->grid
->hscrolled
= src
->grid
->hscrolled
;
366 if (src
->cy
> dst
->grid
->sy
- 1) {
368 dst
->cy
= dst
->grid
->sy
- 1;
374 if (cx
!= NULL
&& cy
!= NULL
) {
376 *cy
= screen_hsize(dst
) + dst
->cy
;
377 reflow
= (screen_size_x(hint
) != screen_size_x(dst
));
382 grid_wrap_position(dst
->grid
, *cx
, *cy
, &wx
, &wy
);
383 screen_resize_cursor(dst
, screen_size_x(hint
), screen_size_y(hint
), 1,
386 grid_unwrap_position(dst
->grid
, cx
, cy
, wx
, wy
);
391 static struct window_copy_mode_data
*
392 window_copy_common_init(struct window_mode_entry
*wme
)
394 struct window_pane
*wp
= wme
->wp
;
395 struct window_copy_mode_data
*data
;
396 struct screen
*base
= &wp
->base
;
398 wme
->data
= data
= xcalloc(1, sizeof *data
);
400 data
->cursordrag
= CURSORDRAG_NONE
;
401 data
->lineflag
= LINE_SEL_NONE
;
402 data
->selflag
= SEL_CHAR
;
404 if (wp
->searchstr
!= NULL
) {
405 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
406 data
->searchregex
= wp
->searchregex
;
407 data
->searchstr
= xstrdup(wp
->searchstr
);
409 data
->searchtype
= WINDOW_COPY_OFF
;
410 data
->searchregex
= 0;
411 data
->searchstr
= NULL
;
413 data
->searchx
= data
->searchy
= data
->searcho
= -1;
416 data
->jumptype
= WINDOW_COPY_OFF
;
417 data
->jumpchar
= NULL
;
419 screen_init(&data
->screen
, screen_size_x(base
), screen_size_y(base
), 0);
420 screen_set_default_cursor(&data
->screen
, global_w_options
);
421 data
->modekeys
= options_get_number(wp
->window
->options
, "mode-keys");
423 evtimer_set(&data
->dragtimer
, window_copy_scroll_timer
, wme
);
428 static struct screen
*
429 window_copy_init(struct window_mode_entry
*wme
,
430 __unused
struct cmd_find_state
*fs
, struct args
*args
)
432 struct window_pane
*wp
= wme
->swp
;
433 struct window_copy_mode_data
*data
;
434 struct screen
*base
= &wp
->base
;
435 struct screen_write_ctx ctx
;
438 data
= window_copy_common_init(wme
);
439 data
->backing
= window_copy_clone_screen(base
, &data
->screen
, &cx
, &cy
,
440 wme
->swp
!= wme
->wp
);
443 if (cy
< screen_hsize(data
->backing
)) {
445 data
->oy
= screen_hsize(data
->backing
) - cy
;
447 data
->cy
= cy
- screen_hsize(data
->backing
);
451 data
->scroll_exit
= args_has(args
, 'e');
452 data
->hide_position
= args_has(args
, 'H');
454 if (base
->hyperlinks
!= NULL
)
455 data
->screen
.hyperlinks
= hyperlinks_copy(base
->hyperlinks
);
456 data
->screen
.cx
= data
->cx
;
457 data
->screen
.cy
= data
->cy
;
459 data
->my
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
462 screen_write_start(&ctx
, &data
->screen
);
463 for (i
= 0; i
< screen_size_y(&data
->screen
); i
++)
464 window_copy_write_line(wme
, &ctx
, i
);
465 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
466 screen_write_stop(&ctx
);
468 return (&data
->screen
);
471 static struct screen
*
472 window_copy_view_init(struct window_mode_entry
*wme
,
473 __unused
struct cmd_find_state
*fs
, __unused
struct args
*args
)
475 struct window_pane
*wp
= wme
->wp
;
476 struct window_copy_mode_data
*data
;
477 struct screen
*base
= &wp
->base
;
478 u_int sx
= screen_size_x(base
);
480 data
= window_copy_common_init(wme
);
483 data
->backing
= xmalloc(sizeof *data
->backing
);
484 screen_init(data
->backing
, sx
, screen_size_y(base
), UINT_MAX
);
485 data
->writing
= xmalloc(sizeof *data
->writing
);
486 screen_init(data
->writing
, sx
, screen_size_y(base
), 0);
487 data
->ictx
= input_init(NULL
, NULL
, NULL
);
489 data
->my
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
492 return (&data
->screen
);
496 window_copy_free(struct window_mode_entry
*wme
)
498 struct window_copy_mode_data
*data
= wme
->data
;
500 evtimer_del(&data
->dragtimer
);
502 free(data
->searchmark
);
503 free(data
->searchstr
);
504 free(data
->jumpchar
);
506 if (data
->writing
!= NULL
) {
507 screen_free(data
->writing
);
510 if (data
->ictx
!= NULL
)
511 input_free(data
->ictx
);
512 screen_free(data
->backing
);
515 screen_free(&data
->screen
);
520 window_copy_add(struct window_pane
*wp
, int parse
, const char *fmt
, ...)
525 window_copy_vadd(wp
, parse
, fmt
, ap
);
530 window_copy_init_ctx_cb(__unused
struct screen_write_ctx
*ctx
,
531 struct tty_ctx
*ttyctx
)
533 memcpy(&ttyctx
->defaults
, &grid_default_cell
, sizeof ttyctx
->defaults
);
534 ttyctx
->palette
= NULL
;
535 ttyctx
->redraw_cb
= NULL
;
536 ttyctx
->set_client_cb
= NULL
;
541 window_copy_vadd(struct window_pane
*wp
, int parse
, const char *fmt
, va_list ap
)
543 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
544 struct window_copy_mode_data
*data
= wme
->data
;
545 struct screen
*backing
= data
->backing
;
546 struct screen
*writing
= data
->writing
;
547 struct screen_write_ctx writing_ctx
, backing_ctx
, ctx
;
549 u_int old_hsize
, old_cy
;
550 u_int sx
= screen_size_x(backing
);
554 vasprintf(&text
, fmt
, ap
);
555 screen_write_start(&writing_ctx
, writing
);
556 screen_write_reset(&writing_ctx
);
557 input_parse_screen(data
->ictx
, writing
, window_copy_init_ctx_cb
,
558 data
, text
, strlen(text
));
562 old_hsize
= screen_hsize(data
->backing
);
563 screen_write_start(&backing_ctx
, backing
);
564 if (data
->backing_written
) {
566 * On the second or later line, do a CRLF before writing
567 * (so it's on a new line).
569 screen_write_carriagereturn(&backing_ctx
);
570 screen_write_linefeed(&backing_ctx
, 0, 8);
572 data
->backing_written
= 1;
573 old_cy
= backing
->cy
;
575 screen_write_fast_copy(&backing_ctx
, writing
, 0, 0, sx
, 1);
577 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
578 screen_write_vnputs(&backing_ctx
, 0, &gc
, fmt
, ap
);
580 screen_write_stop(&backing_ctx
);
582 data
->oy
+= screen_hsize(data
->backing
) - old_hsize
;
584 screen_write_start_pane(&ctx
, wp
, &data
->screen
);
587 * If the history has changed, draw the top line.
588 * (If there's any history at all, it has changed.)
590 if (screen_hsize(data
->backing
))
591 window_copy_redraw_lines(wme
, 0, 1);
593 /* Write the new lines. */
594 window_copy_redraw_lines(wme
, old_cy
, backing
->cy
- old_cy
+ 1);
596 screen_write_stop(&ctx
);
600 window_copy_pageup(struct window_pane
*wp
, int half_page
)
602 window_copy_pageup1(TAILQ_FIRST(&wp
->modes
), half_page
);
606 window_copy_pageup1(struct window_mode_entry
*wme
, int half_page
)
608 struct window_copy_mode_data
*data
= wme
->data
;
609 struct screen
*s
= &data
->screen
;
610 u_int n
, ox
, oy
, px
, py
;
612 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
613 ox
= window_copy_find_length(wme
, oy
);
615 if (data
->cx
!= ox
) {
616 data
->lastcx
= data
->cx
;
619 data
->cx
= data
->lastcx
;
622 if (screen_size_y(s
) > 2) {
624 n
= screen_size_y(s
) / 2;
626 n
= screen_size_y(s
) - 2;
629 if (data
->oy
+ n
> screen_hsize(data
->backing
)) {
630 data
->oy
= screen_hsize(data
->backing
);
638 if (data
->screen
.sel
== NULL
|| !data
->rectflag
) {
639 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
640 px
= window_copy_find_length(wme
, py
);
641 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
643 window_copy_cursor_end_of_line(wme
);
646 if (data
->searchmark
!= NULL
&& !data
->timeout
)
647 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
648 window_copy_update_selection(wme
, 1, 0);
649 window_copy_redraw_screen(wme
);
653 window_copy_pagedown(struct window_pane
*wp
, int half_page
, int scroll_exit
)
655 if (window_copy_pagedown1(TAILQ_FIRST(&wp
->modes
), half_page
,
657 window_pane_reset_mode(wp
);
663 window_copy_pagedown1(struct window_mode_entry
*wme
, int half_page
,
666 struct window_copy_mode_data
*data
= wme
->data
;
667 struct screen
*s
= &data
->screen
;
668 u_int n
, ox
, oy
, px
, py
;
670 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
671 ox
= window_copy_find_length(wme
, oy
);
673 if (data
->cx
!= ox
) {
674 data
->lastcx
= data
->cx
;
677 data
->cx
= data
->lastcx
;
680 if (screen_size_y(s
) > 2) {
682 n
= screen_size_y(s
) / 2;
684 n
= screen_size_y(s
) - 2;
689 if (data
->cy
+ (n
- data
->oy
) >= screen_size_y(data
->backing
))
690 data
->cy
= screen_size_y(data
->backing
) - 1;
692 data
->cy
+= n
- data
->oy
;
696 if (data
->screen
.sel
== NULL
|| !data
->rectflag
) {
697 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
698 px
= window_copy_find_length(wme
, py
);
699 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
701 window_copy_cursor_end_of_line(wme
);
704 if (scroll_exit
&& data
->oy
== 0)
706 if (data
->searchmark
!= NULL
&& !data
->timeout
)
707 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
708 window_copy_update_selection(wme
, 1, 0);
709 window_copy_redraw_screen(wme
);
714 window_copy_previous_paragraph(struct window_mode_entry
*wme
)
716 struct window_copy_mode_data
*data
= wme
->data
;
719 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
721 while (oy
> 0 && window_copy_find_length(wme
, oy
) == 0)
724 while (oy
> 0 && window_copy_find_length(wme
, oy
) > 0)
727 window_copy_scroll_to(wme
, 0, oy
, 0);
731 window_copy_next_paragraph(struct window_mode_entry
*wme
)
733 struct window_copy_mode_data
*data
= wme
->data
;
734 struct screen
*s
= &data
->screen
;
737 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
738 maxy
= screen_hsize(data
->backing
) + screen_size_y(s
) - 1;
740 while (oy
< maxy
&& window_copy_find_length(wme
, oy
) == 0)
743 while (oy
< maxy
&& window_copy_find_length(wme
, oy
) > 0)
746 ox
= window_copy_find_length(wme
, oy
);
747 window_copy_scroll_to(wme
, ox
, oy
, 0);
751 window_copy_get_word(struct window_pane
*wp
, u_int x
, u_int y
)
753 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
754 struct window_copy_mode_data
*data
= wme
->data
;
755 struct grid
*gd
= data
->screen
.grid
;
757 return (format_grid_word(gd
, x
, gd
->hsize
+ y
));
761 window_copy_get_line(struct window_pane
*wp
, u_int y
)
763 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
764 struct window_copy_mode_data
*data
= wme
->data
;
765 struct grid
*gd
= data
->screen
.grid
;
767 return (format_grid_line(gd
, gd
->hsize
+ y
));
771 window_copy_cursor_hyperlink_cb(struct format_tree
*ft
)
773 struct window_pane
*wp
= format_get_pane(ft
);
774 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
775 struct window_copy_mode_data
*data
= wme
->data
;
776 struct grid
*gd
= data
->screen
.grid
;
778 return (format_grid_hyperlink(gd
, data
->cx
, gd
->hsize
+ data
->cy
,
783 window_copy_cursor_word_cb(struct format_tree
*ft
)
785 struct window_pane
*wp
= format_get_pane(ft
);
786 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
787 struct window_copy_mode_data
*data
= wme
->data
;
789 return (window_copy_get_word(wp
, data
->cx
, data
->cy
));
793 window_copy_cursor_line_cb(struct format_tree
*ft
)
795 struct window_pane
*wp
= format_get_pane(ft
);
796 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
797 struct window_copy_mode_data
*data
= wme
->data
;
799 return (window_copy_get_line(wp
, data
->cy
));
803 window_copy_search_match_cb(struct format_tree
*ft
)
805 struct window_pane
*wp
= format_get_pane(ft
);
806 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
807 struct window_copy_mode_data
*data
= wme
->data
;
809 return (window_copy_match_at_cursor(data
));
813 window_copy_formats(struct window_mode_entry
*wme
, struct format_tree
*ft
)
815 struct window_copy_mode_data
*data
= wme
->data
;
817 format_add(ft
, "scroll_position", "%d", data
->oy
);
818 format_add(ft
, "rectangle_toggle", "%d", data
->rectflag
);
820 format_add(ft
, "copy_cursor_x", "%d", data
->cx
);
821 format_add(ft
, "copy_cursor_y", "%d", data
->cy
);
823 if (data
->screen
.sel
!= NULL
) {
824 format_add(ft
, "selection_start_x", "%d", data
->selx
);
825 format_add(ft
, "selection_start_y", "%d", data
->sely
);
826 format_add(ft
, "selection_end_x", "%d", data
->endselx
);
827 format_add(ft
, "selection_end_y", "%d", data
->endsely
);
829 if (data
->cursordrag
!= CURSORDRAG_NONE
)
830 format_add(ft
, "selection_active", "1");
832 format_add(ft
, "selection_active", "0");
833 if (data
->endselx
!= data
->selx
|| data
->endsely
!= data
->sely
)
834 format_add(ft
, "selection_present", "1");
836 format_add(ft
, "selection_present", "0");
838 format_add(ft
, "selection_active", "0");
839 format_add(ft
, "selection_present", "0");
842 format_add(ft
, "search_present", "%d", data
->searchmark
!= NULL
);
843 if (data
->searchcount
!= -1) {
844 format_add(ft
, "search_count", "%d", data
->searchcount
);
845 format_add(ft
, "search_count_partial", "%d", data
->searchmore
);
847 format_add_cb(ft
, "search_match", window_copy_search_match_cb
);
849 format_add_cb(ft
, "copy_cursor_word", window_copy_cursor_word_cb
);
850 format_add_cb(ft
, "copy_cursor_line", window_copy_cursor_line_cb
);
851 format_add_cb(ft
, "copy_cursor_hyperlink",
852 window_copy_cursor_hyperlink_cb
);
856 window_copy_size_changed(struct window_mode_entry
*wme
)
858 struct window_copy_mode_data
*data
= wme
->data
;
859 struct screen
*s
= &data
->screen
;
860 struct screen_write_ctx ctx
;
861 int search
= (data
->searchmark
!= NULL
);
863 window_copy_clear_selection(wme
);
864 window_copy_clear_marks(wme
);
866 screen_write_start(&ctx
, s
);
867 window_copy_write_lines(wme
, &ctx
, 0, screen_size_y(s
));
868 screen_write_stop(&ctx
);
870 if (search
&& !data
->timeout
)
871 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 0);
872 data
->searchx
= data
->cx
;
873 data
->searchy
= data
->cy
;
874 data
->searcho
= data
->oy
;
878 window_copy_resize(struct window_mode_entry
*wme
, u_int sx
, u_int sy
)
880 struct window_copy_mode_data
*data
= wme
->data
;
881 struct screen
*s
= &data
->screen
;
882 struct grid
*gd
= data
->backing
->grid
;
883 u_int cx
, cy
, wx
, wy
;
886 screen_resize(s
, sx
, sy
, 0);
888 cy
= gd
->hsize
+ data
->cy
- data
->oy
;
889 reflow
= (gd
->sx
!= sx
);
891 grid_wrap_position(gd
, cx
, cy
, &wx
, &wy
);
892 screen_resize_cursor(data
->backing
, sx
, sy
, 1, 0, 0);
894 grid_unwrap_position(gd
, &cx
, &cy
, wx
, wy
);
897 if (cy
< gd
->hsize
) {
899 data
->oy
= gd
->hsize
- cy
;
901 data
->cy
= cy
- gd
->hsize
;
905 window_copy_size_changed(wme
);
906 window_copy_redraw_screen(wme
);
910 window_copy_key_table(struct window_mode_entry
*wme
)
912 struct window_pane
*wp
= wme
->wp
;
914 if (options_get_number(wp
->window
->options
, "mode-keys") == MODEKEY_VI
)
915 return ("copy-mode-vi");
916 return ("copy-mode");
920 window_copy_expand_search_string(struct window_copy_cmd_state
*cs
)
922 struct window_mode_entry
*wme
= cs
->wme
;
923 struct window_copy_mode_data
*data
= wme
->data
;
924 const char *ss
= args_string(cs
->args
, 1);
927 if (ss
== NULL
|| *ss
== '\0')
930 if (args_has(cs
->args
, 'F')) {
931 expanded
= format_single(NULL
, ss
, NULL
, NULL
, NULL
, wme
->wp
);
932 if (*expanded
== '\0') {
936 free(data
->searchstr
);
937 data
->searchstr
= expanded
;
939 free(data
->searchstr
);
940 data
->searchstr
= xstrdup(ss
);
945 static enum window_copy_cmd_action
946 window_copy_cmd_append_selection(struct window_copy_cmd_state
*cs
)
948 struct window_mode_entry
*wme
= cs
->wme
;
949 struct session
*s
= cs
->s
;
952 window_copy_append_selection(wme
);
953 window_copy_clear_selection(wme
);
954 return (WINDOW_COPY_CMD_REDRAW
);
957 static enum window_copy_cmd_action
958 window_copy_cmd_append_selection_and_cancel(struct window_copy_cmd_state
*cs
)
960 struct window_mode_entry
*wme
= cs
->wme
;
961 struct session
*s
= cs
->s
;
964 window_copy_append_selection(wme
);
965 window_copy_clear_selection(wme
);
966 return (WINDOW_COPY_CMD_CANCEL
);
969 static enum window_copy_cmd_action
970 window_copy_cmd_back_to_indentation(struct window_copy_cmd_state
*cs
)
972 struct window_mode_entry
*wme
= cs
->wme
;
974 window_copy_cursor_back_to_indentation(wme
);
975 return (WINDOW_COPY_CMD_NOTHING
);
978 static enum window_copy_cmd_action
979 window_copy_cmd_begin_selection(struct window_copy_cmd_state
*cs
)
981 struct window_mode_entry
*wme
= cs
->wme
;
982 struct client
*c
= cs
->c
;
983 struct mouse_event
*m
= cs
->m
;
984 struct window_copy_mode_data
*data
= wme
->data
;
987 window_copy_start_drag(c
, m
);
988 return (WINDOW_COPY_CMD_NOTHING
);
991 data
->lineflag
= LINE_SEL_NONE
;
992 data
->selflag
= SEL_CHAR
;
993 window_copy_start_selection(wme
);
994 return (WINDOW_COPY_CMD_REDRAW
);
997 static enum window_copy_cmd_action
998 window_copy_cmd_stop_selection(struct window_copy_cmd_state
*cs
)
1000 struct window_mode_entry
*wme
= cs
->wme
;
1001 struct window_copy_mode_data
*data
= wme
->data
;
1003 data
->cursordrag
= CURSORDRAG_NONE
;
1004 data
->lineflag
= LINE_SEL_NONE
;
1005 data
->selflag
= SEL_CHAR
;
1006 return (WINDOW_COPY_CMD_NOTHING
);
1009 static enum window_copy_cmd_action
1010 window_copy_cmd_bottom_line(struct window_copy_cmd_state
*cs
)
1012 struct window_mode_entry
*wme
= cs
->wme
;
1013 struct window_copy_mode_data
*data
= wme
->data
;
1016 data
->cy
= screen_size_y(&data
->screen
) - 1;
1018 window_copy_update_selection(wme
, 1, 0);
1019 return (WINDOW_COPY_CMD_REDRAW
);
1022 static enum window_copy_cmd_action
1023 window_copy_cmd_cancel(__unused
struct window_copy_cmd_state
*cs
)
1025 return (WINDOW_COPY_CMD_CANCEL
);
1028 static enum window_copy_cmd_action
1029 window_copy_cmd_clear_selection(struct window_copy_cmd_state
*cs
)
1031 struct window_mode_entry
*wme
= cs
->wme
;
1033 window_copy_clear_selection(wme
);
1034 return (WINDOW_COPY_CMD_REDRAW
);
1037 static enum window_copy_cmd_action
1038 window_copy_do_copy_end_of_line(struct window_copy_cmd_state
*cs
, int pipe
,
1041 struct window_mode_entry
*wme
= cs
->wme
;
1042 struct client
*c
= cs
->c
;
1043 struct session
*s
= cs
->s
;
1044 struct winlink
*wl
= cs
->wl
;
1045 struct window_pane
*wp
= wme
->wp
;
1046 u_int count
= args_count(cs
->args
);
1047 u_int np
= wme
->prefix
, ocx
, ocy
, ooy
;
1048 struct window_copy_mode_data
*data
= wme
->data
;
1049 char *prefix
= NULL
, *command
= NULL
;
1050 const char *arg1
= args_string(cs
->args
, 1);
1051 const char *arg2
= args_string(cs
->args
, 2);
1055 prefix
= format_single(NULL
, arg2
, c
, s
, wl
, wp
);
1056 if (s
!= NULL
&& count
> 1 && *arg1
!= '\0')
1057 command
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1060 prefix
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1067 window_copy_start_selection(wme
);
1068 for (; np
> 1; np
--)
1069 window_copy_cursor_down(wme
, 0);
1070 window_copy_cursor_end_of_line(wme
);
1074 window_copy_copy_pipe(wme
, s
, prefix
, command
);
1076 window_copy_copy_selection(wme
, prefix
);
1081 return (WINDOW_COPY_CMD_CANCEL
);
1084 window_copy_clear_selection(wme
);
1092 return (WINDOW_COPY_CMD_REDRAW
);
1095 static enum window_copy_cmd_action
1096 window_copy_cmd_copy_end_of_line(struct window_copy_cmd_state
*cs
)
1098 return (window_copy_do_copy_end_of_line(cs
, 0, 0));
1101 static enum window_copy_cmd_action
1102 window_copy_cmd_copy_end_of_line_and_cancel(struct window_copy_cmd_state
*cs
)
1104 return (window_copy_do_copy_end_of_line(cs
, 0, 1));
1107 static enum window_copy_cmd_action
1108 window_copy_cmd_copy_pipe_end_of_line(struct window_copy_cmd_state
*cs
)
1110 return (window_copy_do_copy_end_of_line(cs
, 1, 0));
1113 static enum window_copy_cmd_action
1114 window_copy_cmd_copy_pipe_end_of_line_and_cancel(
1115 struct window_copy_cmd_state
*cs
)
1117 return (window_copy_do_copy_end_of_line(cs
, 1, 1));
1120 static enum window_copy_cmd_action
1121 window_copy_do_copy_line(struct window_copy_cmd_state
*cs
, int pipe
, int cancel
)
1123 struct window_mode_entry
*wme
= cs
->wme
;
1124 struct client
*c
= cs
->c
;
1125 struct session
*s
= cs
->s
;
1126 struct winlink
*wl
= cs
->wl
;
1127 struct window_pane
*wp
= wme
->wp
;
1128 struct window_copy_mode_data
*data
= wme
->data
;
1129 u_int count
= args_count(cs
->args
);
1130 u_int np
= wme
->prefix
, ocx
, ocy
, ooy
;
1131 char *prefix
= NULL
, *command
= NULL
;
1132 const char *arg1
= args_string(cs
->args
, 1);
1133 const char *arg2
= args_string(cs
->args
, 2);
1137 prefix
= format_single(NULL
, arg2
, c
, s
, wl
, wp
);
1138 if (s
!= NULL
&& count
> 1 && *arg1
!= '\0')
1139 command
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1142 prefix
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1149 data
->selflag
= SEL_CHAR
;
1150 window_copy_cursor_start_of_line(wme
);
1151 window_copy_start_selection(wme
);
1152 for (; np
> 1; np
--)
1153 window_copy_cursor_down(wme
, 0);
1154 window_copy_cursor_end_of_line(wme
);
1158 window_copy_copy_pipe(wme
, s
, prefix
, command
);
1160 window_copy_copy_selection(wme
, prefix
);
1165 return (WINDOW_COPY_CMD_CANCEL
);
1168 window_copy_clear_selection(wme
);
1176 return (WINDOW_COPY_CMD_REDRAW
);
1179 static enum window_copy_cmd_action
1180 window_copy_cmd_copy_line(struct window_copy_cmd_state
*cs
)
1182 return (window_copy_do_copy_line(cs
, 0, 0));
1185 static enum window_copy_cmd_action
1186 window_copy_cmd_copy_line_and_cancel(struct window_copy_cmd_state
*cs
)
1188 return (window_copy_do_copy_line(cs
, 0, 1));
1191 static enum window_copy_cmd_action
1192 window_copy_cmd_copy_pipe_line(struct window_copy_cmd_state
*cs
)
1194 return (window_copy_do_copy_line(cs
, 1, 0));
1197 static enum window_copy_cmd_action
1198 window_copy_cmd_copy_pipe_line_and_cancel(struct window_copy_cmd_state
*cs
)
1200 return (window_copy_do_copy_line(cs
, 1, 1));
1203 static enum window_copy_cmd_action
1204 window_copy_cmd_copy_selection_no_clear(struct window_copy_cmd_state
*cs
)
1206 struct window_mode_entry
*wme
= cs
->wme
;
1207 struct client
*c
= cs
->c
;
1208 struct session
*s
= cs
->s
;
1209 struct winlink
*wl
= cs
->wl
;
1210 struct window_pane
*wp
= wme
->wp
;
1211 char *prefix
= NULL
;
1212 const char *arg1
= args_string(cs
->args
, 1);
1215 prefix
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1218 window_copy_copy_selection(wme
, prefix
);
1221 return (WINDOW_COPY_CMD_NOTHING
);
1224 static enum window_copy_cmd_action
1225 window_copy_cmd_copy_selection(struct window_copy_cmd_state
*cs
)
1227 struct window_mode_entry
*wme
= cs
->wme
;
1229 window_copy_cmd_copy_selection_no_clear(cs
);
1230 window_copy_clear_selection(wme
);
1231 return (WINDOW_COPY_CMD_REDRAW
);
1234 static enum window_copy_cmd_action
1235 window_copy_cmd_copy_selection_and_cancel(struct window_copy_cmd_state
*cs
)
1237 struct window_mode_entry
*wme
= cs
->wme
;
1239 window_copy_cmd_copy_selection_no_clear(cs
);
1240 window_copy_clear_selection(wme
);
1241 return (WINDOW_COPY_CMD_CANCEL
);
1244 static enum window_copy_cmd_action
1245 window_copy_cmd_cursor_down(struct window_copy_cmd_state
*cs
)
1247 struct window_mode_entry
*wme
= cs
->wme
;
1248 u_int np
= wme
->prefix
;
1250 for (; np
!= 0; np
--)
1251 window_copy_cursor_down(wme
, 0);
1252 return (WINDOW_COPY_CMD_NOTHING
);
1255 static enum window_copy_cmd_action
1256 window_copy_cmd_cursor_down_and_cancel(struct window_copy_cmd_state
*cs
)
1258 struct window_mode_entry
*wme
= cs
->wme
;
1259 struct window_copy_mode_data
*data
= wme
->data
;
1260 u_int np
= wme
->prefix
, cy
;
1263 for (; np
!= 0; np
--)
1264 window_copy_cursor_down(wme
, 0);
1265 if (cy
== data
->cy
&& data
->oy
== 0)
1266 return (WINDOW_COPY_CMD_CANCEL
);
1267 return (WINDOW_COPY_CMD_NOTHING
);
1270 static enum window_copy_cmd_action
1271 window_copy_cmd_cursor_left(struct window_copy_cmd_state
*cs
)
1273 struct window_mode_entry
*wme
= cs
->wme
;
1274 u_int np
= wme
->prefix
;
1276 for (; np
!= 0; np
--)
1277 window_copy_cursor_left(wme
);
1278 return (WINDOW_COPY_CMD_NOTHING
);
1281 static enum window_copy_cmd_action
1282 window_copy_cmd_cursor_right(struct window_copy_cmd_state
*cs
)
1284 struct window_mode_entry
*wme
= cs
->wme
;
1285 struct window_copy_mode_data
*data
= wme
->data
;
1286 u_int np
= wme
->prefix
;
1288 for (; np
!= 0; np
--) {
1289 window_copy_cursor_right(wme
, data
->screen
.sel
!= NULL
&&
1292 return (WINDOW_COPY_CMD_NOTHING
);
1295 /* Scroll line containing the cursor to the given position. */
1296 static enum window_copy_cmd_action
1297 window_copy_cmd_scroll_to(struct window_copy_cmd_state
*cs
, u_int to
)
1299 struct window_mode_entry
*wme
= cs
->wme
;
1300 struct window_copy_mode_data
*data
= wme
->data
;
1302 int scroll_up
; /* >0 up, <0 down */
1304 scroll_up
= data
->cy
- to
;
1305 delta
= abs(scroll_up
);
1306 oy
= screen_hsize(data
->backing
) - data
->oy
;
1309 * oy is the maximum scroll down amount, while data->oy is the maximum
1312 if (scroll_up
> 0 && data
->oy
>= delta
) {
1313 window_copy_scroll_up(wme
, delta
);
1315 } else if (scroll_up
< 0 && oy
>= delta
) {
1316 window_copy_scroll_down(wme
, delta
);
1320 window_copy_update_selection(wme
, 0, 0);
1321 return (WINDOW_COPY_CMD_REDRAW
);
1324 /* Scroll line containing the cursor to the bottom. */
1325 static enum window_copy_cmd_action
1326 window_copy_cmd_scroll_bottom(struct window_copy_cmd_state
*cs
)
1328 struct window_copy_mode_data
*data
= cs
->wme
->data
;
1331 bottom
= screen_size_y(&data
->screen
) - 1;
1332 return (window_copy_cmd_scroll_to(cs
, bottom
));
1335 /* Scroll line containing the cursor to the middle. */
1336 static enum window_copy_cmd_action
1337 window_copy_cmd_scroll_middle(struct window_copy_cmd_state
*cs
)
1339 struct window_copy_mode_data
*data
= cs
->wme
->data
;
1342 mid_value
= (screen_size_y(&data
->screen
) - 1) / 2;
1343 return (window_copy_cmd_scroll_to(cs
, mid_value
));
1346 /* Scroll line containing the cursor to the top. */
1347 static enum window_copy_cmd_action
1348 window_copy_cmd_scroll_top(struct window_copy_cmd_state
*cs
)
1350 return (window_copy_cmd_scroll_to(cs
, 0));
1353 static enum window_copy_cmd_action
1354 window_copy_cmd_cursor_up(struct window_copy_cmd_state
*cs
)
1356 struct window_mode_entry
*wme
= cs
->wme
;
1357 u_int np
= wme
->prefix
;
1359 for (; np
!= 0; np
--)
1360 window_copy_cursor_up(wme
, 0);
1361 return (WINDOW_COPY_CMD_NOTHING
);
1364 static enum window_copy_cmd_action
1365 window_copy_cmd_end_of_line(struct window_copy_cmd_state
*cs
)
1367 struct window_mode_entry
*wme
= cs
->wme
;
1369 window_copy_cursor_end_of_line(wme
);
1370 return (WINDOW_COPY_CMD_NOTHING
);
1373 static enum window_copy_cmd_action
1374 window_copy_cmd_halfpage_down(struct window_copy_cmd_state
*cs
)
1376 struct window_mode_entry
*wme
= cs
->wme
;
1377 struct window_copy_mode_data
*data
= wme
->data
;
1378 u_int np
= wme
->prefix
;
1380 for (; np
!= 0; np
--) {
1381 if (window_copy_pagedown1(wme
, 1, data
->scroll_exit
))
1382 return (WINDOW_COPY_CMD_CANCEL
);
1384 return (WINDOW_COPY_CMD_NOTHING
);
1387 static enum window_copy_cmd_action
1388 window_copy_cmd_halfpage_down_and_cancel(struct window_copy_cmd_state
*cs
)
1391 struct window_mode_entry
*wme
= cs
->wme
;
1392 u_int np
= wme
->prefix
;
1394 for (; np
!= 0; np
--) {
1395 if (window_copy_pagedown1(wme
, 1, 1))
1396 return (WINDOW_COPY_CMD_CANCEL
);
1398 return (WINDOW_COPY_CMD_NOTHING
);
1401 static enum window_copy_cmd_action
1402 window_copy_cmd_halfpage_up(struct window_copy_cmd_state
*cs
)
1404 struct window_mode_entry
*wme
= cs
->wme
;
1405 u_int np
= wme
->prefix
;
1407 for (; np
!= 0; np
--)
1408 window_copy_pageup1(wme
, 1);
1409 return (WINDOW_COPY_CMD_NOTHING
);
1412 static enum window_copy_cmd_action
1413 window_copy_cmd_toggle_position(struct window_copy_cmd_state
*cs
)
1415 struct window_mode_entry
*wme
= cs
->wme
;
1416 struct window_copy_mode_data
*data
= wme
->data
;
1418 data
->hide_position
= !data
->hide_position
;
1419 return (WINDOW_COPY_CMD_REDRAW
);
1422 static enum window_copy_cmd_action
1423 window_copy_cmd_history_bottom(struct window_copy_cmd_state
*cs
)
1425 struct window_mode_entry
*wme
= cs
->wme
;
1426 struct window_copy_mode_data
*data
= wme
->data
;
1427 struct screen
*s
= data
->backing
;
1430 oy
= screen_hsize(s
) + data
->cy
- data
->oy
;
1431 if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
&& oy
== data
->endsely
)
1432 window_copy_other_end(wme
);
1434 data
->cy
= screen_size_y(&data
->screen
) - 1;
1435 data
->cx
= window_copy_find_length(wme
, screen_hsize(s
) + data
->cy
);
1438 if (data
->searchmark
!= NULL
&& !data
->timeout
)
1439 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
1440 window_copy_update_selection(wme
, 1, 0);
1441 return (WINDOW_COPY_CMD_REDRAW
);
1444 static enum window_copy_cmd_action
1445 window_copy_cmd_history_top(struct window_copy_cmd_state
*cs
)
1447 struct window_mode_entry
*wme
= cs
->wme
;
1448 struct window_copy_mode_data
*data
= wme
->data
;
1451 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1452 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
&& oy
== data
->sely
)
1453 window_copy_other_end(wme
);
1457 data
->oy
= screen_hsize(data
->backing
);
1459 if (data
->searchmark
!= NULL
&& !data
->timeout
)
1460 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
1461 window_copy_update_selection(wme
, 1, 0);
1462 return (WINDOW_COPY_CMD_REDRAW
);
1465 static enum window_copy_cmd_action
1466 window_copy_cmd_jump_again(struct window_copy_cmd_state
*cs
)
1468 struct window_mode_entry
*wme
= cs
->wme
;
1469 struct window_copy_mode_data
*data
= wme
->data
;
1470 u_int np
= wme
->prefix
;
1472 switch (data
->jumptype
) {
1473 case WINDOW_COPY_JUMPFORWARD
:
1474 for (; np
!= 0; np
--)
1475 window_copy_cursor_jump(wme
);
1477 case WINDOW_COPY_JUMPBACKWARD
:
1478 for (; np
!= 0; np
--)
1479 window_copy_cursor_jump_back(wme
);
1481 case WINDOW_COPY_JUMPTOFORWARD
:
1482 for (; np
!= 0; np
--)
1483 window_copy_cursor_jump_to(wme
);
1485 case WINDOW_COPY_JUMPTOBACKWARD
:
1486 for (; np
!= 0; np
--)
1487 window_copy_cursor_jump_to_back(wme
);
1490 return (WINDOW_COPY_CMD_NOTHING
);
1493 static enum window_copy_cmd_action
1494 window_copy_cmd_jump_reverse(struct window_copy_cmd_state
*cs
)
1496 struct window_mode_entry
*wme
= cs
->wme
;
1497 struct window_copy_mode_data
*data
= wme
->data
;
1498 u_int np
= wme
->prefix
;
1500 switch (data
->jumptype
) {
1501 case WINDOW_COPY_JUMPFORWARD
:
1502 for (; np
!= 0; np
--)
1503 window_copy_cursor_jump_back(wme
);
1505 case WINDOW_COPY_JUMPBACKWARD
:
1506 for (; np
!= 0; np
--)
1507 window_copy_cursor_jump(wme
);
1509 case WINDOW_COPY_JUMPTOFORWARD
:
1510 for (; np
!= 0; np
--)
1511 window_copy_cursor_jump_to_back(wme
);
1513 case WINDOW_COPY_JUMPTOBACKWARD
:
1514 for (; np
!= 0; np
--)
1515 window_copy_cursor_jump_to(wme
);
1518 return (WINDOW_COPY_CMD_NOTHING
);
1521 static enum window_copy_cmd_action
1522 window_copy_cmd_middle_line(struct window_copy_cmd_state
*cs
)
1524 struct window_mode_entry
*wme
= cs
->wme
;
1525 struct window_copy_mode_data
*data
= wme
->data
;
1528 data
->cy
= (screen_size_y(&data
->screen
) - 1) / 2;
1530 window_copy_update_selection(wme
, 1, 0);
1531 return (WINDOW_COPY_CMD_REDRAW
);
1534 static enum window_copy_cmd_action
1535 window_copy_cmd_previous_matching_bracket(struct window_copy_cmd_state
*cs
)
1537 struct window_mode_entry
*wme
= cs
->wme
;
1538 u_int np
= wme
->prefix
;
1539 struct window_copy_mode_data
*data
= wme
->data
;
1540 struct screen
*s
= data
->backing
;
1541 char open
[] = "{[(", close
[] = "}])";
1542 char tried
, found
, start
, *cp
;
1543 u_int px
, py
, xx
, n
;
1544 struct grid_cell gc
;
1547 for (; np
!= 0; np
--) {
1548 /* Get cursor position and line length. */
1550 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1551 xx
= window_copy_find_length(wme
, py
);
1556 * Get the current character. If not on a bracket, try the
1557 * previous. If still not, then behave like previous-word.
1561 grid_get_cell(s
->grid
, px
, py
, &gc
);
1562 if (gc
.data
.size
!= 1 || (gc
.flags
& GRID_FLAG_PADDING
))
1565 found
= *gc
.data
.data
;
1566 cp
= strchr(close
, found
);
1569 if (data
->modekeys
== MODEKEY_EMACS
) {
1570 if (!tried
&& px
> 0) {
1575 window_copy_cursor_previous_word(wme
, close
, 1);
1579 start
= open
[cp
- close
];
1581 /* Walk backward until the matching bracket is reached. */
1592 xx
= window_copy_find_length(wme
, py
);
1593 } while (xx
== 0 && py
> 0);
1594 if (xx
== 0 && py
== 0) {
1602 grid_get_cell(s
->grid
, px
, py
, &gc
);
1603 if (gc
.data
.size
== 1 &&
1604 (~gc
.flags
& GRID_FLAG_PADDING
)) {
1605 if (*gc
.data
.data
== found
)
1607 else if (*gc
.data
.data
== start
)
1612 /* Move the cursor to the found location if any. */
1614 window_copy_scroll_to(wme
, px
, py
, 0);
1617 return (WINDOW_COPY_CMD_NOTHING
);
1620 static enum window_copy_cmd_action
1621 window_copy_cmd_next_matching_bracket(struct window_copy_cmd_state
*cs
)
1623 struct window_mode_entry
*wme
= cs
->wme
;
1624 u_int np
= wme
->prefix
;
1625 struct window_copy_mode_data
*data
= wme
->data
;
1626 struct screen
*s
= data
->backing
;
1627 char open
[] = "{[(", close
[] = "}])";
1628 char tried
, found
, end
, *cp
;
1629 u_int px
, py
, xx
, yy
, sx
, sy
, n
;
1630 struct grid_cell gc
;
1632 struct grid_line
*gl
;
1634 for (; np
!= 0; np
--) {
1635 /* Get cursor position and line length. */
1637 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1638 xx
= window_copy_find_length(wme
, py
);
1639 yy
= screen_hsize(s
) + screen_size_y(s
) - 1;
1644 * Get the current character. If not on a bracket, try the
1645 * next. If still not, then behave like next-word.
1649 grid_get_cell(s
->grid
, px
, py
, &gc
);
1650 if (gc
.data
.size
!= 1 || (gc
.flags
& GRID_FLAG_PADDING
))
1653 found
= *gc
.data
.data
;
1656 * In vi mode, attempt to move to previous bracket if a
1657 * closing bracket is found first. If this fails,
1658 * return to the original cursor position.
1660 cp
= strchr(close
, found
);
1661 if (cp
!= NULL
&& data
->modekeys
== MODEKEY_VI
) {
1663 sy
= screen_hsize(s
) + data
->cy
- data
->oy
;
1665 window_copy_scroll_to(wme
, px
, py
, 0);
1666 window_copy_cmd_previous_matching_bracket(cs
);
1669 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1670 grid_get_cell(s
->grid
, px
, py
, &gc
);
1671 if (gc
.data
.size
== 1 &&
1672 (~gc
.flags
& GRID_FLAG_PADDING
) &&
1673 strchr(close
, *gc
.data
.data
) != NULL
)
1674 window_copy_scroll_to(wme
, sx
, sy
, 0);
1678 cp
= strchr(open
, found
);
1681 if (data
->modekeys
== MODEKEY_EMACS
) {
1682 if (!tried
&& px
<= xx
) {
1687 window_copy_cursor_next_word_end(wme
, open
, 0);
1690 /* For vi, continue searching for bracket until EOL. */
1694 gl
= grid_get_line(s
->grid
, py
);
1695 if (~gl
->flags
& GRID_LINE_WRAPPED
)
1697 if (gl
->cellsize
> s
->grid
->sx
)
1701 xx
= window_copy_find_length(wme
, py
);
1706 end
= close
[cp
- open
];
1708 /* Walk forward until the matching bracket is reached. */
1719 xx
= window_copy_find_length(wme
, py
);
1723 grid_get_cell(s
->grid
, px
, py
, &gc
);
1724 if (gc
.data
.size
== 1 &&
1725 (~gc
.flags
& GRID_FLAG_PADDING
)) {
1726 if (*gc
.data
.data
== found
)
1728 else if (*gc
.data
.data
== end
)
1733 /* Move the cursor to the found location if any. */
1735 window_copy_scroll_to(wme
, px
, py
, 0);
1738 return (WINDOW_COPY_CMD_NOTHING
);
1741 static enum window_copy_cmd_action
1742 window_copy_cmd_next_paragraph(struct window_copy_cmd_state
*cs
)
1744 struct window_mode_entry
*wme
= cs
->wme
;
1745 u_int np
= wme
->prefix
;
1747 for (; np
!= 0; np
--)
1748 window_copy_next_paragraph(wme
);
1749 return (WINDOW_COPY_CMD_NOTHING
);
1752 static enum window_copy_cmd_action
1753 window_copy_cmd_next_space(struct window_copy_cmd_state
*cs
)
1755 struct window_mode_entry
*wme
= cs
->wme
;
1756 u_int np
= wme
->prefix
;
1758 for (; np
!= 0; np
--)
1759 window_copy_cursor_next_word(wme
, "");
1760 return (WINDOW_COPY_CMD_NOTHING
);
1763 static enum window_copy_cmd_action
1764 window_copy_cmd_next_space_end(struct window_copy_cmd_state
*cs
)
1766 struct window_mode_entry
*wme
= cs
->wme
;
1767 u_int np
= wme
->prefix
;
1769 for (; np
!= 0; np
--)
1770 window_copy_cursor_next_word_end(wme
, "", 0);
1771 return (WINDOW_COPY_CMD_NOTHING
);
1774 static enum window_copy_cmd_action
1775 window_copy_cmd_next_word(struct window_copy_cmd_state
*cs
)
1777 struct window_mode_entry
*wme
= cs
->wme
;
1778 u_int np
= wme
->prefix
;
1779 const char *separators
;
1781 separators
= options_get_string(cs
->s
->options
, "word-separators");
1783 for (; np
!= 0; np
--)
1784 window_copy_cursor_next_word(wme
, separators
);
1785 return (WINDOW_COPY_CMD_NOTHING
);
1788 static enum window_copy_cmd_action
1789 window_copy_cmd_next_word_end(struct window_copy_cmd_state
*cs
)
1791 struct window_mode_entry
*wme
= cs
->wme
;
1792 u_int np
= wme
->prefix
;
1793 const char *separators
;
1795 separators
= options_get_string(cs
->s
->options
, "word-separators");
1797 for (; np
!= 0; np
--)
1798 window_copy_cursor_next_word_end(wme
, separators
, 0);
1799 return (WINDOW_COPY_CMD_NOTHING
);
1802 static enum window_copy_cmd_action
1803 window_copy_cmd_other_end(struct window_copy_cmd_state
*cs
)
1805 struct window_mode_entry
*wme
= cs
->wme
;
1806 u_int np
= wme
->prefix
;
1807 struct window_copy_mode_data
*data
= wme
->data
;
1809 data
->selflag
= SEL_CHAR
;
1811 window_copy_other_end(wme
);
1812 return (WINDOW_COPY_CMD_NOTHING
);
1815 static enum window_copy_cmd_action
1816 window_copy_cmd_page_down(struct window_copy_cmd_state
*cs
)
1818 struct window_mode_entry
*wme
= cs
->wme
;
1819 struct window_copy_mode_data
*data
= wme
->data
;
1820 u_int np
= wme
->prefix
;
1822 for (; np
!= 0; np
--) {
1823 if (window_copy_pagedown1(wme
, 0, data
->scroll_exit
))
1824 return (WINDOW_COPY_CMD_CANCEL
);
1826 return (WINDOW_COPY_CMD_NOTHING
);
1829 static enum window_copy_cmd_action
1830 window_copy_cmd_page_down_and_cancel(struct window_copy_cmd_state
*cs
)
1832 struct window_mode_entry
*wme
= cs
->wme
;
1833 u_int np
= wme
->prefix
;
1835 for (; np
!= 0; np
--) {
1836 if (window_copy_pagedown1(wme
, 0, 1))
1837 return (WINDOW_COPY_CMD_CANCEL
);
1839 return (WINDOW_COPY_CMD_NOTHING
);
1842 static enum window_copy_cmd_action
1843 window_copy_cmd_page_up(struct window_copy_cmd_state
*cs
)
1845 struct window_mode_entry
*wme
= cs
->wme
;
1846 u_int np
= wme
->prefix
;
1848 for (; np
!= 0; np
--)
1849 window_copy_pageup1(wme
, 0);
1850 return (WINDOW_COPY_CMD_NOTHING
);
1853 static enum window_copy_cmd_action
1854 window_copy_cmd_previous_paragraph(struct window_copy_cmd_state
*cs
)
1856 struct window_mode_entry
*wme
= cs
->wme
;
1857 u_int np
= wme
->prefix
;
1859 for (; np
!= 0; np
--)
1860 window_copy_previous_paragraph(wme
);
1861 return (WINDOW_COPY_CMD_NOTHING
);
1864 static enum window_copy_cmd_action
1865 window_copy_cmd_previous_space(struct window_copy_cmd_state
*cs
)
1867 struct window_mode_entry
*wme
= cs
->wme
;
1868 u_int np
= wme
->prefix
;
1870 for (; np
!= 0; np
--)
1871 window_copy_cursor_previous_word(wme
, "", 1);
1872 return (WINDOW_COPY_CMD_NOTHING
);
1875 static enum window_copy_cmd_action
1876 window_copy_cmd_previous_word(struct window_copy_cmd_state
*cs
)
1878 struct window_mode_entry
*wme
= cs
->wme
;
1879 u_int np
= wme
->prefix
;
1880 const char *separators
;
1882 separators
= options_get_string(cs
->s
->options
, "word-separators");
1884 for (; np
!= 0; np
--)
1885 window_copy_cursor_previous_word(wme
, separators
, 1);
1886 return (WINDOW_COPY_CMD_NOTHING
);
1889 static enum window_copy_cmd_action
1890 window_copy_cmd_rectangle_on(struct window_copy_cmd_state
*cs
)
1892 struct window_mode_entry
*wme
= cs
->wme
;
1893 struct window_copy_mode_data
*data
= wme
->data
;
1895 data
->lineflag
= LINE_SEL_NONE
;
1896 window_copy_rectangle_set(wme
, 1);
1898 return (WINDOW_COPY_CMD_NOTHING
);
1901 static enum window_copy_cmd_action
1902 window_copy_cmd_rectangle_off(struct window_copy_cmd_state
*cs
)
1904 struct window_mode_entry
*wme
= cs
->wme
;
1905 struct window_copy_mode_data
*data
= wme
->data
;
1907 data
->lineflag
= LINE_SEL_NONE
;
1908 window_copy_rectangle_set(wme
, 0);
1910 return (WINDOW_COPY_CMD_NOTHING
);
1913 static enum window_copy_cmd_action
1914 window_copy_cmd_rectangle_toggle(struct window_copy_cmd_state
*cs
)
1916 struct window_mode_entry
*wme
= cs
->wme
;
1917 struct window_copy_mode_data
*data
= wme
->data
;
1919 data
->lineflag
= LINE_SEL_NONE
;
1920 window_copy_rectangle_set(wme
, !data
->rectflag
);
1922 return (WINDOW_COPY_CMD_NOTHING
);
1925 static enum window_copy_cmd_action
1926 window_copy_cmd_scroll_down(struct window_copy_cmd_state
*cs
)
1928 struct window_mode_entry
*wme
= cs
->wme
;
1929 struct window_copy_mode_data
*data
= wme
->data
;
1930 u_int np
= wme
->prefix
;
1932 for (; np
!= 0; np
--)
1933 window_copy_cursor_down(wme
, 1);
1934 if (data
->scroll_exit
&& data
->oy
== 0)
1935 return (WINDOW_COPY_CMD_CANCEL
);
1936 return (WINDOW_COPY_CMD_NOTHING
);
1939 static enum window_copy_cmd_action
1940 window_copy_cmd_scroll_down_and_cancel(struct window_copy_cmd_state
*cs
)
1942 struct window_mode_entry
*wme
= cs
->wme
;
1943 struct window_copy_mode_data
*data
= wme
->data
;
1944 u_int np
= wme
->prefix
;
1946 for (; np
!= 0; np
--)
1947 window_copy_cursor_down(wme
, 1);
1949 return (WINDOW_COPY_CMD_CANCEL
);
1950 return (WINDOW_COPY_CMD_NOTHING
);
1953 static enum window_copy_cmd_action
1954 window_copy_cmd_scroll_up(struct window_copy_cmd_state
*cs
)
1956 struct window_mode_entry
*wme
= cs
->wme
;
1957 u_int np
= wme
->prefix
;
1959 for (; np
!= 0; np
--)
1960 window_copy_cursor_up(wme
, 1);
1961 return (WINDOW_COPY_CMD_NOTHING
);
1964 static enum window_copy_cmd_action
1965 window_copy_cmd_search_again(struct window_copy_cmd_state
*cs
)
1967 struct window_mode_entry
*wme
= cs
->wme
;
1968 struct window_copy_mode_data
*data
= wme
->data
;
1969 u_int np
= wme
->prefix
;
1971 if (data
->searchtype
== WINDOW_COPY_SEARCHUP
) {
1972 for (; np
!= 0; np
--)
1973 window_copy_search_up(wme
, data
->searchregex
);
1974 } else if (data
->searchtype
== WINDOW_COPY_SEARCHDOWN
) {
1975 for (; np
!= 0; np
--)
1976 window_copy_search_down(wme
, data
->searchregex
);
1978 return (WINDOW_COPY_CMD_NOTHING
);
1981 static enum window_copy_cmd_action
1982 window_copy_cmd_search_reverse(struct window_copy_cmd_state
*cs
)
1984 struct window_mode_entry
*wme
= cs
->wme
;
1985 struct window_copy_mode_data
*data
= wme
->data
;
1986 u_int np
= wme
->prefix
;
1988 if (data
->searchtype
== WINDOW_COPY_SEARCHUP
) {
1989 for (; np
!= 0; np
--)
1990 window_copy_search_down(wme
, data
->searchregex
);
1991 } else if (data
->searchtype
== WINDOW_COPY_SEARCHDOWN
) {
1992 for (; np
!= 0; np
--)
1993 window_copy_search_up(wme
, data
->searchregex
);
1995 return (WINDOW_COPY_CMD_NOTHING
);
1998 static enum window_copy_cmd_action
1999 window_copy_cmd_select_line(struct window_copy_cmd_state
*cs
)
2001 struct window_mode_entry
*wme
= cs
->wme
;
2002 struct window_copy_mode_data
*data
= wme
->data
;
2003 u_int np
= wme
->prefix
;
2005 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
2007 data
->selflag
= SEL_LINE
;
2008 data
->dx
= data
->cx
;
2009 data
->dy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2011 window_copy_cursor_start_of_line(wme
);
2012 data
->selrx
= data
->cx
;
2013 data
->selry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2014 data
->endselry
= data
->selry
;
2015 window_copy_start_selection(wme
);
2016 window_copy_cursor_end_of_line(wme
);
2017 data
->endselry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2018 data
->endselrx
= window_copy_find_length(wme
, data
->endselry
);
2019 for (; np
> 1; np
--) {
2020 window_copy_cursor_down(wme
, 0);
2021 window_copy_cursor_end_of_line(wme
);
2024 return (WINDOW_COPY_CMD_REDRAW
);
2027 static enum window_copy_cmd_action
2028 window_copy_cmd_select_word(struct window_copy_cmd_state
*cs
)
2030 struct window_mode_entry
*wme
= cs
->wme
;
2031 struct options
*session_options
= cs
->s
->options
;
2032 struct window_copy_mode_data
*data
= wme
->data
;
2033 u_int px
, py
, nextx
, nexty
;
2035 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
2037 data
->selflag
= SEL_WORD
;
2038 data
->dx
= data
->cx
;
2039 data
->dy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2041 data
->separators
= options_get_string(session_options
,
2043 window_copy_cursor_previous_word(wme
, data
->separators
, 0);
2045 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2048 window_copy_start_selection(wme
);
2050 /* Handle single character words. */
2053 if (grid_get_line(data
->backing
->grid
, nexty
)->flags
&
2054 GRID_LINE_WRAPPED
&& nextx
> screen_size_x(data
->backing
) - 1) {
2058 if (px
>= window_copy_find_length(wme
, py
) ||
2059 !window_copy_in_set(wme
, nextx
, nexty
, WHITESPACE
))
2060 window_copy_cursor_next_word_end(wme
, data
->separators
, 1);
2062 window_copy_update_cursor(wme
, px
, data
->cy
);
2063 if (window_copy_update_selection(wme
, 1, 1))
2064 window_copy_redraw_lines(wme
, data
->cy
, 1);
2066 data
->endselrx
= data
->cx
;
2067 data
->endselry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2068 if (data
->dy
> data
->endselry
) {
2069 data
->dy
= data
->endselry
;
2070 data
->dx
= data
->endselrx
;
2071 } else if (data
->dx
> data
->endselrx
)
2072 data
->dx
= data
->endselrx
;
2074 return (WINDOW_COPY_CMD_REDRAW
);
2077 static enum window_copy_cmd_action
2078 window_copy_cmd_set_mark(struct window_copy_cmd_state
*cs
)
2080 struct window_copy_mode_data
*data
= cs
->wme
->data
;
2082 data
->mx
= data
->cx
;
2083 data
->my
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2085 return (WINDOW_COPY_CMD_REDRAW
);
2088 static enum window_copy_cmd_action
2089 window_copy_cmd_start_of_line(struct window_copy_cmd_state
*cs
)
2091 struct window_mode_entry
*wme
= cs
->wme
;
2093 window_copy_cursor_start_of_line(wme
);
2094 return (WINDOW_COPY_CMD_NOTHING
);
2097 static enum window_copy_cmd_action
2098 window_copy_cmd_top_line(struct window_copy_cmd_state
*cs
)
2100 struct window_mode_entry
*wme
= cs
->wme
;
2101 struct window_copy_mode_data
*data
= wme
->data
;
2106 window_copy_update_selection(wme
, 1, 0);
2107 return (WINDOW_COPY_CMD_REDRAW
);
2110 static enum window_copy_cmd_action
2111 window_copy_cmd_copy_pipe_no_clear(struct window_copy_cmd_state
*cs
)
2113 struct window_mode_entry
*wme
= cs
->wme
;
2114 struct client
*c
= cs
->c
;
2115 struct session
*s
= cs
->s
;
2116 struct winlink
*wl
= cs
->wl
;
2117 struct window_pane
*wp
= wme
->wp
;
2118 char *command
= NULL
, *prefix
= NULL
;
2119 const char *arg1
= args_string(cs
->args
, 1);
2120 const char *arg2
= args_string(cs
->args
, 2);
2123 prefix
= format_single(NULL
, arg2
, c
, s
, wl
, wp
);
2125 if (s
!= NULL
&& arg1
!= NULL
&& *arg1
!= '\0')
2126 command
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
2127 window_copy_copy_pipe(wme
, s
, prefix
, command
);
2131 return (WINDOW_COPY_CMD_NOTHING
);
2134 static enum window_copy_cmd_action
2135 window_copy_cmd_copy_pipe(struct window_copy_cmd_state
*cs
)
2137 struct window_mode_entry
*wme
= cs
->wme
;
2139 window_copy_cmd_copy_pipe_no_clear(cs
);
2140 window_copy_clear_selection(wme
);
2141 return (WINDOW_COPY_CMD_REDRAW
);
2144 static enum window_copy_cmd_action
2145 window_copy_cmd_copy_pipe_and_cancel(struct window_copy_cmd_state
*cs
)
2147 struct window_mode_entry
*wme
= cs
->wme
;
2149 window_copy_cmd_copy_pipe_no_clear(cs
);
2150 window_copy_clear_selection(wme
);
2151 return (WINDOW_COPY_CMD_CANCEL
);
2154 static enum window_copy_cmd_action
2155 window_copy_cmd_pipe_no_clear(struct window_copy_cmd_state
*cs
)
2157 struct window_mode_entry
*wme
= cs
->wme
;
2158 struct client
*c
= cs
->c
;
2159 struct session
*s
= cs
->s
;
2160 struct winlink
*wl
= cs
->wl
;
2161 struct window_pane
*wp
= wme
->wp
;
2162 char *command
= NULL
;
2163 const char *arg1
= args_string(cs
->args
, 1);
2165 if (s
!= NULL
&& arg1
!= NULL
&& *arg1
!= '\0')
2166 command
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
2167 window_copy_pipe(wme
, s
, command
);
2170 return (WINDOW_COPY_CMD_NOTHING
);
2173 static enum window_copy_cmd_action
2174 window_copy_cmd_pipe(struct window_copy_cmd_state
*cs
)
2176 struct window_mode_entry
*wme
= cs
->wme
;
2178 window_copy_cmd_pipe_no_clear(cs
);
2179 window_copy_clear_selection(wme
);
2180 return (WINDOW_COPY_CMD_REDRAW
);
2183 static enum window_copy_cmd_action
2184 window_copy_cmd_pipe_and_cancel(struct window_copy_cmd_state
*cs
)
2186 struct window_mode_entry
*wme
= cs
->wme
;
2188 window_copy_cmd_pipe_no_clear(cs
);
2189 window_copy_clear_selection(wme
);
2190 return (WINDOW_COPY_CMD_CANCEL
);
2193 static enum window_copy_cmd_action
2194 window_copy_cmd_goto_line(struct window_copy_cmd_state
*cs
)
2196 struct window_mode_entry
*wme
= cs
->wme
;
2197 const char *arg1
= args_string(cs
->args
, 1);
2200 window_copy_goto_line(wme
, arg1
);
2201 return (WINDOW_COPY_CMD_NOTHING
);
2204 static enum window_copy_cmd_action
2205 window_copy_cmd_jump_backward(struct window_copy_cmd_state
*cs
)
2207 struct window_mode_entry
*wme
= cs
->wme
;
2208 struct window_copy_mode_data
*data
= wme
->data
;
2209 u_int np
= wme
->prefix
;
2210 const char *arg1
= args_string(cs
->args
, 1);
2212 if (*arg1
!= '\0') {
2213 data
->jumptype
= WINDOW_COPY_JUMPBACKWARD
;
2214 free(data
->jumpchar
);
2215 data
->jumpchar
= utf8_fromcstr(arg1
);
2216 for (; np
!= 0; np
--)
2217 window_copy_cursor_jump_back(wme
);
2219 return (WINDOW_COPY_CMD_NOTHING
);
2222 static enum window_copy_cmd_action
2223 window_copy_cmd_jump_forward(struct window_copy_cmd_state
*cs
)
2225 struct window_mode_entry
*wme
= cs
->wme
;
2226 struct window_copy_mode_data
*data
= wme
->data
;
2227 u_int np
= wme
->prefix
;
2228 const char *arg1
= args_string(cs
->args
, 1);
2230 if (*arg1
!= '\0') {
2231 data
->jumptype
= WINDOW_COPY_JUMPFORWARD
;
2232 free(data
->jumpchar
);
2233 data
->jumpchar
= utf8_fromcstr(arg1
);
2234 for (; np
!= 0; np
--)
2235 window_copy_cursor_jump(wme
);
2237 return (WINDOW_COPY_CMD_NOTHING
);
2240 static enum window_copy_cmd_action
2241 window_copy_cmd_jump_to_backward(struct window_copy_cmd_state
*cs
)
2243 struct window_mode_entry
*wme
= cs
->wme
;
2244 struct window_copy_mode_data
*data
= wme
->data
;
2245 u_int np
= wme
->prefix
;
2246 const char *arg1
= args_string(cs
->args
, 1);
2248 if (*arg1
!= '\0') {
2249 data
->jumptype
= WINDOW_COPY_JUMPTOBACKWARD
;
2250 free(data
->jumpchar
);
2251 data
->jumpchar
= utf8_fromcstr(arg1
);
2252 for (; np
!= 0; np
--)
2253 window_copy_cursor_jump_to_back(wme
);
2255 return (WINDOW_COPY_CMD_NOTHING
);
2258 static enum window_copy_cmd_action
2259 window_copy_cmd_jump_to_forward(struct window_copy_cmd_state
*cs
)
2261 struct window_mode_entry
*wme
= cs
->wme
;
2262 struct window_copy_mode_data
*data
= wme
->data
;
2263 u_int np
= wme
->prefix
;
2264 const char *arg1
= args_string(cs
->args
, 1);
2266 if (*arg1
!= '\0') {
2267 data
->jumptype
= WINDOW_COPY_JUMPTOFORWARD
;
2268 free(data
->jumpchar
);
2269 data
->jumpchar
= utf8_fromcstr(arg1
);
2270 for (; np
!= 0; np
--)
2271 window_copy_cursor_jump_to(wme
);
2273 return (WINDOW_COPY_CMD_NOTHING
);
2276 static enum window_copy_cmd_action
2277 window_copy_cmd_jump_to_mark(struct window_copy_cmd_state
*cs
)
2279 struct window_mode_entry
*wme
= cs
->wme
;
2281 window_copy_jump_to_mark(wme
);
2282 return (WINDOW_COPY_CMD_NOTHING
);
2285 static enum window_copy_cmd_action
2286 window_copy_cmd_next_prompt(struct window_copy_cmd_state
*cs
)
2288 struct window_mode_entry
*wme
= cs
->wme
;
2289 const char *arg1
= args_string(cs
->args
, 1);
2291 window_copy_cursor_prompt(wme
, 1, arg1
);
2292 return (WINDOW_COPY_CMD_NOTHING
);
2295 static enum window_copy_cmd_action
2296 window_copy_cmd_previous_prompt(struct window_copy_cmd_state
*cs
)
2298 struct window_mode_entry
*wme
= cs
->wme
;
2299 const char *arg1
= args_string(cs
->args
, 1);
2301 window_copy_cursor_prompt(wme
, 0, arg1
);
2302 return (WINDOW_COPY_CMD_NOTHING
);
2305 static enum window_copy_cmd_action
2306 window_copy_cmd_search_backward(struct window_copy_cmd_state
*cs
)
2308 struct window_mode_entry
*wme
= cs
->wme
;
2309 struct window_copy_mode_data
*data
= wme
->data
;
2310 u_int np
= wme
->prefix
;
2312 if (!window_copy_expand_search_string(cs
))
2313 return (WINDOW_COPY_CMD_NOTHING
);
2315 if (data
->searchstr
!= NULL
) {
2316 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2317 data
->searchregex
= 1;
2319 for (; np
!= 0; np
--)
2320 window_copy_search_up(wme
, 1);
2322 return (WINDOW_COPY_CMD_NOTHING
);
2325 static enum window_copy_cmd_action
2326 window_copy_cmd_search_backward_text(struct window_copy_cmd_state
*cs
)
2328 struct window_mode_entry
*wme
= cs
->wme
;
2329 struct window_copy_mode_data
*data
= wme
->data
;
2330 u_int np
= wme
->prefix
;
2332 if (!window_copy_expand_search_string(cs
))
2333 return (WINDOW_COPY_CMD_NOTHING
);
2335 if (data
->searchstr
!= NULL
) {
2336 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2337 data
->searchregex
= 0;
2339 for (; np
!= 0; np
--)
2340 window_copy_search_up(wme
, 0);
2342 return (WINDOW_COPY_CMD_NOTHING
);
2345 static enum window_copy_cmd_action
2346 window_copy_cmd_search_forward(struct window_copy_cmd_state
*cs
)
2348 struct window_mode_entry
*wme
= cs
->wme
;
2349 struct window_copy_mode_data
*data
= wme
->data
;
2350 u_int np
= wme
->prefix
;
2352 if (!window_copy_expand_search_string(cs
))
2353 return (WINDOW_COPY_CMD_NOTHING
);
2355 if (data
->searchstr
!= NULL
) {
2356 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2357 data
->searchregex
= 1;
2359 for (; np
!= 0; np
--)
2360 window_copy_search_down(wme
, 1);
2362 return (WINDOW_COPY_CMD_NOTHING
);
2365 static enum window_copy_cmd_action
2366 window_copy_cmd_search_forward_text(struct window_copy_cmd_state
*cs
)
2368 struct window_mode_entry
*wme
= cs
->wme
;
2369 struct window_copy_mode_data
*data
= wme
->data
;
2370 u_int np
= wme
->prefix
;
2372 if (!window_copy_expand_search_string(cs
))
2373 return (WINDOW_COPY_CMD_NOTHING
);
2375 if (data
->searchstr
!= NULL
) {
2376 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2377 data
->searchregex
= 0;
2379 for (; np
!= 0; np
--)
2380 window_copy_search_down(wme
, 0);
2382 return (WINDOW_COPY_CMD_NOTHING
);
2385 static enum window_copy_cmd_action
2386 window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state
*cs
)
2388 struct window_mode_entry
*wme
= cs
->wme
;
2389 struct window_copy_mode_data
*data
= wme
->data
;
2390 const char *arg1
= args_string(cs
->args
, 1);
2391 const char *ss
= data
->searchstr
;
2393 enum window_copy_cmd_action action
= WINDOW_COPY_CMD_NOTHING
;
2397 log_debug("%s: %s", __func__
, arg1
);
2400 if (data
->searchx
== -1 || data
->searchy
== -1) {
2401 data
->searchx
= data
->cx
;
2402 data
->searchy
= data
->cy
;
2403 data
->searcho
= data
->oy
;
2404 } else if (ss
!= NULL
&& strcmp(arg1
, ss
) != 0) {
2405 data
->cx
= data
->searchx
;
2406 data
->cy
= data
->searchy
;
2407 data
->oy
= data
->searcho
;
2408 action
= WINDOW_COPY_CMD_REDRAW
;
2410 if (*arg1
== '\0') {
2411 window_copy_clear_marks(wme
);
2412 return (WINDOW_COPY_CMD_REDRAW
);
2417 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2418 data
->searchregex
= 0;
2419 free(data
->searchstr
);
2420 data
->searchstr
= xstrdup(arg1
);
2421 if (!window_copy_search_up(wme
, 0)) {
2422 window_copy_clear_marks(wme
);
2423 return (WINDOW_COPY_CMD_REDRAW
);
2427 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2428 data
->searchregex
= 0;
2429 free(data
->searchstr
);
2430 data
->searchstr
= xstrdup(arg1
);
2431 if (!window_copy_search_down(wme
, 0)) {
2432 window_copy_clear_marks(wme
);
2433 return (WINDOW_COPY_CMD_REDRAW
);
2440 static enum window_copy_cmd_action
2441 window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state
*cs
)
2443 struct window_mode_entry
*wme
= cs
->wme
;
2444 struct window_copy_mode_data
*data
= wme
->data
;
2445 const char *arg1
= args_string(cs
->args
, 1);
2446 const char *ss
= data
->searchstr
;
2448 enum window_copy_cmd_action action
= WINDOW_COPY_CMD_NOTHING
;
2452 log_debug("%s: %s", __func__
, arg1
);
2455 if (data
->searchx
== -1 || data
->searchy
== -1) {
2456 data
->searchx
= data
->cx
;
2457 data
->searchy
= data
->cy
;
2458 data
->searcho
= data
->oy
;
2459 } else if (ss
!= NULL
&& strcmp(arg1
, ss
) != 0) {
2460 data
->cx
= data
->searchx
;
2461 data
->cy
= data
->searchy
;
2462 data
->oy
= data
->searcho
;
2463 action
= WINDOW_COPY_CMD_REDRAW
;
2465 if (*arg1
== '\0') {
2466 window_copy_clear_marks(wme
);
2467 return (WINDOW_COPY_CMD_REDRAW
);
2472 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2473 data
->searchregex
= 0;
2474 free(data
->searchstr
);
2475 data
->searchstr
= xstrdup(arg1
);
2476 if (!window_copy_search_down(wme
, 0)) {
2477 window_copy_clear_marks(wme
);
2478 return (WINDOW_COPY_CMD_REDRAW
);
2482 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2483 data
->searchregex
= 0;
2484 free(data
->searchstr
);
2485 data
->searchstr
= xstrdup(arg1
);
2486 if (!window_copy_search_up(wme
, 0)) {
2487 window_copy_clear_marks(wme
);
2488 return (WINDOW_COPY_CMD_REDRAW
);
2494 static enum window_copy_cmd_action
2495 window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state
*cs
)
2497 struct window_mode_entry
*wme
= cs
->wme
;
2498 struct window_pane
*wp
= wme
->swp
;
2499 struct window_copy_mode_data
*data
= wme
->data
;
2502 return (WINDOW_COPY_CMD_NOTHING
);
2504 screen_free(data
->backing
);
2505 free(data
->backing
);
2506 data
->backing
= window_copy_clone_screen(&wp
->base
, &data
->screen
, NULL
,
2507 NULL
, wme
->swp
!= wme
->wp
);
2509 window_copy_size_changed(wme
);
2510 return (WINDOW_COPY_CMD_REDRAW
);
2513 static const struct {
2514 const char *command
;
2517 enum window_copy_cmd_clear clear
;
2518 enum window_copy_cmd_action (*f
)(struct window_copy_cmd_state
*);
2519 } window_copy_cmd_table
[] = {
2520 { .command
= "append-selection",
2523 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2524 .f
= window_copy_cmd_append_selection
2526 { .command
= "append-selection-and-cancel",
2529 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2530 .f
= window_copy_cmd_append_selection_and_cancel
2532 { .command
= "back-to-indentation",
2535 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2536 .f
= window_copy_cmd_back_to_indentation
2538 { .command
= "begin-selection",
2541 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2542 .f
= window_copy_cmd_begin_selection
2544 { .command
= "bottom-line",
2547 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2548 .f
= window_copy_cmd_bottom_line
2550 { .command
= "cancel",
2553 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2554 .f
= window_copy_cmd_cancel
2556 { .command
= "clear-selection",
2559 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2560 .f
= window_copy_cmd_clear_selection
2562 { .command
= "copy-end-of-line",
2565 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2566 .f
= window_copy_cmd_copy_end_of_line
2568 { .command
= "copy-end-of-line-and-cancel",
2571 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2572 .f
= window_copy_cmd_copy_end_of_line_and_cancel
2574 { .command
= "copy-pipe-end-of-line",
2577 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2578 .f
= window_copy_cmd_copy_pipe_end_of_line
2580 { .command
= "copy-pipe-end-of-line-and-cancel",
2583 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2584 .f
= window_copy_cmd_copy_pipe_end_of_line_and_cancel
2586 { .command
= "copy-line",
2589 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2590 .f
= window_copy_cmd_copy_line
2592 { .command
= "copy-line-and-cancel",
2595 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2596 .f
= window_copy_cmd_copy_line_and_cancel
2598 { .command
= "copy-pipe-line",
2601 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2602 .f
= window_copy_cmd_copy_pipe_line
2604 { .command
= "copy-pipe-line-and-cancel",
2607 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2608 .f
= window_copy_cmd_copy_pipe_line_and_cancel
2610 { .command
= "copy-pipe-no-clear",
2613 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2614 .f
= window_copy_cmd_copy_pipe_no_clear
2616 { .command
= "copy-pipe",
2619 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2620 .f
= window_copy_cmd_copy_pipe
2622 { .command
= "copy-pipe-and-cancel",
2625 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2626 .f
= window_copy_cmd_copy_pipe_and_cancel
2628 { .command
= "copy-selection-no-clear",
2631 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2632 .f
= window_copy_cmd_copy_selection_no_clear
2634 { .command
= "copy-selection",
2637 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2638 .f
= window_copy_cmd_copy_selection
2640 { .command
= "copy-selection-and-cancel",
2643 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2644 .f
= window_copy_cmd_copy_selection_and_cancel
2646 { .command
= "cursor-down",
2649 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2650 .f
= window_copy_cmd_cursor_down
2652 { .command
= "cursor-down-and-cancel",
2655 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2656 .f
= window_copy_cmd_cursor_down_and_cancel
2658 { .command
= "cursor-left",
2661 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2662 .f
= window_copy_cmd_cursor_left
2664 { .command
= "cursor-right",
2667 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2668 .f
= window_copy_cmd_cursor_right
2670 { .command
= "cursor-up",
2673 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2674 .f
= window_copy_cmd_cursor_up
2676 { .command
= "end-of-line",
2679 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2680 .f
= window_copy_cmd_end_of_line
2682 { .command
= "goto-line",
2685 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2686 .f
= window_copy_cmd_goto_line
2688 { .command
= "halfpage-down",
2691 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2692 .f
= window_copy_cmd_halfpage_down
2694 { .command
= "halfpage-down-and-cancel",
2697 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2698 .f
= window_copy_cmd_halfpage_down_and_cancel
2700 { .command
= "halfpage-up",
2703 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2704 .f
= window_copy_cmd_halfpage_up
2706 { .command
= "history-bottom",
2709 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2710 .f
= window_copy_cmd_history_bottom
2712 { .command
= "history-top",
2715 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2716 .f
= window_copy_cmd_history_top
2718 { .command
= "jump-again",
2721 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2722 .f
= window_copy_cmd_jump_again
2724 { .command
= "jump-backward",
2727 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2728 .f
= window_copy_cmd_jump_backward
2730 { .command
= "jump-forward",
2733 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2734 .f
= window_copy_cmd_jump_forward
2736 { .command
= "jump-reverse",
2739 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2740 .f
= window_copy_cmd_jump_reverse
2742 { .command
= "jump-to-backward",
2745 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2746 .f
= window_copy_cmd_jump_to_backward
2748 { .command
= "jump-to-forward",
2751 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2752 .f
= window_copy_cmd_jump_to_forward
2754 { .command
= "jump-to-mark",
2757 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2758 .f
= window_copy_cmd_jump_to_mark
2760 { .command
= "next-prompt",
2763 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2764 .f
= window_copy_cmd_next_prompt
2766 { .command
= "previous-prompt",
2769 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2770 .f
= window_copy_cmd_previous_prompt
2772 { .command
= "middle-line",
2775 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2776 .f
= window_copy_cmd_middle_line
2778 { .command
= "next-matching-bracket",
2781 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2782 .f
= window_copy_cmd_next_matching_bracket
2784 { .command
= "next-paragraph",
2787 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2788 .f
= window_copy_cmd_next_paragraph
2790 { .command
= "next-space",
2793 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2794 .f
= window_copy_cmd_next_space
2796 { .command
= "next-space-end",
2799 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2800 .f
= window_copy_cmd_next_space_end
2802 { .command
= "next-word",
2805 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2806 .f
= window_copy_cmd_next_word
2808 { .command
= "next-word-end",
2811 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2812 .f
= window_copy_cmd_next_word_end
2814 { .command
= "other-end",
2817 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2818 .f
= window_copy_cmd_other_end
2820 { .command
= "page-down",
2823 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2824 .f
= window_copy_cmd_page_down
2826 { .command
= "page-down-and-cancel",
2829 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2830 .f
= window_copy_cmd_page_down_and_cancel
2832 { .command
= "page-up",
2835 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2836 .f
= window_copy_cmd_page_up
2838 { .command
= "pipe-no-clear",
2841 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2842 .f
= window_copy_cmd_pipe_no_clear
2844 { .command
= "pipe",
2847 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2848 .f
= window_copy_cmd_pipe
2850 { .command
= "pipe-and-cancel",
2853 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2854 .f
= window_copy_cmd_pipe_and_cancel
2856 { .command
= "previous-matching-bracket",
2859 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2860 .f
= window_copy_cmd_previous_matching_bracket
2862 { .command
= "previous-paragraph",
2865 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2866 .f
= window_copy_cmd_previous_paragraph
2868 { .command
= "previous-space",
2871 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2872 .f
= window_copy_cmd_previous_space
2874 { .command
= "previous-word",
2877 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2878 .f
= window_copy_cmd_previous_word
2880 { .command
= "rectangle-on",
2883 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2884 .f
= window_copy_cmd_rectangle_on
2886 { .command
= "rectangle-off",
2889 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2890 .f
= window_copy_cmd_rectangle_off
2892 { .command
= "rectangle-toggle",
2895 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2896 .f
= window_copy_cmd_rectangle_toggle
2898 { .command
= "refresh-from-pane",
2901 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2902 .f
= window_copy_cmd_refresh_from_pane
2904 { .command
= "scroll-bottom",
2907 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2908 .f
= window_copy_cmd_scroll_bottom
2910 { .command
= "scroll-down",
2913 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2914 .f
= window_copy_cmd_scroll_down
2916 { .command
= "scroll-down-and-cancel",
2919 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2920 .f
= window_copy_cmd_scroll_down_and_cancel
2922 { .command
= "scroll-middle",
2925 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2926 .f
= window_copy_cmd_scroll_middle
2928 { .command
= "scroll-top",
2931 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2932 .f
= window_copy_cmd_scroll_top
2934 { .command
= "scroll-up",
2937 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2938 .f
= window_copy_cmd_scroll_up
2940 { .command
= "search-again",
2943 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2944 .f
= window_copy_cmd_search_again
2946 { .command
= "search-backward",
2949 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2950 .f
= window_copy_cmd_search_backward
2952 { .command
= "search-backward-text",
2955 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2956 .f
= window_copy_cmd_search_backward_text
2958 { .command
= "search-backward-incremental",
2961 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2962 .f
= window_copy_cmd_search_backward_incremental
2964 { .command
= "search-forward",
2967 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2968 .f
= window_copy_cmd_search_forward
2970 { .command
= "search-forward-text",
2973 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2974 .f
= window_copy_cmd_search_forward_text
2976 { .command
= "search-forward-incremental",
2979 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2980 .f
= window_copy_cmd_search_forward_incremental
2982 { .command
= "search-reverse",
2985 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2986 .f
= window_copy_cmd_search_reverse
2988 { .command
= "select-line",
2991 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2992 .f
= window_copy_cmd_select_line
2994 { .command
= "select-word",
2997 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2998 .f
= window_copy_cmd_select_word
3000 { .command
= "set-mark",
3003 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
3004 .f
= window_copy_cmd_set_mark
3006 { .command
= "start-of-line",
3009 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
3010 .f
= window_copy_cmd_start_of_line
3012 { .command
= "stop-selection",
3015 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
3016 .f
= window_copy_cmd_stop_selection
3018 { .command
= "toggle-position",
3021 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
3022 .f
= window_copy_cmd_toggle_position
3024 { .command
= "top-line",
3027 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
3028 .f
= window_copy_cmd_top_line
3033 window_copy_command(struct window_mode_entry
*wme
, struct client
*c
,
3034 struct session
*s
, struct winlink
*wl
, struct args
*args
,
3035 struct mouse_event
*m
)
3037 struct window_copy_mode_data
*data
= wme
->data
;
3038 struct window_copy_cmd_state cs
;
3039 enum window_copy_cmd_action action
;
3040 enum window_copy_cmd_clear clear
= WINDOW_COPY_CMD_CLEAR_NEVER
;
3041 const char *command
;
3042 u_int i
, count
= args_count(args
);
3047 command
= args_string(args
, 0);
3049 if (m
!= NULL
&& m
->valid
&& !MOUSE_WHEEL(m
->b
))
3050 window_copy_move_mouse(m
);
3060 action
= WINDOW_COPY_CMD_NOTHING
;
3061 for (i
= 0; i
< nitems(window_copy_cmd_table
); i
++) {
3062 if (strcmp(window_copy_cmd_table
[i
].command
, command
) == 0) {
3063 if (count
- 1 < window_copy_cmd_table
[i
].minargs
||
3064 count
- 1 > window_copy_cmd_table
[i
].maxargs
)
3066 clear
= window_copy_cmd_table
[i
].clear
;
3067 action
= window_copy_cmd_table
[i
].f(&cs
);
3072 if (strncmp(command
, "search-", 7) != 0 && data
->searchmark
!= NULL
) {
3073 keys
= options_get_number(wme
->wp
->window
->options
, "mode-keys");
3074 if (clear
== WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
&&
3076 clear
= WINDOW_COPY_CMD_CLEAR_NEVER
;
3077 if (clear
!= WINDOW_COPY_CMD_CLEAR_NEVER
) {
3078 window_copy_clear_marks(wme
);
3079 data
->searchx
= data
->searchy
= -1;
3081 if (action
== WINDOW_COPY_CMD_NOTHING
)
3082 action
= WINDOW_COPY_CMD_REDRAW
;
3086 if (action
== WINDOW_COPY_CMD_CANCEL
)
3087 window_pane_reset_mode(wme
->wp
);
3088 else if (action
== WINDOW_COPY_CMD_REDRAW
)
3089 window_copy_redraw_screen(wme
);
3093 window_copy_scroll_to(struct window_mode_entry
*wme
, u_int px
, u_int py
,
3096 struct window_copy_mode_data
*data
= wme
->data
;
3097 struct grid
*gd
= data
->backing
->grid
;
3102 if (py
>= gd
->hsize
- data
->oy
&& py
< gd
->hsize
- data
->oy
+ gd
->sy
)
3103 data
->cy
= py
- (gd
->hsize
- data
->oy
);
3109 } else if (py
> gd
->hsize
+ gd
->sy
- gap
) {
3111 data
->cy
= py
- gd
->hsize
;
3113 offset
= py
+ gap
- gd
->sy
;
3114 data
->cy
= py
- offset
;
3116 data
->oy
= gd
->hsize
- offset
;
3119 if (!no_redraw
&& data
->searchmark
!= NULL
&& !data
->timeout
)
3120 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
3121 window_copy_update_selection(wme
, 1, 0);
3123 window_copy_redraw_screen(wme
);
3127 window_copy_search_compare(struct grid
*gd
, u_int px
, u_int py
,
3128 struct grid
*sgd
, u_int spx
, int cis
)
3130 struct grid_cell gc
, sgc
;
3131 const struct utf8_data
*ud
, *sud
;
3133 grid_get_cell(gd
, px
, py
, &gc
);
3135 grid_get_cell(sgd
, spx
, 0, &sgc
);
3138 if (ud
->size
!= sud
->size
|| ud
->width
!= sud
->width
)
3141 if (cis
&& ud
->size
== 1)
3142 return (tolower(ud
->data
[0]) == sud
->data
[0]);
3144 return (memcmp(ud
->data
, sud
->data
, ud
->size
) == 0);
3148 window_copy_search_lr(struct grid
*gd
, struct grid
*sgd
, u_int
*ppx
, u_int py
,
3149 u_int first
, u_int last
, int cis
)
3151 u_int ax
, bx
, px
, pywrap
, endline
;
3153 struct grid_line
*gl
;
3155 endline
= gd
->hsize
+ gd
->sy
- 1;
3156 for (ax
= first
; ax
< last
; ax
++) {
3157 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
3161 while (px
>= gd
->sx
&& pywrap
< endline
) {
3162 gl
= grid_get_line(gd
, pywrap
);
3163 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3168 /* We have run off the end of the grid. */
3171 matched
= window_copy_search_compare(gd
, px
, pywrap
,
3176 if (bx
== sgd
->sx
) {
3185 window_copy_search_rl(struct grid
*gd
,
3186 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
, int cis
)
3188 u_int ax
, bx
, px
, pywrap
, endline
;
3190 struct grid_line
*gl
;
3192 endline
= gd
->hsize
+ gd
->sy
- 1;
3193 for (ax
= last
; ax
> first
; ax
--) {
3194 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
3198 while (px
>= gd
->sx
&& pywrap
< endline
) {
3199 gl
= grid_get_line(gd
, pywrap
);
3200 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3205 /* We have run off the end of the grid. */
3208 matched
= window_copy_search_compare(gd
, px
, pywrap
,
3213 if (bx
== sgd
->sx
) {
3222 window_copy_search_lr_regex(struct grid
*gd
, u_int
*ppx
, u_int
*psx
, u_int py
,
3223 u_int first
, u_int last
, regex_t
*reg
)
3226 u_int endline
, foundx
, foundy
, len
, pywrap
, size
= 1;
3228 regmatch_t regmatch
;
3229 struct grid_line
*gl
;
3232 * This can happen during search if the last match was the last
3233 * character on a line.
3238 /* Set flags for regex search. */
3240 eflags
|= REG_NOTBOL
;
3242 /* Need to look at the entire string. */
3243 buf
= xmalloc(size
);
3245 buf
= window_copy_stringify(gd
, py
, first
, gd
->sx
, buf
, &size
);
3246 len
= gd
->sx
- first
;
3247 endline
= gd
->hsize
+ gd
->sy
- 1;
3249 while (buf
!= NULL
&&
3250 pywrap
<= endline
&&
3251 len
< WINDOW_COPY_SEARCH_MAX_LINE
) {
3252 gl
= grid_get_line(gd
, pywrap
);
3253 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3256 buf
= window_copy_stringify(gd
, pywrap
, 0, gd
->sx
, buf
, &size
);
3260 if (regexec(reg
, buf
, 1, ®match
, eflags
) == 0 &&
3261 regmatch
.rm_so
!= regmatch
.rm_eo
) {
3264 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3265 buf
+ regmatch
.rm_so
);
3266 if (foundy
== py
&& foundx
< last
) {
3268 len
-= foundx
- first
;
3269 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3270 buf
+ regmatch
.rm_eo
);
3272 while (foundy
> py
) {
3289 window_copy_search_rl_regex(struct grid
*gd
, u_int
*ppx
, u_int
*psx
, u_int py
,
3290 u_int first
, u_int last
, regex_t
*reg
)
3293 u_int endline
, len
, pywrap
, size
= 1;
3295 struct grid_line
*gl
;
3297 /* Set flags for regex search. */
3299 eflags
|= REG_NOTBOL
;
3301 /* Need to look at the entire string. */
3302 buf
= xmalloc(size
);
3304 buf
= window_copy_stringify(gd
, py
, first
, gd
->sx
, buf
, &size
);
3305 len
= gd
->sx
- first
;
3306 endline
= gd
->hsize
+ gd
->sy
- 1;
3308 while (buf
!= NULL
&&
3309 pywrap
<= endline
&&
3310 len
< WINDOW_COPY_SEARCH_MAX_LINE
) {
3311 gl
= grid_get_line(gd
, pywrap
);
3312 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3315 buf
= window_copy_stringify(gd
, pywrap
, 0, gd
->sx
, buf
, &size
);
3319 if (window_copy_last_regex(gd
, py
, first
, last
, len
, ppx
, psx
, buf
,
3333 window_copy_cellstring(const struct grid_line
*gl
, u_int px
, size_t *size
,
3336 static struct utf8_data ud
;
3337 struct grid_cell_entry
*gce
;
3340 if (px
>= gl
->cellsize
) {
3346 gce
= &gl
->celldata
[px
];
3347 if (gce
->flags
& GRID_FLAG_PADDING
) {
3352 if (~gce
->flags
& GRID_FLAG_EXTENDED
) {
3355 return (&gce
->data
.data
);
3358 utf8_to_data(gl
->extddata
[gce
->offset
].data
, &ud
);
3367 copy
= xmalloc(ud
.size
);
3368 memcpy(copy
, ud
.data
, ud
.size
);
3372 /* Find last match in given range. */
3374 window_copy_last_regex(struct grid
*gd
, u_int py
, u_int first
, u_int last
,
3375 u_int len
, u_int
*ppx
, u_int
*psx
, const char *buf
, const regex_t
*preg
,
3378 u_int foundx
, foundy
, oldx
, px
= 0, savepx
, savesx
= 0;
3379 regmatch_t regmatch
;
3384 while (regexec(preg
, buf
+ px
, 1, ®match
, eflags
) == 0) {
3385 if (regmatch
.rm_so
== regmatch
.rm_eo
)
3387 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3388 buf
+ px
+ regmatch
.rm_so
);
3389 if (foundy
> py
|| foundx
>= last
)
3391 len
-= foundx
- oldx
;
3393 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3394 buf
+ px
+ regmatch
.rm_eo
);
3395 if (foundy
> py
|| foundx
>= last
) {
3398 while (foundy
> py
) {
3405 savesx
= foundx
- savepx
;
3409 px
+= regmatch
.rm_eo
;
3423 /* Stringify line and append to input buffer. Caller frees. */
3425 window_copy_stringify(struct grid
*gd
, u_int py
, u_int first
, u_int last
,
3426 char *buf
, u_int
*size
)
3428 u_int ax
, bx
, newsize
= *size
;
3429 const struct grid_line
*gl
;
3431 size_t bufsize
= 1024, dlen
;
3434 while (bufsize
< newsize
)
3436 buf
= xrealloc(buf
, bufsize
);
3438 gl
= grid_peek_line(gd
, py
);
3440 for (ax
= first
; ax
< last
; ax
++) {
3441 d
= window_copy_cellstring(gl
, ax
, &dlen
, &allocated
);
3443 while (bufsize
< newsize
) {
3445 buf
= xrealloc(buf
, bufsize
);
3450 memcpy(buf
+ bx
, d
, dlen
);
3456 buf
[newsize
- 1] = '\0';
3462 /* Map start of C string containing UTF-8 data to grid cell position. */
3464 window_copy_cstrtocellpos(struct grid
*gd
, u_int ncells
, u_int
*ppx
, u_int
*ppy
,
3467 u_int cell
, ccell
, px
, pywrap
, pos
, len
;
3469 const struct grid_line
*gl
;
3478 /* Populate the array of cell data. */
3479 cells
= xreallocarray(NULL
, ncells
, sizeof cells
[0]);
3483 gl
= grid_peek_line(gd
, pywrap
);
3484 while (cell
< ncells
) {
3485 cells
[cell
].d
= window_copy_cellstring(gl
, px
,
3486 &cells
[cell
].dlen
, &cells
[cell
].allocated
);
3492 gl
= grid_peek_line(gd
, pywrap
);
3496 /* Locate starting cell. */
3499 while (cell
< ncells
) {
3503 while (ccell
< ncells
) {
3504 if (str
[pos
] == '\0') {
3509 dlen
= cells
[ccell
].dlen
;
3511 if (str
[pos
] != *d
) {
3517 if (dlen
> len
- pos
)
3519 if (memcmp(str
+ pos
, d
, dlen
) != 0) {
3532 /* If not found this will be one past the end. */
3535 while (px
>= gd
->sx
) {
3543 /* Free cell data. */
3544 for (cell
= 0; cell
< ncells
; cell
++) {
3545 if (cells
[cell
].allocated
)
3546 free((void *)cells
[cell
].d
);
3552 window_copy_move_left(struct screen
*s
, u_int
*fx
, u_int
*fy
, int wrapflag
)
3554 if (*fx
== 0) { /* left */
3555 if (*fy
== 0) { /* top */
3557 *fx
= screen_size_x(s
) - 1;
3558 *fy
= screen_hsize(s
) + screen_size_y(s
) - 1;
3562 *fx
= screen_size_x(s
) - 1;
3569 window_copy_move_right(struct screen
*s
, u_int
*fx
, u_int
*fy
, int wrapflag
)
3571 if (*fx
== screen_size_x(s
) - 1) { /* right */
3572 if (*fy
== screen_hsize(s
) + screen_size_y(s
) - 1) { /* bottom */
3586 window_copy_is_lowercase(const char *ptr
)
3588 while (*ptr
!= '\0') {
3589 if (*ptr
!= tolower((u_char
)*ptr
))
3597 * Handle backward wrapped regex searches with overlapping matches. In this case
3598 * find the longest overlapping match from previous wrapped lines.
3601 window_copy_search_back_overlap(struct grid
*gd
, regex_t
*preg
, u_int
*ppx
,
3602 u_int
*psx
, u_int
*ppy
, u_int endline
)
3604 u_int endx
, endy
, oldendx
, oldendy
, px
, py
, sx
;
3607 oldendx
= *ppx
+ *psx
;
3609 while (oldendx
> gd
->sx
- 1) {
3617 while (found
&& px
== 0 && py
- 1 > endline
&&
3618 grid_get_line(gd
, py
- 2)->flags
& GRID_LINE_WRAPPED
&&
3619 endx
== oldendx
&& endy
== oldendy
) {
3621 found
= window_copy_search_rl_regex(gd
, &px
, &sx
, py
- 1, 0,
3626 while (endx
> gd
->sx
- 1) {
3630 if (endx
== oldendx
&& endy
== oldendy
) {
3639 * Search for text stored in sgd starting from position fx,fy up to endline. If
3640 * found, jump to it. If cis then ignore case. The direction is 0 for searching
3641 * up, down otherwise. If wrap then go to begin/end of grid and try again if
3645 window_copy_search_jump(struct window_mode_entry
*wme
, struct grid
*gd
,
3646 struct grid
*sgd
, u_int fx
, u_int fy
, u_int endline
, int cis
, int wrap
,
3647 int direction
, int regex
)
3649 u_int i
, px
, sx
, ssize
= 1;
3650 int found
= 0, cflags
= REG_EXTENDED
;
3655 sbuf
= xmalloc(ssize
);
3657 sbuf
= window_copy_stringify(sgd
, 0, 0, sgd
->sx
, sbuf
, &ssize
);
3659 cflags
|= REG_ICASE
;
3660 if (regcomp(®
, sbuf
, cflags
) != 0) {
3668 for (i
= fy
; i
<= endline
; i
++) {
3670 found
= window_copy_search_lr_regex(gd
,
3671 &px
, &sx
, i
, fx
, gd
->sx
, ®
);
3673 found
= window_copy_search_lr(gd
, sgd
,
3674 &px
, i
, fx
, gd
->sx
, cis
);
3681 for (i
= fy
+ 1; endline
< i
; i
--) {
3683 found
= window_copy_search_rl_regex(gd
,
3684 &px
, &sx
, i
- 1, 0, fx
+ 1, ®
);
3686 window_copy_search_back_overlap(gd
,
3687 ®
, &px
, &sx
, &i
, endline
);
3690 found
= window_copy_search_rl(gd
, sgd
,
3691 &px
, i
- 1, 0, fx
+ 1, cis
);
3704 window_copy_scroll_to(wme
, px
, i
, 1);
3708 return (window_copy_search_jump(wme
, gd
, sgd
,
3709 direction
? 0 : gd
->sx
- 1,
3710 direction
? 0 : gd
->hsize
+ gd
->sy
- 1, fy
, cis
, 0,
3717 window_copy_move_after_search_mark(struct window_copy_mode_data
*data
,
3718 u_int
*fx
, u_int
*fy
, int wrapflag
)
3720 struct screen
*s
= data
->backing
;
3723 if (window_copy_search_mark_at(data
, *fx
, *fy
, &start
) == 0 &&
3724 data
->searchmark
[start
] != 0) {
3725 while (window_copy_search_mark_at(data
, *fx
, *fy
, &at
) == 0) {
3726 if (data
->searchmark
[at
] != data
->searchmark
[start
])
3728 /* Stop if not wrapping and at the end of the grid. */
3730 *fx
== screen_size_x(s
) - 1 &&
3731 *fy
== screen_hsize(s
) + screen_size_y(s
) - 1)
3734 window_copy_move_right(s
, fx
, fy
, wrapflag
);
3740 * Search in for text searchstr. If direction is 0 then search up, otherwise
3744 window_copy_search(struct window_mode_entry
*wme
, int direction
, int regex
)
3746 struct window_pane
*wp
= wme
->wp
;
3747 struct window_copy_mode_data
*data
= wme
->data
;
3748 struct screen
*s
= data
->backing
, ss
;
3749 struct screen_write_ctx ctx
;
3750 struct grid
*gd
= s
->grid
;
3751 const char *str
= data
->searchstr
;
3752 u_int at
, endline
, fx
, fy
, start
;
3753 int cis
, found
, keys
, visible_only
;
3756 if (regex
&& str
[strcspn(str
, "^$*+()?[].\\")] == '\0')
3759 data
->searchdirection
= direction
;
3764 if (data
->searchall
|| wp
->searchstr
== NULL
||
3765 wp
->searchregex
!= regex
) {
3767 data
->searchall
= 0;
3769 visible_only
= (strcmp(wp
->searchstr
, str
) == 0);
3770 if (visible_only
== 0 && data
->searchmark
!= NULL
)
3771 window_copy_clear_marks(wme
);
3772 free(wp
->searchstr
);
3773 wp
->searchstr
= xstrdup(str
);
3774 wp
->searchregex
= regex
;
3777 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3779 screen_init(&ss
, screen_write_strlen("%s", str
), 1, 0);
3780 screen_write_start(&ctx
, &ss
);
3781 screen_write_nputs(&ctx
, -1, &grid_default_cell
, "%s", str
);
3782 screen_write_stop(&ctx
);
3784 wrapflag
= options_get_number(wp
->window
->options
, "wrap-search");
3785 cis
= window_copy_is_lowercase(str
);
3787 keys
= options_get_number(wp
->window
->options
, "mode-keys");
3791 * Behave according to mode-keys. If it is emacs, search forward
3792 * leaves the cursor after the match. If it is vi, the cursor
3793 * remains at the beginning of the match, regardless of
3794 * direction, which means that we need to start the next search
3795 * after the term the cursor is currently on when searching
3798 if (keys
== MODEKEY_VI
) {
3799 if (data
->searchmark
!= NULL
)
3800 window_copy_move_after_search_mark(data
, &fx
,
3804 * When there are no search marks, start the
3805 * search after the current cursor position.
3807 window_copy_move_right(s
, &fx
, &fy
, wrapflag
);
3810 endline
= gd
->hsize
+ gd
->sy
- 1;
3812 window_copy_move_left(s
, &fx
, &fy
, wrapflag
);
3816 found
= window_copy_search_jump(wme
, gd
, ss
.grid
, fx
, fy
, endline
, cis
,
3817 wrapflag
, direction
, regex
);
3819 window_copy_search_marks(wme
, &ss
, regex
, visible_only
);
3821 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3824 * When searching forward, if the cursor is not at the beginning
3825 * of the mark, search again.
3828 window_copy_search_mark_at(data
, fx
, fy
, &at
) == 0 &&
3830 data
->searchmark
!= NULL
&&
3831 data
->searchmark
[at
] == data
->searchmark
[at
- 1]) {
3832 window_copy_move_after_search_mark(data
, &fx
, &fy
,
3834 window_copy_search_jump(wme
, gd
, ss
.grid
, fx
,
3835 fy
, endline
, cis
, wrapflag
, direction
,
3838 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3843 * When in Emacs mode, position the cursor just after
3846 if (keys
== MODEKEY_EMACS
) {
3847 window_copy_move_after_search_mark(data
, &fx
,
3850 data
->cy
= fy
- screen_hsize(data
->backing
) +
3855 * When searching backward, position the cursor at the
3856 * beginning of the mark.
3858 if (window_copy_search_mark_at(data
, fx
, fy
,
3860 while (window_copy_search_mark_at(data
, fx
, fy
,
3862 data
->searchmark
!= NULL
&&
3863 data
->searchmark
[at
] ==
3864 data
->searchmark
[start
]) {
3867 screen_hsize(data
->backing
) +
3872 window_copy_move_left(s
, &fx
, &fy
, 0);
3877 window_copy_redraw_screen(wme
);
3884 window_copy_visible_lines(struct window_copy_mode_data
*data
, u_int
*start
,
3887 struct grid
*gd
= data
->backing
->grid
;
3888 const struct grid_line
*gl
;
3890 for (*start
= gd
->hsize
- data
->oy
; *start
> 0; (*start
)--) {
3891 gl
= grid_peek_line(gd
, (*start
) - 1);
3892 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3895 *end
= gd
->hsize
- data
->oy
+ gd
->sy
;
3899 window_copy_search_mark_at(struct window_copy_mode_data
*data
, u_int px
,
3900 u_int py
, u_int
*at
)
3902 struct screen
*s
= data
->backing
;
3903 struct grid
*gd
= s
->grid
;
3905 if (py
< gd
->hsize
- data
->oy
)
3907 if (py
> gd
->hsize
- data
->oy
+ gd
->sy
- 1)
3909 *at
= ((py
- (gd
->hsize
- data
->oy
)) * gd
->sx
) + px
;
3914 window_copy_search_marks(struct window_mode_entry
*wme
, struct screen
*ssp
,
3915 int regex
, int visible_only
)
3917 struct window_copy_mode_data
*data
= wme
->data
;
3918 struct screen
*s
= data
->backing
, ss
;
3919 struct screen_write_ctx ctx
;
3920 struct grid
*gd
= s
->grid
;
3921 int found
, cis
, stopped
= 0;
3922 int cflags
= REG_EXTENDED
;
3923 u_int px
, py
, i
, b
, nfound
= 0, width
;
3924 u_int ssize
= 1, start
, end
;
3927 uint64_t stop
= 0, tstart
, t
;
3930 width
= screen_write_strlen("%s", data
->searchstr
);
3931 screen_init(&ss
, width
, 1, 0);
3932 screen_write_start(&ctx
, &ss
);
3933 screen_write_nputs(&ctx
, -1, &grid_default_cell
, "%s",
3935 screen_write_stop(&ctx
);
3938 width
= screen_size_x(ssp
);
3940 cis
= window_copy_is_lowercase(data
->searchstr
);
3943 sbuf
= xmalloc(ssize
);
3945 sbuf
= window_copy_stringify(ssp
->grid
, 0, 0, ssp
->grid
->sx
,
3948 cflags
|= REG_ICASE
;
3949 if (regcomp(®
, sbuf
, cflags
) != 0) {
3955 tstart
= get_timer();
3958 window_copy_visible_lines(data
, &start
, &end
);
3961 end
= gd
->hsize
+ gd
->sy
;
3962 stop
= get_timer() + WINDOW_COPY_SEARCH_ALL_TIMEOUT
;
3966 free(data
->searchmark
);
3967 data
->searchmark
= xcalloc(gd
->sx
, gd
->sy
);
3968 data
->searchgen
= 1;
3970 for (py
= start
; py
< end
; py
++) {
3974 found
= window_copy_search_lr_regex(gd
,
3975 &px
, &width
, py
, px
, gd
->sx
, ®
);
3979 found
= window_copy_search_lr(gd
, ssp
->grid
,
3980 &px
, py
, px
, gd
->sx
, cis
);
3986 if (window_copy_search_mark_at(data
, px
, py
, &b
) == 0) {
3987 if (b
+ width
> gd
->sx
* gd
->sy
)
3988 width
= (gd
->sx
* gd
->sy
) - b
;
3989 for (i
= b
; i
< b
+ width
; i
++) {
3990 if (data
->searchmark
[i
] != 0)
3992 data
->searchmark
[i
] = data
->searchgen
;
3994 if (data
->searchgen
== UCHAR_MAX
)
3995 data
->searchgen
= 1;
4003 if (t
- tstart
> WINDOW_COPY_SEARCH_TIMEOUT
) {
4007 if (stop
!= 0 && t
> stop
) {
4012 if (data
->timeout
) {
4013 window_copy_clear_marks(wme
);
4017 if (stopped
&& stop
!= 0) {
4018 /* Try again but just the visible context. */
4019 window_copy_visible_lines(data
, &start
, &end
);
4024 if (!visible_only
) {
4027 data
->searchcount
= 1000;
4028 else if (nfound
> 100)
4029 data
->searchcount
= 100;
4030 else if (nfound
> 10)
4031 data
->searchcount
= 10;
4033 data
->searchcount
= -1;
4034 data
->searchmore
= 1;
4036 data
->searchcount
= nfound
;
4037 data
->searchmore
= 0;
4050 window_copy_clear_marks(struct window_mode_entry
*wme
)
4052 struct window_copy_mode_data
*data
= wme
->data
;
4054 free(data
->searchmark
);
4055 data
->searchmark
= NULL
;
4059 window_copy_search_up(struct window_mode_entry
*wme
, int regex
)
4061 return (window_copy_search(wme
, 0, regex
));
4065 window_copy_search_down(struct window_mode_entry
*wme
, int regex
)
4067 return (window_copy_search(wme
, 1, regex
));
4071 window_copy_goto_line(struct window_mode_entry
*wme
, const char *linestr
)
4073 struct window_copy_mode_data
*data
= wme
->data
;
4077 lineno
= strtonum(linestr
, -1, INT_MAX
, &errstr
);
4080 if (lineno
< 0 || (u_int
)lineno
> screen_hsize(data
->backing
))
4081 lineno
= screen_hsize(data
->backing
);
4084 window_copy_update_selection(wme
, 1, 0);
4085 window_copy_redraw_screen(wme
);
4089 window_copy_match_start_end(struct window_copy_mode_data
*data
, u_int at
,
4090 u_int
*start
, u_int
*end
)
4092 struct grid
*gd
= data
->backing
->grid
;
4093 u_int last
= (gd
->sy
* gd
->sx
) - 1;
4094 u_char mark
= data
->searchmark
[at
];
4097 while (*start
!= 0 && data
->searchmark
[*start
] == mark
)
4099 if (data
->searchmark
[*start
] != mark
)
4101 while (*end
!= last
&& data
->searchmark
[*end
] == mark
)
4103 if (data
->searchmark
[*end
] != mark
)
4108 window_copy_match_at_cursor(struct window_copy_mode_data
*data
)
4110 struct grid
*gd
= data
->backing
->grid
;
4111 struct grid_cell gc
;
4112 u_int at
, start
, end
, cy
, px
, py
;
4113 u_int sx
= screen_size_x(data
->backing
);
4117 if (data
->searchmark
== NULL
)
4120 cy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
4121 if (window_copy_search_mark_at(data
, data
->cx
, cy
, &at
) != 0)
4123 if (data
->searchmark
[at
] == 0) {
4124 /* Allow one position after the match. */
4125 if (at
== 0 || data
->searchmark
[--at
] == 0)
4128 window_copy_match_start_end(data
, at
, &start
, &end
);
4131 * Cells will not be set in the marked array unless they are valid text
4132 * and wrapping will be taken care of, so we can just copy.
4134 for (at
= start
; at
<= end
; at
++) {
4136 px
= at
- (py
* sx
);
4138 grid_get_cell(gd
, px
, gd
->hsize
+ py
- data
->oy
, &gc
);
4139 buf
= xrealloc(buf
, len
+ gc
.data
.size
+ 1);
4140 memcpy(buf
+ len
, gc
.data
.data
, gc
.data
.size
);
4141 len
+= gc
.data
.size
;
4149 window_copy_update_style(struct window_mode_entry
*wme
, u_int fx
, u_int fy
,
4150 struct grid_cell
*gc
, const struct grid_cell
*mgc
,
4151 const struct grid_cell
*cgc
, const struct grid_cell
*mkgc
)
4153 struct window_pane
*wp
= wme
->wp
;
4154 struct window_copy_mode_data
*data
= wme
->data
;
4155 u_int mark
, start
, end
, cy
, cursor
, current
;
4156 int inv
= 0, found
= 0;
4159 if (data
->showmark
&& fy
== data
->my
) {
4160 gc
->attr
= mkgc
->attr
;
4173 if (data
->searchmark
== NULL
)
4176 if (window_copy_search_mark_at(data
, fx
, fy
, ¤t
) != 0)
4178 mark
= data
->searchmark
[current
];
4182 cy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
4183 if (window_copy_search_mark_at(data
, data
->cx
, cy
, &cursor
) == 0) {
4184 keys
= options_get_number(wp
->window
->options
, "mode-keys");
4186 keys
== MODEKEY_EMACS
&&
4187 data
->searchdirection
) {
4188 if (data
->searchmark
[cursor
- 1] == mark
) {
4192 } else if (data
->searchmark
[cursor
] == mark
)
4195 window_copy_match_start_end(data
, cursor
, &start
, &end
);
4196 if (current
>= start
&& current
<= end
) {
4197 gc
->attr
= cgc
->attr
;
4211 gc
->attr
= mgc
->attr
;
4223 window_copy_write_one(struct window_mode_entry
*wme
,
4224 struct screen_write_ctx
*ctx
, u_int py
, u_int fy
, u_int nx
,
4225 const struct grid_cell
*mgc
, const struct grid_cell
*cgc
,
4226 const struct grid_cell
*mkgc
)
4228 struct window_copy_mode_data
*data
= wme
->data
;
4229 struct grid
*gd
= data
->backing
->grid
;
4230 struct grid_cell gc
;
4233 screen_write_cursormove(ctx
, 0, py
, 0);
4234 for (fx
= 0; fx
< nx
; fx
++) {
4235 grid_get_cell(gd
, fx
, fy
, &gc
);
4236 if (fx
+ gc
.data
.width
<= nx
) {
4237 window_copy_update_style(wme
, fx
, fy
, &gc
, mgc
, cgc
,
4239 screen_write_cell(ctx
, &gc
);
4245 window_copy_write_line(struct window_mode_entry
*wme
,
4246 struct screen_write_ctx
*ctx
, u_int py
)
4248 struct window_pane
*wp
= wme
->wp
;
4249 struct window_copy_mode_data
*data
= wme
->data
;
4250 struct screen
*s
= &data
->screen
;
4251 struct options
*oo
= wp
->window
->options
;
4252 struct grid_line
*gl
;
4253 struct grid_cell gc
, mgc
, cgc
, mkgc
;
4254 char hdr
[512], tmp
[256], *t
;
4256 u_int hsize
= screen_hsize(data
->backing
);
4258 style_apply(&gc
, oo
, "mode-style", NULL
);
4259 gc
.flags
|= GRID_FLAG_NOPALETTE
;
4260 style_apply(&mgc
, oo
, "copy-mode-match-style", NULL
);
4261 mgc
.flags
|= GRID_FLAG_NOPALETTE
;
4262 style_apply(&cgc
, oo
, "copy-mode-current-match-style", NULL
);
4263 cgc
.flags
|= GRID_FLAG_NOPALETTE
;
4264 style_apply(&mkgc
, oo
, "copy-mode-mark-style", NULL
);
4265 mkgc
.flags
|= GRID_FLAG_NOPALETTE
;
4267 if (py
== 0 && s
->rupper
< s
->rlower
&& !data
->hide_position
) {
4268 gl
= grid_get_line(data
->backing
->grid
, hsize
- data
->oy
);
4270 xsnprintf(tmp
, sizeof tmp
, "[%u/%u]", data
->oy
, hsize
);
4272 t
= format_pretty_time(gl
->time
, 1);
4273 xsnprintf(tmp
, sizeof tmp
, "%s [%u/%u]", t
, data
->oy
,
4278 if (data
->searchmark
== NULL
) {
4279 if (data
->timeout
) {
4280 size
= xsnprintf(hdr
, sizeof hdr
,
4281 "(timed out) %s", tmp
);
4283 size
= xsnprintf(hdr
, sizeof hdr
, "%s", tmp
);
4285 if (data
->searchcount
== -1)
4286 size
= xsnprintf(hdr
, sizeof hdr
, "%s", tmp
);
4288 size
= xsnprintf(hdr
, sizeof hdr
,
4289 "(%d%s results) %s", data
->searchcount
,
4290 data
->searchmore
? "+" : "", tmp
);
4293 if (size
> screen_size_x(s
))
4294 size
= screen_size_x(s
);
4295 screen_write_cursormove(ctx
, screen_size_x(s
) - size
, 0, 0);
4296 screen_write_puts(ctx
, &gc
, "%s", hdr
);
4300 if (size
< screen_size_x(s
)) {
4301 window_copy_write_one(wme
, ctx
, py
, hsize
- data
->oy
+ py
,
4302 screen_size_x(s
) - size
, &mgc
, &cgc
, &mkgc
);
4305 if (py
== data
->cy
&& data
->cx
== screen_size_x(s
)) {
4306 screen_write_cursormove(ctx
, screen_size_x(s
) - 1, py
, 0);
4307 screen_write_putc(ctx
, &grid_default_cell
, '$');
4312 window_copy_write_lines(struct window_mode_entry
*wme
,
4313 struct screen_write_ctx
*ctx
, u_int py
, u_int ny
)
4317 for (yy
= py
; yy
< py
+ ny
; yy
++)
4318 window_copy_write_line(wme
, ctx
, py
);
4322 window_copy_redraw_selection(struct window_mode_entry
*wme
, u_int old_y
)
4324 struct window_copy_mode_data
*data
= wme
->data
;
4325 struct grid
*gd
= data
->backing
->grid
;
4326 u_int new_y
, start
, end
;
4329 if (old_y
<= new_y
) {
4338 * In word selection mode the first word on the line below the cursor
4339 * might be selected, so add this line to the redraw area.
4341 if (data
->selflag
== SEL_WORD
) {
4342 /* Last grid line in data coordinates. */
4343 if (end
< gd
->sy
+ data
->oy
- 1)
4346 window_copy_redraw_lines(wme
, start
, end
- start
+ 1);
4350 window_copy_redraw_lines(struct window_mode_entry
*wme
, u_int py
, u_int ny
)
4352 struct window_pane
*wp
= wme
->wp
;
4353 struct window_copy_mode_data
*data
= wme
->data
;
4354 struct screen_write_ctx ctx
;
4357 screen_write_start_pane(&ctx
, wp
, NULL
);
4358 for (i
= py
; i
< py
+ ny
; i
++)
4359 window_copy_write_line(wme
, &ctx
, i
);
4360 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
4361 screen_write_stop(&ctx
);
4365 window_copy_redraw_screen(struct window_mode_entry
*wme
)
4367 struct window_copy_mode_data
*data
= wme
->data
;
4369 window_copy_redraw_lines(wme
, 0, screen_size_y(&data
->screen
));
4373 window_copy_synchronize_cursor_end(struct window_mode_entry
*wme
, int begin
,
4376 struct window_copy_mode_data
*data
= wme
->data
;
4380 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4381 switch (data
->selflag
) {
4386 if (data
->dy
> yy
|| (data
->dy
== yy
&& data
->dx
> xx
)) {
4387 /* Right to left selection. */
4388 window_copy_cursor_previous_word_pos(wme
,
4389 data
->separators
, &xx
, &yy
);
4392 /* Reset the end. */
4393 data
->endselx
= data
->endselrx
;
4394 data
->endsely
= data
->endselry
;
4396 /* Left to right selection. */
4397 if (xx
>= window_copy_find_length(wme
, yy
) ||
4398 !window_copy_in_set(wme
, xx
+ 1, yy
, WHITESPACE
)) {
4399 window_copy_cursor_next_word_end_pos(wme
,
4400 data
->separators
, &xx
, &yy
);
4403 /* Reset the start. */
4404 data
->selx
= data
->selrx
;
4405 data
->sely
= data
->selry
;
4412 if (data
->dy
> yy
) {
4413 /* Right to left selection. */
4417 /* Reset the end. */
4418 data
->endselx
= data
->endselrx
;
4419 data
->endsely
= data
->endselry
;
4421 /* Left to right selection. */
4422 if (yy
< data
->endselry
)
4423 yy
= data
->endselry
;
4424 xx
= window_copy_find_length(wme
, yy
);
4426 /* Reset the start. */
4427 data
->selx
= data
->selrx
;
4428 data
->sely
= data
->selry
;
4444 window_copy_synchronize_cursor(struct window_mode_entry
*wme
, int no_reset
)
4446 struct window_copy_mode_data
*data
= wme
->data
;
4448 switch (data
->cursordrag
) {
4449 case CURSORDRAG_ENDSEL
:
4450 window_copy_synchronize_cursor_end(wme
, 0, no_reset
);
4452 case CURSORDRAG_SEL
:
4453 window_copy_synchronize_cursor_end(wme
, 1, no_reset
);
4455 case CURSORDRAG_NONE
:
4461 window_copy_update_cursor(struct window_mode_entry
*wme
, u_int cx
, u_int cy
)
4463 struct window_pane
*wp
= wme
->wp
;
4464 struct window_copy_mode_data
*data
= wme
->data
;
4465 struct screen
*s
= &data
->screen
;
4466 struct screen_write_ctx ctx
;
4467 u_int old_cx
, old_cy
;
4469 old_cx
= data
->cx
; old_cy
= data
->cy
;
4470 data
->cx
= cx
; data
->cy
= cy
;
4471 if (old_cx
== screen_size_x(s
))
4472 window_copy_redraw_lines(wme
, old_cy
, 1);
4473 if (data
->cx
== screen_size_x(s
))
4474 window_copy_redraw_lines(wme
, data
->cy
, 1);
4476 screen_write_start_pane(&ctx
, wp
, NULL
);
4477 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
4478 screen_write_stop(&ctx
);
4483 window_copy_start_selection(struct window_mode_entry
*wme
)
4485 struct window_copy_mode_data
*data
= wme
->data
;
4487 data
->selx
= data
->cx
;
4488 data
->sely
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4490 data
->endselx
= data
->selx
;
4491 data
->endsely
= data
->sely
;
4493 data
->cursordrag
= CURSORDRAG_ENDSEL
;
4495 window_copy_set_selection(wme
, 1, 0);
4499 window_copy_adjust_selection(struct window_mode_entry
*wme
, u_int
*selx
,
4502 struct window_copy_mode_data
*data
= wme
->data
;
4503 struct screen
*s
= &data
->screen
;
4510 ty
= screen_hsize(data
->backing
) - data
->oy
;
4512 relpos
= WINDOW_COPY_REL_POS_ABOVE
;
4513 if (!data
->rectflag
)
4516 } else if (sy
> ty
+ screen_size_y(s
) - 1) {
4517 relpos
= WINDOW_COPY_REL_POS_BELOW
;
4518 if (!data
->rectflag
)
4519 sx
= screen_size_x(s
) - 1;
4520 sy
= screen_size_y(s
) - 1;
4522 relpos
= WINDOW_COPY_REL_POS_ON_SCREEN
;
4532 window_copy_update_selection(struct window_mode_entry
*wme
, int may_redraw
,
4535 struct window_copy_mode_data
*data
= wme
->data
;
4536 struct screen
*s
= &data
->screen
;
4538 if (s
->sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
)
4540 return (window_copy_set_selection(wme
, may_redraw
, no_reset
));
4544 window_copy_set_selection(struct window_mode_entry
*wme
, int may_redraw
,
4547 struct window_pane
*wp
= wme
->wp
;
4548 struct window_copy_mode_data
*data
= wme
->data
;
4549 struct screen
*s
= &data
->screen
;
4550 struct options
*oo
= wp
->window
->options
;
4551 struct grid_cell gc
;
4552 u_int sx
, sy
, cy
, endsx
, endsy
;
4553 int startrelpos
, endrelpos
;
4555 window_copy_synchronize_cursor(wme
, no_reset
);
4557 /* Adjust the selection. */
4560 startrelpos
= window_copy_adjust_selection(wme
, &sx
, &sy
);
4562 /* Adjust the end of selection. */
4563 endsx
= data
->endselx
;
4564 endsy
= data
->endsely
;
4565 endrelpos
= window_copy_adjust_selection(wme
, &endsx
, &endsy
);
4567 /* Selection is outside of the current screen */
4568 if (startrelpos
== endrelpos
&&
4569 startrelpos
!= WINDOW_COPY_REL_POS_ON_SCREEN
) {
4570 screen_hide_selection(s
);
4574 /* Set colours and selection. */
4575 style_apply(&gc
, oo
, "mode-style", NULL
);
4576 gc
.flags
|= GRID_FLAG_NOPALETTE
;
4577 screen_set_selection(s
, sx
, sy
, endsx
, endsy
, data
->rectflag
,
4578 data
->modekeys
, &gc
);
4580 if (data
->rectflag
&& may_redraw
) {
4582 * Can't rely on the caller to redraw the right lines for
4583 * rectangle selection - find the highest line and the number
4584 * of lines, and redraw just past that in both directions
4587 if (data
->cursordrag
== CURSORDRAG_ENDSEL
) {
4589 window_copy_redraw_lines(wme
, sy
, cy
- sy
+ 1);
4591 window_copy_redraw_lines(wme
, cy
, sy
- cy
+ 1);
4594 window_copy_redraw_lines(wme
, endsy
,
4597 window_copy_redraw_lines(wme
, cy
,
4607 window_copy_get_selection(struct window_mode_entry
*wme
, size_t *len
)
4609 struct window_pane
*wp
= wme
->wp
;
4610 struct window_copy_mode_data
*data
= wme
->data
;
4611 struct screen
*s
= &data
->screen
;
4614 u_int i
, xx
, yy
, sx
, sy
, ex
, ey
, ey_last
;
4615 u_int firstsx
, lastex
, restex
, restsx
, selx
;
4618 if (data
->screen
.sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
) {
4619 buf
= window_copy_match_at_cursor(data
);
4633 * The selection extends from selx,sely to (adjusted) cx,cy on
4637 /* Find start and end. */
4640 if (yy
< data
->sely
|| (yy
== data
->sely
&& xx
< data
->selx
)) {
4642 ex
= data
->selx
; ey
= data
->sely
;
4644 sx
= data
->selx
; sy
= data
->sely
;
4648 /* Trim ex to end of line. */
4649 ey_last
= window_copy_find_length(wme
, ey
);
4654 * Deal with rectangle-copy if necessary; four situations: start of
4655 * first line (firstsx), end of last line (lastex), start (restsx) and
4656 * end (restex) of all other lines.
4658 xx
= screen_size_x(s
);
4661 * Behave according to mode-keys. If it is emacs, copy like emacs,
4662 * keeping the top-left-most character, and dropping the
4663 * bottom-right-most, regardless of copy direction. If it is vi, also
4664 * keep bottom-right-most character.
4666 keys
= options_get_number(wp
->window
->options
, "mode-keys");
4667 if (data
->rectflag
) {
4669 * Need to ignore the column with the cursor in it, which for
4670 * rectangular copy means knowing which side the cursor is on.
4672 if (data
->cursordrag
== CURSORDRAG_ENDSEL
)
4675 selx
= data
->endselx
;
4676 if (selx
< data
->cx
) {
4677 /* Selection start is on the left. */
4678 if (keys
== MODEKEY_EMACS
) {
4683 lastex
= data
->cx
+ 1;
4684 restex
= data
->cx
+ 1;
4689 /* Cursor is on the left. */
4696 if (keys
== MODEKEY_EMACS
)
4705 /* Copy the lines. */
4706 for (i
= sy
; i
<= ey
; i
++) {
4707 window_copy_copy_line(wme
, &buf
, &off
, i
,
4708 (i
== sy
? firstsx
: restsx
),
4709 (i
== ey
? lastex
: restex
));
4712 /* Don't bother if no data. */
4718 /* Remove final \n (unless at end in vi mode). */
4719 if (keys
== MODEKEY_EMACS
|| lastex
<= ey_last
) {
4720 if (~grid_get_line(data
->backing
->grid
, ey
)->flags
&
4721 GRID_LINE_WRAPPED
|| lastex
!= ey_last
)
4729 window_copy_copy_buffer(struct window_mode_entry
*wme
, const char *prefix
,
4730 void *buf
, size_t len
)
4732 struct window_pane
*wp
= wme
->wp
;
4733 struct screen_write_ctx ctx
;
4735 if (options_get_number(global_options
, "set-clipboard") != 0) {
4736 screen_write_start_pane(&ctx
, wp
, NULL
);
4737 screen_write_setselection(&ctx
, "", buf
, len
);
4738 screen_write_stop(&ctx
);
4739 notify_pane("pane-set-clipboard", wp
);
4742 paste_add(prefix
, buf
, len
);
4746 window_copy_pipe_run(struct window_mode_entry
*wme
, struct session
*s
,
4747 const char *cmd
, size_t *len
)
4752 buf
= window_copy_get_selection(wme
, len
);
4753 if (cmd
== NULL
|| *cmd
== '\0')
4754 cmd
= options_get_string(global_options
, "copy-command");
4755 if (cmd
!= NULL
&& *cmd
!= '\0') {
4756 job
= job_run(cmd
, 0, NULL
, NULL
, s
, NULL
, NULL
, NULL
, NULL
,
4757 NULL
, JOB_NOWAIT
, -1, -1);
4758 bufferevent_write(job_get_event(job
), buf
, *len
);
4764 window_copy_pipe(struct window_mode_entry
*wme
, struct session
*s
,
4769 window_copy_pipe_run(wme
, s
, cmd
, &len
);
4773 window_copy_copy_pipe(struct window_mode_entry
*wme
, struct session
*s
,
4774 const char *prefix
, const char *cmd
)
4779 buf
= window_copy_pipe_run(wme
, s
, cmd
, &len
);
4781 window_copy_copy_buffer(wme
, prefix
, buf
, len
);
4785 window_copy_copy_selection(struct window_mode_entry
*wme
, const char *prefix
)
4790 buf
= window_copy_get_selection(wme
, &len
);
4792 window_copy_copy_buffer(wme
, prefix
, buf
, len
);
4796 window_copy_append_selection(struct window_mode_entry
*wme
)
4798 struct window_pane
*wp
= wme
->wp
;
4800 struct paste_buffer
*pb
;
4801 const char *bufdata
, *bufname
= NULL
;
4802 size_t len
, bufsize
;
4803 struct screen_write_ctx ctx
;
4805 buf
= window_copy_get_selection(wme
, &len
);
4809 if (options_get_number(global_options
, "set-clipboard") != 0) {
4810 screen_write_start_pane(&ctx
, wp
, NULL
);
4811 screen_write_setselection(&ctx
, "", buf
, len
);
4812 screen_write_stop(&ctx
);
4813 notify_pane("pane-set-clipboard", wp
);
4816 pb
= paste_get_top(&bufname
);
4818 bufdata
= paste_buffer_data(pb
, &bufsize
);
4819 buf
= xrealloc(buf
, len
+ bufsize
);
4820 memmove(buf
+ bufsize
, buf
, len
);
4821 memcpy(buf
, bufdata
, bufsize
);
4824 if (paste_set(buf
, len
, bufname
, NULL
) != 0)
4829 window_copy_copy_line(struct window_mode_entry
*wme
, char **buf
, size_t *off
,
4830 u_int sy
, u_int sx
, u_int ex
)
4832 struct window_copy_mode_data
*data
= wme
->data
;
4833 struct grid
*gd
= data
->backing
->grid
;
4834 struct grid_cell gc
;
4835 struct grid_line
*gl
;
4836 struct utf8_data ud
;
4837 u_int i
, xx
, wrapped
= 0;
4844 * Work out if the line was wrapped at the screen edge and all of it is
4847 gl
= grid_get_line(gd
, sy
);
4848 if (gl
->flags
& GRID_LINE_WRAPPED
&& gl
->cellsize
<= gd
->sx
)
4851 /* If the line was wrapped, don't strip spaces (use the full length). */
4855 xx
= window_copy_find_length(wme
, sy
);
4862 for (i
= sx
; i
< ex
; i
++) {
4863 grid_get_cell(gd
, i
, sy
, &gc
);
4864 if (gc
.flags
& GRID_FLAG_PADDING
)
4866 utf8_copy(&ud
, &gc
.data
);
4867 if (ud
.size
== 1 && (gc
.attr
& GRID_ATTR_CHARSET
)) {
4868 s
= tty_acs_get(NULL
, ud
.data
[0]);
4869 if (s
!= NULL
&& strlen(s
) <= sizeof ud
.data
) {
4870 ud
.size
= strlen(s
);
4871 memcpy(ud
.data
, s
, ud
.size
);
4875 *buf
= xrealloc(*buf
, (*off
) + ud
.size
);
4876 memcpy(*buf
+ *off
, ud
.data
, ud
.size
);
4881 /* Only add a newline if the line wasn't wrapped. */
4882 if (!wrapped
|| ex
!= xx
) {
4883 *buf
= xrealloc(*buf
, (*off
) + 1);
4884 (*buf
)[(*off
)++] = '\n';
4889 window_copy_clear_selection(struct window_mode_entry
*wme
)
4891 struct window_copy_mode_data
*data
= wme
->data
;
4894 screen_clear_selection(&data
->screen
);
4896 data
->cursordrag
= CURSORDRAG_NONE
;
4897 data
->lineflag
= LINE_SEL_NONE
;
4898 data
->selflag
= SEL_CHAR
;
4900 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4901 px
= window_copy_find_length(wme
, py
);
4903 window_copy_update_cursor(wme
, px
, data
->cy
);
4907 window_copy_in_set(struct window_mode_entry
*wme
, u_int px
, u_int py
,
4910 struct window_copy_mode_data
*data
= wme
->data
;
4911 struct grid_cell gc
;
4913 grid_get_cell(data
->backing
->grid
, px
, py
, &gc
);
4914 if (gc
.flags
& GRID_FLAG_PADDING
)
4916 return (utf8_cstrhas(set
, &gc
.data
));
4920 window_copy_find_length(struct window_mode_entry
*wme
, u_int py
)
4922 struct window_copy_mode_data
*data
= wme
->data
;
4924 return (grid_line_length(data
->backing
->grid
, py
));
4928 window_copy_cursor_start_of_line(struct window_mode_entry
*wme
)
4930 struct window_copy_mode_data
*data
= wme
->data
;
4931 struct screen
*back_s
= data
->backing
;
4932 struct grid_reader gr
;
4933 u_int px
, py
, oldy
, hsize
;
4936 hsize
= screen_hsize(back_s
);
4937 py
= hsize
+ data
->cy
- data
->oy
;
4940 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4941 grid_reader_cursor_start_of_line(&gr
, 1);
4942 grid_reader_get_cursor(&gr
, &px
, &py
);
4943 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
4947 window_copy_cursor_back_to_indentation(struct window_mode_entry
*wme
)
4949 struct window_copy_mode_data
*data
= wme
->data
;
4950 struct screen
*back_s
= data
->backing
;
4951 struct grid_reader gr
;
4952 u_int px
, py
, oldy
, hsize
;
4955 hsize
= screen_hsize(back_s
);
4956 py
= hsize
+ data
->cy
- data
->oy
;
4959 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4960 grid_reader_cursor_back_to_indentation(&gr
);
4961 grid_reader_get_cursor(&gr
, &px
, &py
);
4962 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
4966 window_copy_cursor_end_of_line(struct window_mode_entry
*wme
)
4968 struct window_copy_mode_data
*data
= wme
->data
;
4969 struct screen
*back_s
= data
->backing
;
4970 struct grid_reader gr
;
4971 u_int px
, py
, oldy
, hsize
;
4974 hsize
= screen_hsize(back_s
);
4975 py
= hsize
+ data
->cy
- data
->oy
;
4978 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4979 if (data
->screen
.sel
!= NULL
&& data
->rectflag
)
4980 grid_reader_cursor_end_of_line(&gr
, 1, 1);
4982 grid_reader_cursor_end_of_line(&gr
, 1, 0);
4983 grid_reader_get_cursor(&gr
, &px
, &py
);
4984 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
4985 data
->oy
, oldy
, px
, py
, 0);
4989 window_copy_other_end(struct window_mode_entry
*wme
)
4991 struct window_copy_mode_data
*data
= wme
->data
;
4992 struct screen
*s
= &data
->screen
;
4993 u_int selx
, sely
, cy
, yy
, hsize
;
4995 if (s
->sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
)
4998 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
4999 data
->lineflag
= LINE_SEL_RIGHT_LEFT
;
5000 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
5001 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
5003 switch (data
->cursordrag
) {
5004 case CURSORDRAG_NONE
:
5005 case CURSORDRAG_SEL
:
5006 data
->cursordrag
= CURSORDRAG_ENDSEL
;
5008 case CURSORDRAG_ENDSEL
:
5009 data
->cursordrag
= CURSORDRAG_SEL
;
5013 selx
= data
->endselx
;
5014 sely
= data
->endsely
;
5015 if (data
->cursordrag
== CURSORDRAG_SEL
) {
5021 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5025 hsize
= screen_hsize(data
->backing
);
5026 if (sely
< hsize
- data
->oy
) { /* above */
5027 data
->oy
= hsize
- sely
;
5029 } else if (sely
> hsize
- data
->oy
+ screen_size_y(s
)) { /* below */
5030 data
->oy
= hsize
- sely
+ screen_size_y(s
) - 1;
5031 data
->cy
= screen_size_y(s
) - 1;
5033 data
->cy
= cy
+ sely
- yy
;
5035 window_copy_update_selection(wme
, 1, 1);
5036 window_copy_redraw_screen(wme
);
5040 window_copy_cursor_left(struct window_mode_entry
*wme
)
5042 struct window_copy_mode_data
*data
= wme
->data
;
5043 struct screen
*back_s
= data
->backing
;
5044 struct grid_reader gr
;
5045 u_int px
, py
, oldy
, hsize
;
5048 hsize
= screen_hsize(back_s
);
5049 py
= hsize
+ data
->cy
- data
->oy
;
5052 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5053 grid_reader_cursor_left(&gr
, 1);
5054 grid_reader_get_cursor(&gr
, &px
, &py
);
5055 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
5059 window_copy_cursor_right(struct window_mode_entry
*wme
, int all
)
5061 struct window_copy_mode_data
*data
= wme
->data
;
5062 struct screen
*back_s
= data
->backing
;
5063 struct grid_reader gr
;
5064 u_int px
, py
, oldy
, hsize
;
5067 hsize
= screen_hsize(back_s
);
5068 py
= hsize
+ data
->cy
- data
->oy
;
5071 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5072 grid_reader_cursor_right(&gr
, 1, all
);
5073 grid_reader_get_cursor(&gr
, &px
, &py
);
5074 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
5075 data
->oy
, oldy
, px
, py
, 0);
5079 window_copy_cursor_up(struct window_mode_entry
*wme
, int scroll_only
)
5081 struct window_copy_mode_data
*data
= wme
->data
;
5082 struct screen
*s
= &data
->screen
;
5083 u_int ox
, oy
, px
, py
;
5086 norectsel
= data
->screen
.sel
== NULL
|| !data
->rectflag
;
5087 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5088 ox
= window_copy_find_length(wme
, oy
);
5089 if (norectsel
&& data
->cx
!= ox
) {
5090 data
->lastcx
= data
->cx
;
5094 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
&& oy
== data
->sely
)
5095 window_copy_other_end(wme
);
5097 if (scroll_only
|| data
->cy
== 0) {
5099 data
->cx
= data
->lastcx
;
5100 window_copy_scroll_down(wme
, 1);
5102 if (data
->cy
== screen_size_y(s
) - 1)
5103 window_copy_redraw_lines(wme
, data
->cy
, 1);
5105 window_copy_redraw_lines(wme
, data
->cy
, 2);
5109 window_copy_update_cursor(wme
, data
->lastcx
,
5112 window_copy_update_cursor(wme
, data
->cx
, data
->cy
- 1);
5113 if (window_copy_update_selection(wme
, 1, 0)) {
5114 if (data
->cy
== screen_size_y(s
) - 1)
5115 window_copy_redraw_lines(wme
, data
->cy
, 1);
5117 window_copy_redraw_lines(wme
, data
->cy
, 2);
5122 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5123 px
= window_copy_find_length(wme
, py
);
5124 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
5127 window_copy_update_cursor(wme
, px
, data
->cy
);
5128 if (window_copy_update_selection(wme
, 1, 0))
5129 window_copy_redraw_lines(wme
, data
->cy
, 1);
5133 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
5135 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5137 px
= screen_size_x(data
->backing
);
5139 px
= window_copy_find_length(wme
, py
);
5140 window_copy_update_cursor(wme
, px
, data
->cy
);
5141 if (window_copy_update_selection(wme
, 1, 0))
5142 window_copy_redraw_lines(wme
, data
->cy
, 1);
5144 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
5146 window_copy_update_cursor(wme
, 0, data
->cy
);
5147 if (window_copy_update_selection(wme
, 1, 0))
5148 window_copy_redraw_lines(wme
, data
->cy
, 1);
5153 window_copy_cursor_down(struct window_mode_entry
*wme
, int scroll_only
)
5155 struct window_copy_mode_data
*data
= wme
->data
;
5156 struct screen
*s
= &data
->screen
;
5157 u_int ox
, oy
, px
, py
;
5160 norectsel
= data
->screen
.sel
== NULL
|| !data
->rectflag
;
5161 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5162 ox
= window_copy_find_length(wme
, oy
);
5163 if (norectsel
&& data
->cx
!= ox
) {
5164 data
->lastcx
= data
->cx
;
5168 if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
&& oy
== data
->endsely
)
5169 window_copy_other_end(wme
);
5171 if (scroll_only
|| data
->cy
== screen_size_y(s
) - 1) {
5173 data
->cx
= data
->lastcx
;
5174 window_copy_scroll_up(wme
, 1);
5175 if (scroll_only
&& data
->cy
> 0)
5176 window_copy_redraw_lines(wme
, data
->cy
- 1, 2);
5179 window_copy_update_cursor(wme
, data
->lastcx
,
5182 window_copy_update_cursor(wme
, data
->cx
, data
->cy
+ 1);
5183 if (window_copy_update_selection(wme
, 1, 0))
5184 window_copy_redraw_lines(wme
, data
->cy
- 1, 2);
5188 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5189 px
= window_copy_find_length(wme
, py
);
5190 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
5193 window_copy_update_cursor(wme
, px
, data
->cy
);
5194 if (window_copy_update_selection(wme
, 1, 0))
5195 window_copy_redraw_lines(wme
, data
->cy
, 1);
5199 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
5201 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5203 px
= screen_size_x(data
->backing
);
5205 px
= window_copy_find_length(wme
, py
);
5206 window_copy_update_cursor(wme
, px
, data
->cy
);
5207 if (window_copy_update_selection(wme
, 1, 0))
5208 window_copy_redraw_lines(wme
, data
->cy
, 1);
5210 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
5212 window_copy_update_cursor(wme
, 0, data
->cy
);
5213 if (window_copy_update_selection(wme
, 1, 0))
5214 window_copy_redraw_lines(wme
, data
->cy
, 1);
5219 window_copy_cursor_jump(struct window_mode_entry
*wme
)
5221 struct window_copy_mode_data
*data
= wme
->data
;
5222 struct screen
*back_s
= data
->backing
;
5223 struct grid_reader gr
;
5224 u_int px
, py
, oldy
, hsize
;
5227 hsize
= screen_hsize(back_s
);
5228 py
= hsize
+ data
->cy
- data
->oy
;
5231 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5232 if (grid_reader_cursor_jump(&gr
, data
->jumpchar
)) {
5233 grid_reader_get_cursor(&gr
, &px
, &py
);
5234 window_copy_acquire_cursor_down(wme
, hsize
,
5235 screen_size_y(back_s
), data
->oy
, oldy
, px
, py
, 0);
5240 window_copy_cursor_jump_back(struct window_mode_entry
*wme
)
5242 struct window_copy_mode_data
*data
= wme
->data
;
5243 struct screen
*back_s
= data
->backing
;
5244 struct grid_reader gr
;
5245 u_int px
, py
, oldy
, hsize
;
5248 hsize
= screen_hsize(back_s
);
5249 py
= hsize
+ data
->cy
- data
->oy
;
5252 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5253 grid_reader_cursor_left(&gr
, 0);
5254 if (grid_reader_cursor_jump_back(&gr
, data
->jumpchar
)) {
5255 grid_reader_get_cursor(&gr
, &px
, &py
);
5256 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
,
5262 window_copy_cursor_jump_to(struct window_mode_entry
*wme
)
5264 struct window_copy_mode_data
*data
= wme
->data
;
5265 struct screen
*back_s
= data
->backing
;
5266 struct grid_reader gr
;
5267 u_int px
, py
, oldy
, hsize
;
5270 hsize
= screen_hsize(back_s
);
5271 py
= hsize
+ data
->cy
- data
->oy
;
5274 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5275 if (grid_reader_cursor_jump(&gr
, data
->jumpchar
)) {
5276 grid_reader_cursor_left(&gr
, 1);
5277 grid_reader_get_cursor(&gr
, &px
, &py
);
5278 window_copy_acquire_cursor_down(wme
, hsize
,
5279 screen_size_y(back_s
), data
->oy
, oldy
, px
, py
, 0);
5284 window_copy_cursor_jump_to_back(struct window_mode_entry
*wme
)
5286 struct window_copy_mode_data
*data
= wme
->data
;
5287 struct screen
*back_s
= data
->backing
;
5288 struct grid_reader gr
;
5289 u_int px
, py
, oldy
, hsize
;
5292 hsize
= screen_hsize(back_s
);
5293 py
= hsize
+ data
->cy
- data
->oy
;
5296 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5297 grid_reader_cursor_left(&gr
, 0);
5298 grid_reader_cursor_left(&gr
, 0);
5299 if (grid_reader_cursor_jump_back(&gr
, data
->jumpchar
)) {
5300 grid_reader_cursor_right(&gr
, 1, 0);
5301 grid_reader_get_cursor(&gr
, &px
, &py
);
5302 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
,
5308 window_copy_cursor_next_word(struct window_mode_entry
*wme
,
5309 const char *separators
)
5311 struct window_copy_mode_data
*data
= wme
->data
;
5312 struct screen
*back_s
= data
->backing
;
5313 struct grid_reader gr
;
5314 u_int px
, py
, oldy
, hsize
;
5317 hsize
= screen_hsize(back_s
);
5318 py
= hsize
+ data
->cy
- data
->oy
;
5321 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5322 grid_reader_cursor_next_word(&gr
, separators
);
5323 grid_reader_get_cursor(&gr
, &px
, &py
);
5324 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
5325 data
->oy
, oldy
, px
, py
, 0);
5328 /* Compute the next place where a word ends. */
5330 window_copy_cursor_next_word_end_pos(struct window_mode_entry
*wme
,
5331 const char *separators
, u_int
*ppx
, u_int
*ppy
)
5333 struct window_pane
*wp
= wme
->wp
;
5334 struct window_copy_mode_data
*data
= wme
->data
;
5335 struct options
*oo
= wp
->window
->options
;
5336 struct screen
*back_s
= data
->backing
;
5337 struct grid_reader gr
;
5338 u_int px
, py
, hsize
;
5341 hsize
= screen_hsize(back_s
);
5342 py
= hsize
+ data
->cy
- data
->oy
;
5344 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5345 if (options_get_number(oo
, "mode-keys") == MODEKEY_VI
) {
5346 if (!grid_reader_in_set(&gr
, WHITESPACE
))
5347 grid_reader_cursor_right(&gr
, 0, 0);
5348 grid_reader_cursor_next_word_end(&gr
, separators
);
5349 grid_reader_cursor_left(&gr
, 1);
5351 grid_reader_cursor_next_word_end(&gr
, separators
);
5352 grid_reader_get_cursor(&gr
, &px
, &py
);
5357 /* Move to the next place where a word ends. */
5359 window_copy_cursor_next_word_end(struct window_mode_entry
*wme
,
5360 const char *separators
, int no_reset
)
5362 struct window_pane
*wp
= wme
->wp
;
5363 struct window_copy_mode_data
*data
= wme
->data
;
5364 struct options
*oo
= wp
->window
->options
;
5365 struct screen
*back_s
= data
->backing
;
5366 struct grid_reader gr
;
5367 u_int px
, py
, oldy
, hsize
;
5370 hsize
= screen_hsize(back_s
);
5371 py
= hsize
+ data
->cy
- data
->oy
;
5374 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5375 if (options_get_number(oo
, "mode-keys") == MODEKEY_VI
) {
5376 if (!grid_reader_in_set(&gr
, WHITESPACE
))
5377 grid_reader_cursor_right(&gr
, 0, 0);
5378 grid_reader_cursor_next_word_end(&gr
, separators
);
5379 grid_reader_cursor_left(&gr
, 1);
5381 grid_reader_cursor_next_word_end(&gr
, separators
);
5382 grid_reader_get_cursor(&gr
, &px
, &py
);
5383 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
5384 data
->oy
, oldy
, px
, py
, no_reset
);
5387 /* Compute the previous place where a word begins. */
5389 window_copy_cursor_previous_word_pos(struct window_mode_entry
*wme
,
5390 const char *separators
, u_int
*ppx
, u_int
*ppy
)
5392 struct window_copy_mode_data
*data
= wme
->data
;
5393 struct screen
*back_s
= data
->backing
;
5394 struct grid_reader gr
;
5395 u_int px
, py
, hsize
;
5398 hsize
= screen_hsize(back_s
);
5399 py
= hsize
+ data
->cy
- data
->oy
;
5401 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5402 grid_reader_cursor_previous_word(&gr
, separators
, /* already= */ 0,
5403 /* stop_at_eol= */ 1);
5404 grid_reader_get_cursor(&gr
, &px
, &py
);
5409 /* Move to the previous place where a word begins. */
5411 window_copy_cursor_previous_word(struct window_mode_entry
*wme
,
5412 const char *separators
, int already
)
5414 struct window_copy_mode_data
*data
= wme
->data
;
5415 struct window
*w
= wme
->wp
->window
;
5416 struct screen
*back_s
= data
->backing
;
5417 struct grid_reader gr
;
5418 u_int px
, py
, oldy
, hsize
;
5421 if (options_get_number(w
->options
, "mode-keys") == MODEKEY_EMACS
)
5427 hsize
= screen_hsize(back_s
);
5428 py
= hsize
+ data
->cy
- data
->oy
;
5431 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5432 grid_reader_cursor_previous_word(&gr
, separators
, already
, stop_at_eol
);
5433 grid_reader_get_cursor(&gr
, &px
, &py
);
5434 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
5438 window_copy_cursor_prompt(struct window_mode_entry
*wme
, int direction
,
5441 struct window_copy_mode_data
*data
= wme
->data
;
5442 struct screen
*s
= data
->backing
;
5443 struct grid
*gd
= s
->grid
;
5445 u_int line
= gd
->hsize
- data
->oy
+ data
->cy
;
5448 if (args
!= NULL
&& strcmp(args
, "-o") == 0)
5449 line_flag
= GRID_LINE_START_OUTPUT
;
5451 line_flag
= GRID_LINE_START_PROMPT
;
5453 if (direction
== 0) { /* up */
5458 end_line
= gd
->hsize
+ gd
->sy
- 1;
5461 if (line
== end_line
)
5464 if (line
== end_line
)
5468 if (grid_get_line(gd
, line
)->flags
& line_flag
)
5473 if (line
> gd
->hsize
) {
5474 data
->cy
= line
- gd
->hsize
;
5478 data
->oy
= gd
->hsize
- line
;
5481 window_copy_update_selection(wme
, 1, 0);
5482 window_copy_redraw_screen(wme
);
5486 window_copy_scroll_up(struct window_mode_entry
*wme
, u_int ny
)
5488 struct window_pane
*wp
= wme
->wp
;
5489 struct window_copy_mode_data
*data
= wme
->data
;
5490 struct screen
*s
= &data
->screen
;
5491 struct screen_write_ctx ctx
;
5499 if (data
->searchmark
!= NULL
&& !data
->timeout
)
5500 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
5501 window_copy_update_selection(wme
, 0, 0);
5503 screen_write_start_pane(&ctx
, wp
, NULL
);
5504 screen_write_cursormove(&ctx
, 0, 0, 0);
5505 screen_write_deleteline(&ctx
, ny
, 8);
5506 window_copy_write_lines(wme
, &ctx
, screen_size_y(s
) - ny
, ny
);
5507 window_copy_write_line(wme
, &ctx
, 0);
5508 if (screen_size_y(s
) > 1)
5509 window_copy_write_line(wme
, &ctx
, 1);
5510 if (screen_size_y(s
) > 3)
5511 window_copy_write_line(wme
, &ctx
, screen_size_y(s
) - 2);
5512 if (s
->sel
!= NULL
&& screen_size_y(s
) > ny
)
5513 window_copy_write_line(wme
, &ctx
, screen_size_y(s
) - ny
- 1);
5514 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
5515 screen_write_stop(&ctx
);
5519 window_copy_scroll_down(struct window_mode_entry
*wme
, u_int ny
)
5521 struct window_pane
*wp
= wme
->wp
;
5522 struct window_copy_mode_data
*data
= wme
->data
;
5523 struct screen
*s
= &data
->screen
;
5524 struct screen_write_ctx ctx
;
5526 if (ny
> screen_hsize(data
->backing
))
5529 if (data
->oy
> screen_hsize(data
->backing
) - ny
)
5530 ny
= screen_hsize(data
->backing
) - data
->oy
;
5535 if (data
->searchmark
!= NULL
&& !data
->timeout
)
5536 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
5537 window_copy_update_selection(wme
, 0, 0);
5539 screen_write_start_pane(&ctx
, wp
, NULL
);
5540 screen_write_cursormove(&ctx
, 0, 0, 0);
5541 screen_write_insertline(&ctx
, ny
, 8);
5542 window_copy_write_lines(wme
, &ctx
, 0, ny
);
5543 if (s
->sel
!= NULL
&& screen_size_y(s
) > ny
)
5544 window_copy_write_line(wme
, &ctx
, ny
);
5545 else if (ny
== 1) /* nuke position */
5546 window_copy_write_line(wme
, &ctx
, 1);
5547 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
5548 screen_write_stop(&ctx
);
5552 window_copy_rectangle_set(struct window_mode_entry
*wme
, int rectflag
)
5554 struct window_copy_mode_data
*data
= wme
->data
;
5557 data
->rectflag
= rectflag
;
5559 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5560 px
= window_copy_find_length(wme
, py
);
5562 window_copy_update_cursor(wme
, px
, data
->cy
);
5564 window_copy_update_selection(wme
, 1, 0);
5565 window_copy_redraw_screen(wme
);
5569 window_copy_move_mouse(struct mouse_event
*m
)
5571 struct window_pane
*wp
;
5572 struct window_mode_entry
*wme
;
5575 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5578 wme
= TAILQ_FIRST(&wp
->modes
);
5581 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5584 if (cmd_mouse_at(wp
, m
, &x
, &y
, 0) != 0)
5587 window_copy_update_cursor(wme
, x
, y
);
5591 window_copy_start_drag(struct client
*c
, struct mouse_event
*m
)
5593 struct window_pane
*wp
;
5594 struct window_mode_entry
*wme
;
5595 struct window_copy_mode_data
*data
;
5601 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5604 wme
= TAILQ_FIRST(&wp
->modes
);
5607 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5610 if (cmd_mouse_at(wp
, m
, &x
, &y
, 1) != 0)
5613 c
->tty
.mouse_drag_update
= window_copy_drag_update
;
5614 c
->tty
.mouse_drag_release
= window_copy_drag_release
;
5617 yg
= screen_hsize(data
->backing
) + y
- data
->oy
;
5618 if (x
< data
->selrx
|| x
> data
->endselrx
|| yg
!= data
->selry
)
5619 data
->selflag
= SEL_CHAR
;
5620 switch (data
->selflag
) {
5622 if (data
->separators
!= NULL
) {
5623 window_copy_update_cursor(wme
, x
, y
);
5624 window_copy_cursor_previous_word_pos(wme
,
5625 data
->separators
, &x
, &y
);
5626 y
-= screen_hsize(data
->backing
) - data
->oy
;
5628 window_copy_update_cursor(wme
, x
, y
);
5631 window_copy_update_cursor(wme
, 0, y
);
5634 window_copy_update_cursor(wme
, x
, y
);
5635 window_copy_start_selection(wme
);
5639 window_copy_redraw_screen(wme
);
5640 window_copy_drag_update(c
, m
);
5644 window_copy_drag_update(struct client
*c
, struct mouse_event
*m
)
5646 struct window_pane
*wp
;
5647 struct window_mode_entry
*wme
;
5648 struct window_copy_mode_data
*data
;
5649 u_int x
, y
, old_cx
, old_cy
;
5650 struct timeval tv
= {
5651 .tv_usec
= WINDOW_COPY_DRAG_REPEAT_TIME
5657 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5660 wme
= TAILQ_FIRST(&wp
->modes
);
5663 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5667 evtimer_del(&data
->dragtimer
);
5669 if (cmd_mouse_at(wp
, m
, &x
, &y
, 0) != 0)
5674 window_copy_update_cursor(wme
, x
, y
);
5675 if (window_copy_update_selection(wme
, 1, 0))
5676 window_copy_redraw_selection(wme
, old_cy
);
5677 if (old_cy
!= data
->cy
|| old_cx
== data
->cx
) {
5679 evtimer_add(&data
->dragtimer
, &tv
);
5680 window_copy_cursor_up(wme
, 1);
5681 } else if (y
== screen_size_y(&data
->screen
) - 1) {
5682 evtimer_add(&data
->dragtimer
, &tv
);
5683 window_copy_cursor_down(wme
, 1);
5689 window_copy_drag_release(struct client
*c
, struct mouse_event
*m
)
5691 struct window_pane
*wp
;
5692 struct window_mode_entry
*wme
;
5693 struct window_copy_mode_data
*data
;
5698 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5701 wme
= TAILQ_FIRST(&wp
->modes
);
5704 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5708 evtimer_del(&data
->dragtimer
);
5712 window_copy_jump_to_mark(struct window_mode_entry
*wme
)
5714 struct window_copy_mode_data
*data
= wme
->data
;
5718 tmy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5719 data
->cx
= data
->mx
;
5720 if (data
->my
< screen_hsize(data
->backing
)) {
5722 data
->oy
= screen_hsize(data
->backing
) - data
->my
;
5724 data
->cy
= data
->my
- screen_hsize(data
->backing
);
5730 window_copy_update_selection(wme
, 0, 0);
5731 window_copy_redraw_screen(wme
);
5734 /* Scroll up if the cursor went off the visible screen. */
5736 window_copy_acquire_cursor_up(struct window_mode_entry
*wme
, u_int hsize
,
5737 u_int oy
, u_int oldy
, u_int px
, u_int py
)
5739 u_int cy
, yy
, ny
, nd
;
5752 window_copy_cursor_up(wme
, 1);
5755 window_copy_update_cursor(wme
, px
, cy
);
5756 if (window_copy_update_selection(wme
, 1, 0))
5757 window_copy_redraw_lines(wme
, cy
, nd
);
5760 /* Scroll down if the cursor went off the visible screen. */
5762 window_copy_acquire_cursor_down(struct window_mode_entry
*wme
, u_int hsize
,
5763 u_int sy
, u_int oy
, u_int oldy
, u_int px
, u_int py
, int no_reset
)
5765 u_int cy
, yy
, ny
, nd
;
5767 cy
= py
- hsize
+ oy
;
5778 window_copy_cursor_down(wme
, 1);
5782 window_copy_update_cursor(wme
, px
, yy
);
5784 window_copy_update_cursor(wme
, px
, cy
);
5785 if (window_copy_update_selection(wme
, 1, no_reset
))
5786 window_copy_redraw_lines(wme
, oldy
, nd
);