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, int, int);
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 *,
103 static void window_copy_copy_selection(struct window_mode_entry
*,
104 const char *, int, int);
105 static void window_copy_append_selection(struct window_mode_entry
*);
106 static void window_copy_clear_selection(struct window_mode_entry
*);
107 static void window_copy_copy_line(struct window_mode_entry
*, char **,
108 size_t *, u_int
, u_int
, u_int
);
109 static int window_copy_in_set(struct window_mode_entry
*, u_int
, u_int
,
111 static u_int
window_copy_find_length(struct window_mode_entry
*, u_int
);
112 static void window_copy_cursor_start_of_line(struct window_mode_entry
*);
113 static void window_copy_cursor_back_to_indentation(
114 struct window_mode_entry
*);
115 static void window_copy_cursor_end_of_line(struct window_mode_entry
*);
116 static void window_copy_other_end(struct window_mode_entry
*);
117 static void window_copy_cursor_left(struct window_mode_entry
*);
118 static void window_copy_cursor_right(struct window_mode_entry
*, int);
119 static void window_copy_cursor_up(struct window_mode_entry
*, int);
120 static void window_copy_cursor_down(struct window_mode_entry
*, int);
121 static void window_copy_cursor_jump(struct window_mode_entry
*);
122 static void window_copy_cursor_jump_back(struct window_mode_entry
*);
123 static void window_copy_cursor_jump_to(struct window_mode_entry
*);
124 static void window_copy_cursor_jump_to_back(struct window_mode_entry
*);
125 static void window_copy_cursor_next_word(struct window_mode_entry
*,
127 static void window_copy_cursor_next_word_end_pos(struct window_mode_entry
*,
128 const char *, u_int
*, u_int
*);
129 static void window_copy_cursor_next_word_end(struct window_mode_entry
*,
131 static void window_copy_cursor_previous_word_pos(struct window_mode_entry
*,
132 const char *, u_int
*, u_int
*);
133 static void window_copy_cursor_previous_word(struct window_mode_entry
*,
135 static void window_copy_cursor_prompt(struct window_mode_entry
*, int,
137 static void window_copy_scroll_up(struct window_mode_entry
*, u_int
);
138 static void window_copy_scroll_down(struct window_mode_entry
*, u_int
);
139 static void window_copy_rectangle_set(struct window_mode_entry
*, int);
140 static void window_copy_move_mouse(struct mouse_event
*);
141 static void window_copy_drag_update(struct client
*, struct mouse_event
*);
142 static void window_copy_drag_release(struct client
*, struct mouse_event
*);
143 static void window_copy_jump_to_mark(struct window_mode_entry
*);
144 static void window_copy_acquire_cursor_up(struct window_mode_entry
*,
145 u_int
, u_int
, u_int
, u_int
, u_int
);
146 static void window_copy_acquire_cursor_down(struct window_mode_entry
*,
147 u_int
, u_int
, u_int
, u_int
, u_int
, u_int
, int);
149 const struct window_mode window_copy_mode
= {
152 .init
= window_copy_init
,
153 .free
= window_copy_free
,
154 .resize
= window_copy_resize
,
155 .key_table
= window_copy_key_table
,
156 .command
= window_copy_command
,
157 .formats
= window_copy_formats
,
160 const struct window_mode window_view_mode
= {
163 .init
= window_copy_view_init
,
164 .free
= window_copy_free
,
165 .resize
= window_copy_resize
,
166 .key_table
= window_copy_key_table
,
167 .command
= window_copy_command
,
168 .formats
= window_copy_formats
,
173 WINDOW_COPY_SEARCHUP
,
174 WINDOW_COPY_SEARCHDOWN
,
175 WINDOW_COPY_JUMPFORWARD
,
176 WINDOW_COPY_JUMPBACKWARD
,
177 WINDOW_COPY_JUMPTOFORWARD
,
178 WINDOW_COPY_JUMPTOBACKWARD
,
182 WINDOW_COPY_REL_POS_ABOVE
,
183 WINDOW_COPY_REL_POS_ON_SCREEN
,
184 WINDOW_COPY_REL_POS_BELOW
,
187 enum window_copy_cmd_action
{
188 WINDOW_COPY_CMD_NOTHING
,
189 WINDOW_COPY_CMD_REDRAW
,
190 WINDOW_COPY_CMD_CANCEL
,
193 enum window_copy_cmd_clear
{
194 WINDOW_COPY_CMD_CLEAR_ALWAYS
,
195 WINDOW_COPY_CMD_CLEAR_NEVER
,
196 WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
199 struct window_copy_cmd_state
{
200 struct window_mode_entry
*wme
;
203 struct mouse_event
*m
;
211 * Copy mode's visible screen (the "screen" field) is filled from one of two
212 * sources: the original contents of the pane (used when we actually enter via
213 * the "copy-mode" command, to copy the contents of the current pane), or else
214 * a series of lines containing the output from an output-writing tmux command
215 * (such as any of the "show-*" or "list-*" commands).
217 * In either case, the full content of the copy-mode grid is pointed at by the
218 * "backing" field, and is copied into "screen" as needed (that is, when
219 * scrolling occurs). When copy-mode is backed by a pane, backing points
220 * directly at that pane's screen structure (&wp->base); when backed by a list
221 * of output-lines from a command, it points at a newly-allocated screen
222 * structure (which is deallocated when the mode ends).
224 struct window_copy_mode_data
{
225 struct screen screen
;
227 struct screen
*backing
;
228 int backing_written
; /* backing display started */
229 struct screen
*writing
;
230 struct input_ctx
*ictx
;
232 int viewmode
; /* view mode entered */
234 u_int oy
; /* number of lines scrolled up */
236 u_int selx
; /* beginning of selection */
239 u_int endselx
; /* end of selection */
243 CURSORDRAG_NONE
, /* selection is independent of cursor */
244 CURSORDRAG_ENDSEL
, /* end is synchronized with cursor */
245 CURSORDRAG_SEL
, /* start is synchronized with cursor */
253 } lineflag
; /* line selection mode */
254 int rectflag
; /* in rectangle copy mode? */
255 int scroll_exit
; /* exit on scroll to end? */
256 int hide_position
; /* hide position marker */
259 SEL_CHAR
, /* select one char at a time */
260 SEL_WORD
, /* select one word at a time */
261 SEL_LINE
, /* select one line at a time */
264 const char *separators
; /* word separators */
266 u_int dx
; /* drag start position */
269 u_int selrx
; /* selection reset positions */
277 u_int lastcx
; /* position in last line w/ content */
278 u_int lastsx
; /* size of last line w/ content */
280 u_int mx
; /* mark position */
297 int timeout
; /* search has timed out */
298 #define WINDOW_COPY_SEARCH_TIMEOUT 10000
299 #define WINDOW_COPY_SEARCH_ALL_TIMEOUT 200
300 #define WINDOW_COPY_SEARCH_MAX_LINE 2000
303 struct utf8_data
*jumpchar
;
305 struct event dragtimer
;
306 #define WINDOW_COPY_DRAG_REPEAT_TIME 50000
310 window_copy_scroll_timer(__unused
int fd
, __unused
short events
, void *arg
)
312 struct window_mode_entry
*wme
= arg
;
313 struct window_pane
*wp
= wme
->wp
;
314 struct window_copy_mode_data
*data
= wme
->data
;
315 struct timeval tv
= {
316 .tv_usec
= WINDOW_COPY_DRAG_REPEAT_TIME
319 evtimer_del(&data
->dragtimer
);
321 if (TAILQ_FIRST(&wp
->modes
) != wme
)
325 evtimer_add(&data
->dragtimer
, &tv
);
326 window_copy_cursor_up(wme
, 1);
327 } else if (data
->cy
== screen_size_y(&data
->screen
) - 1) {
328 evtimer_add(&data
->dragtimer
, &tv
);
329 window_copy_cursor_down(wme
, 1);
333 static struct screen
*
334 window_copy_clone_screen(struct screen
*src
, struct screen
*hint
, u_int
*cx
,
338 const struct grid_line
*gl
;
342 dst
= xcalloc(1, sizeof *dst
);
344 sy
= screen_hsize(src
) + screen_size_y(src
);
346 while (sy
> screen_hsize(src
)) {
347 gl
= grid_peek_line(src
->grid
, sy
- 1);
348 if (gl
->cellused
!= 0)
353 log_debug("%s: target screen is %ux%u, source %ux%u", __func__
,
354 screen_size_x(src
), sy
, screen_size_x(hint
),
355 screen_hsize(src
) + screen_size_y(src
));
356 screen_init(dst
, screen_size_x(src
), sy
, screen_hlimit(src
));
359 * Ensure history is on for the backing grid so lines are not deleted
362 dst
->grid
->flags
|= GRID_HISTORY
;
363 grid_duplicate_lines(dst
->grid
, 0, src
->grid
, 0, sy
);
365 dst
->grid
->sy
= sy
- screen_hsize(src
);
366 dst
->grid
->hsize
= screen_hsize(src
);
367 dst
->grid
->hscrolled
= src
->grid
->hscrolled
;
368 if (src
->cy
> dst
->grid
->sy
- 1) {
370 dst
->cy
= dst
->grid
->sy
- 1;
376 if (cx
!= NULL
&& cy
!= NULL
) {
378 *cy
= screen_hsize(dst
) + dst
->cy
;
379 reflow
= (screen_size_x(hint
) != screen_size_x(dst
));
384 grid_wrap_position(dst
->grid
, *cx
, *cy
, &wx
, &wy
);
385 screen_resize_cursor(dst
, screen_size_x(hint
), screen_size_y(hint
), 1,
388 grid_unwrap_position(dst
->grid
, cx
, cy
, wx
, wy
);
393 static struct window_copy_mode_data
*
394 window_copy_common_init(struct window_mode_entry
*wme
)
396 struct window_pane
*wp
= wme
->wp
;
397 struct window_copy_mode_data
*data
;
398 struct screen
*base
= &wp
->base
;
400 wme
->data
= data
= xcalloc(1, sizeof *data
);
402 data
->cursordrag
= CURSORDRAG_NONE
;
403 data
->lineflag
= LINE_SEL_NONE
;
404 data
->selflag
= SEL_CHAR
;
406 if (wp
->searchstr
!= NULL
) {
407 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
408 data
->searchregex
= wp
->searchregex
;
409 data
->searchstr
= xstrdup(wp
->searchstr
);
411 data
->searchtype
= WINDOW_COPY_OFF
;
412 data
->searchregex
= 0;
413 data
->searchstr
= NULL
;
415 data
->searchx
= data
->searchy
= data
->searcho
= -1;
418 data
->jumptype
= WINDOW_COPY_OFF
;
419 data
->jumpchar
= NULL
;
421 screen_init(&data
->screen
, screen_size_x(base
), screen_size_y(base
), 0);
422 screen_set_default_cursor(&data
->screen
, global_w_options
);
423 data
->modekeys
= options_get_number(wp
->window
->options
, "mode-keys");
425 evtimer_set(&data
->dragtimer
, window_copy_scroll_timer
, wme
);
430 static struct screen
*
431 window_copy_init(struct window_mode_entry
*wme
,
432 __unused
struct cmd_find_state
*fs
, struct args
*args
)
434 struct window_pane
*wp
= wme
->swp
;
435 struct window_copy_mode_data
*data
;
436 struct screen
*base
= &wp
->base
;
437 struct screen_write_ctx ctx
;
440 data
= window_copy_common_init(wme
);
441 data
->backing
= window_copy_clone_screen(base
, &data
->screen
, &cx
, &cy
,
442 wme
->swp
!= wme
->wp
);
445 if (cy
< screen_hsize(data
->backing
)) {
447 data
->oy
= screen_hsize(data
->backing
) - cy
;
449 data
->cy
= cy
- screen_hsize(data
->backing
);
453 data
->scroll_exit
= args_has(args
, 'e');
454 data
->hide_position
= args_has(args
, 'H');
456 if (base
->hyperlinks
!= NULL
)
457 data
->screen
.hyperlinks
= hyperlinks_copy(base
->hyperlinks
);
458 data
->screen
.cx
= data
->cx
;
459 data
->screen
.cy
= data
->cy
;
461 data
->my
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
464 screen_write_start(&ctx
, &data
->screen
);
465 for (i
= 0; i
< screen_size_y(&data
->screen
); i
++)
466 window_copy_write_line(wme
, &ctx
, i
);
467 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
468 screen_write_stop(&ctx
);
470 return (&data
->screen
);
473 static struct screen
*
474 window_copy_view_init(struct window_mode_entry
*wme
,
475 __unused
struct cmd_find_state
*fs
, __unused
struct args
*args
)
477 struct window_pane
*wp
= wme
->wp
;
478 struct window_copy_mode_data
*data
;
479 struct screen
*base
= &wp
->base
;
480 u_int sx
= screen_size_x(base
);
482 data
= window_copy_common_init(wme
);
485 data
->backing
= xmalloc(sizeof *data
->backing
);
486 screen_init(data
->backing
, sx
, screen_size_y(base
), UINT_MAX
);
487 data
->writing
= xmalloc(sizeof *data
->writing
);
488 screen_init(data
->writing
, sx
, screen_size_y(base
), 0);
489 data
->ictx
= input_init(NULL
, NULL
, NULL
);
491 data
->my
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
494 return (&data
->screen
);
498 window_copy_free(struct window_mode_entry
*wme
)
500 struct window_copy_mode_data
*data
= wme
->data
;
502 evtimer_del(&data
->dragtimer
);
504 free(data
->searchmark
);
505 free(data
->searchstr
);
506 free(data
->jumpchar
);
508 if (data
->writing
!= NULL
) {
509 screen_free(data
->writing
);
512 if (data
->ictx
!= NULL
)
513 input_free(data
->ictx
);
514 screen_free(data
->backing
);
517 screen_free(&data
->screen
);
522 window_copy_add(struct window_pane
*wp
, int parse
, const char *fmt
, ...)
527 window_copy_vadd(wp
, parse
, fmt
, ap
);
532 window_copy_init_ctx_cb(__unused
struct screen_write_ctx
*ctx
,
533 struct tty_ctx
*ttyctx
)
535 memcpy(&ttyctx
->defaults
, &grid_default_cell
, sizeof ttyctx
->defaults
);
536 ttyctx
->palette
= NULL
;
537 ttyctx
->redraw_cb
= NULL
;
538 ttyctx
->set_client_cb
= NULL
;
543 window_copy_vadd(struct window_pane
*wp
, int parse
, const char *fmt
, va_list ap
)
545 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
546 struct window_copy_mode_data
*data
= wme
->data
;
547 struct screen
*backing
= data
->backing
;
548 struct screen
*writing
= data
->writing
;
549 struct screen_write_ctx writing_ctx
, backing_ctx
, ctx
;
551 u_int old_hsize
, old_cy
;
552 u_int sx
= screen_size_x(backing
);
556 vasprintf(&text
, fmt
, ap
);
557 screen_write_start(&writing_ctx
, writing
);
558 screen_write_reset(&writing_ctx
);
559 input_parse_screen(data
->ictx
, writing
, window_copy_init_ctx_cb
,
560 data
, text
, strlen(text
));
564 old_hsize
= screen_hsize(data
->backing
);
565 screen_write_start(&backing_ctx
, backing
);
566 if (data
->backing_written
) {
568 * On the second or later line, do a CRLF before writing
569 * (so it's on a new line).
571 screen_write_carriagereturn(&backing_ctx
);
572 screen_write_linefeed(&backing_ctx
, 0, 8);
574 data
->backing_written
= 1;
575 old_cy
= backing
->cy
;
577 screen_write_fast_copy(&backing_ctx
, writing
, 0, 0, sx
, 1);
579 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
580 screen_write_vnputs(&backing_ctx
, 0, &gc
, fmt
, ap
);
582 screen_write_stop(&backing_ctx
);
584 data
->oy
+= screen_hsize(data
->backing
) - old_hsize
;
586 screen_write_start_pane(&ctx
, wp
, &data
->screen
);
589 * If the history has changed, draw the top line.
590 * (If there's any history at all, it has changed.)
592 if (screen_hsize(data
->backing
))
593 window_copy_redraw_lines(wme
, 0, 1);
595 /* Write the new lines. */
596 window_copy_redraw_lines(wme
, old_cy
, backing
->cy
- old_cy
+ 1);
598 screen_write_stop(&ctx
);
602 window_copy_pageup(struct window_pane
*wp
, int half_page
)
604 window_copy_pageup1(TAILQ_FIRST(&wp
->modes
), half_page
);
608 window_copy_pageup1(struct window_mode_entry
*wme
, int half_page
)
610 struct window_copy_mode_data
*data
= wme
->data
;
611 struct screen
*s
= &data
->screen
;
612 u_int n
, ox
, oy
, px
, py
;
614 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
615 ox
= window_copy_find_length(wme
, oy
);
617 if (data
->cx
!= ox
) {
618 data
->lastcx
= data
->cx
;
621 data
->cx
= data
->lastcx
;
624 if (screen_size_y(s
) > 2) {
626 n
= screen_size_y(s
) / 2;
628 n
= screen_size_y(s
) - 2;
631 if (data
->oy
+ n
> screen_hsize(data
->backing
)) {
632 data
->oy
= screen_hsize(data
->backing
);
640 if (data
->screen
.sel
== NULL
|| !data
->rectflag
) {
641 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
642 px
= window_copy_find_length(wme
, py
);
643 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
645 window_copy_cursor_end_of_line(wme
);
648 if (data
->searchmark
!= NULL
&& !data
->timeout
)
649 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
650 window_copy_update_selection(wme
, 1, 0);
651 window_copy_redraw_screen(wme
);
655 window_copy_pagedown(struct window_pane
*wp
, int half_page
, int scroll_exit
)
657 if (window_copy_pagedown1(TAILQ_FIRST(&wp
->modes
), half_page
,
659 window_pane_reset_mode(wp
);
665 window_copy_pagedown1(struct window_mode_entry
*wme
, int half_page
,
668 struct window_copy_mode_data
*data
= wme
->data
;
669 struct screen
*s
= &data
->screen
;
670 u_int n
, ox
, oy
, px
, py
;
672 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
673 ox
= window_copy_find_length(wme
, oy
);
675 if (data
->cx
!= ox
) {
676 data
->lastcx
= data
->cx
;
679 data
->cx
= data
->lastcx
;
682 if (screen_size_y(s
) > 2) {
684 n
= screen_size_y(s
) / 2;
686 n
= screen_size_y(s
) - 2;
691 if (data
->cy
+ (n
- data
->oy
) >= screen_size_y(data
->backing
))
692 data
->cy
= screen_size_y(data
->backing
) - 1;
694 data
->cy
+= n
- data
->oy
;
698 if (data
->screen
.sel
== NULL
|| !data
->rectflag
) {
699 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
700 px
= window_copy_find_length(wme
, py
);
701 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
703 window_copy_cursor_end_of_line(wme
);
706 if (scroll_exit
&& data
->oy
== 0)
708 if (data
->searchmark
!= NULL
&& !data
->timeout
)
709 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
710 window_copy_update_selection(wme
, 1, 0);
711 window_copy_redraw_screen(wme
);
716 window_copy_previous_paragraph(struct window_mode_entry
*wme
)
718 struct window_copy_mode_data
*data
= wme
->data
;
721 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
723 while (oy
> 0 && window_copy_find_length(wme
, oy
) == 0)
726 while (oy
> 0 && window_copy_find_length(wme
, oy
) > 0)
729 window_copy_scroll_to(wme
, 0, oy
, 0);
733 window_copy_next_paragraph(struct window_mode_entry
*wme
)
735 struct window_copy_mode_data
*data
= wme
->data
;
736 struct screen
*s
= &data
->screen
;
739 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
740 maxy
= screen_hsize(data
->backing
) + screen_size_y(s
) - 1;
742 while (oy
< maxy
&& window_copy_find_length(wme
, oy
) == 0)
745 while (oy
< maxy
&& window_copy_find_length(wme
, oy
) > 0)
748 ox
= window_copy_find_length(wme
, oy
);
749 window_copy_scroll_to(wme
, ox
, oy
, 0);
753 window_copy_get_word(struct window_pane
*wp
, u_int x
, u_int y
)
755 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
756 struct window_copy_mode_data
*data
= wme
->data
;
757 struct grid
*gd
= data
->screen
.grid
;
759 return (format_grid_word(gd
, x
, gd
->hsize
+ y
));
763 window_copy_get_line(struct window_pane
*wp
, u_int y
)
765 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
766 struct window_copy_mode_data
*data
= wme
->data
;
767 struct grid
*gd
= data
->screen
.grid
;
769 return (format_grid_line(gd
, gd
->hsize
+ y
));
773 window_copy_cursor_hyperlink_cb(struct format_tree
*ft
)
775 struct window_pane
*wp
= format_get_pane(ft
);
776 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
777 struct window_copy_mode_data
*data
= wme
->data
;
778 struct grid
*gd
= data
->screen
.grid
;
780 return (format_grid_hyperlink(gd
, data
->cx
, gd
->hsize
+ data
->cy
,
785 window_copy_cursor_word_cb(struct format_tree
*ft
)
787 struct window_pane
*wp
= format_get_pane(ft
);
788 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
789 struct window_copy_mode_data
*data
= wme
->data
;
791 return (window_copy_get_word(wp
, data
->cx
, data
->cy
));
795 window_copy_cursor_line_cb(struct format_tree
*ft
)
797 struct window_pane
*wp
= format_get_pane(ft
);
798 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
799 struct window_copy_mode_data
*data
= wme
->data
;
801 return (window_copy_get_line(wp
, data
->cy
));
805 window_copy_search_match_cb(struct format_tree
*ft
)
807 struct window_pane
*wp
= format_get_pane(ft
);
808 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
809 struct window_copy_mode_data
*data
= wme
->data
;
811 return (window_copy_match_at_cursor(data
));
815 window_copy_formats(struct window_mode_entry
*wme
, struct format_tree
*ft
)
817 struct window_copy_mode_data
*data
= wme
->data
;
818 u_int hsize
= screen_hsize(data
->backing
);
819 struct grid_line
*gl
;
821 gl
= grid_get_line(data
->backing
->grid
, hsize
- data
->oy
);
822 format_add(ft
, "top_line_time", "%llu", (unsigned long long)gl
->time
);
824 format_add(ft
, "scroll_position", "%d", data
->oy
);
825 format_add(ft
, "rectangle_toggle", "%d", data
->rectflag
);
827 format_add(ft
, "copy_cursor_x", "%d", data
->cx
);
828 format_add(ft
, "copy_cursor_y", "%d", data
->cy
);
830 if (data
->screen
.sel
!= NULL
) {
831 format_add(ft
, "selection_start_x", "%d", data
->selx
);
832 format_add(ft
, "selection_start_y", "%d", data
->sely
);
833 format_add(ft
, "selection_end_x", "%d", data
->endselx
);
834 format_add(ft
, "selection_end_y", "%d", data
->endsely
);
836 if (data
->cursordrag
!= CURSORDRAG_NONE
)
837 format_add(ft
, "selection_active", "1");
839 format_add(ft
, "selection_active", "0");
840 if (data
->endselx
!= data
->selx
|| data
->endsely
!= data
->sely
)
841 format_add(ft
, "selection_present", "1");
843 format_add(ft
, "selection_present", "0");
845 format_add(ft
, "selection_active", "0");
846 format_add(ft
, "selection_present", "0");
849 format_add(ft
, "search_present", "%d", data
->searchmark
!= NULL
);
850 format_add(ft
, "search_timed_out", "%d", data
->timeout
);
851 if (data
->searchcount
!= -1) {
852 format_add(ft
, "search_count", "%d", data
->searchcount
);
853 format_add(ft
, "search_count_partial", "%d", data
->searchmore
);
855 format_add_cb(ft
, "search_match", window_copy_search_match_cb
);
857 format_add_cb(ft
, "copy_cursor_word", window_copy_cursor_word_cb
);
858 format_add_cb(ft
, "copy_cursor_line", window_copy_cursor_line_cb
);
859 format_add_cb(ft
, "copy_cursor_hyperlink",
860 window_copy_cursor_hyperlink_cb
);
864 window_copy_size_changed(struct window_mode_entry
*wme
)
866 struct window_copy_mode_data
*data
= wme
->data
;
867 struct screen
*s
= &data
->screen
;
868 struct screen_write_ctx ctx
;
869 int search
= (data
->searchmark
!= NULL
);
871 window_copy_clear_selection(wme
);
872 window_copy_clear_marks(wme
);
874 screen_write_start(&ctx
, s
);
875 window_copy_write_lines(wme
, &ctx
, 0, screen_size_y(s
));
876 screen_write_stop(&ctx
);
878 if (search
&& !data
->timeout
)
879 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 0);
880 data
->searchx
= data
->cx
;
881 data
->searchy
= data
->cy
;
882 data
->searcho
= data
->oy
;
886 window_copy_resize(struct window_mode_entry
*wme
, u_int sx
, u_int sy
)
888 struct window_copy_mode_data
*data
= wme
->data
;
889 struct screen
*s
= &data
->screen
;
890 struct grid
*gd
= data
->backing
->grid
;
891 u_int cx
, cy
, wx
, wy
;
894 screen_resize(s
, sx
, sy
, 0);
896 cy
= gd
->hsize
+ data
->cy
- data
->oy
;
897 reflow
= (gd
->sx
!= sx
);
899 grid_wrap_position(gd
, cx
, cy
, &wx
, &wy
);
900 screen_resize_cursor(data
->backing
, sx
, sy
, 1, 0, 0);
902 grid_unwrap_position(gd
, &cx
, &cy
, wx
, wy
);
905 if (cy
< gd
->hsize
) {
907 data
->oy
= gd
->hsize
- cy
;
909 data
->cy
= cy
- gd
->hsize
;
913 window_copy_size_changed(wme
);
914 window_copy_redraw_screen(wme
);
918 window_copy_key_table(struct window_mode_entry
*wme
)
920 struct window_pane
*wp
= wme
->wp
;
922 if (options_get_number(wp
->window
->options
, "mode-keys") == MODEKEY_VI
)
923 return ("copy-mode-vi");
924 return ("copy-mode");
928 window_copy_expand_search_string(struct window_copy_cmd_state
*cs
)
930 struct window_mode_entry
*wme
= cs
->wme
;
931 struct window_copy_mode_data
*data
= wme
->data
;
932 const char *ss
= args_string(cs
->wargs
, 0);
935 if (ss
== NULL
|| *ss
== '\0')
938 if (args_has(cs
->args
, 'F')) {
939 expanded
= format_single(NULL
, ss
, NULL
, NULL
, NULL
, wme
->wp
);
940 if (*expanded
== '\0') {
944 free(data
->searchstr
);
945 data
->searchstr
= expanded
;
947 free(data
->searchstr
);
948 data
->searchstr
= xstrdup(ss
);
953 static enum window_copy_cmd_action
954 window_copy_cmd_append_selection(struct window_copy_cmd_state
*cs
)
956 struct window_mode_entry
*wme
= cs
->wme
;
957 struct session
*s
= cs
->s
;
960 window_copy_append_selection(wme
);
961 window_copy_clear_selection(wme
);
962 return (WINDOW_COPY_CMD_REDRAW
);
965 static enum window_copy_cmd_action
966 window_copy_cmd_append_selection_and_cancel(struct window_copy_cmd_state
*cs
)
968 struct window_mode_entry
*wme
= cs
->wme
;
969 struct session
*s
= cs
->s
;
972 window_copy_append_selection(wme
);
973 window_copy_clear_selection(wme
);
974 return (WINDOW_COPY_CMD_CANCEL
);
977 static enum window_copy_cmd_action
978 window_copy_cmd_back_to_indentation(struct window_copy_cmd_state
*cs
)
980 struct window_mode_entry
*wme
= cs
->wme
;
982 window_copy_cursor_back_to_indentation(wme
);
983 return (WINDOW_COPY_CMD_NOTHING
);
986 static enum window_copy_cmd_action
987 window_copy_cmd_begin_selection(struct window_copy_cmd_state
*cs
)
989 struct window_mode_entry
*wme
= cs
->wme
;
990 struct client
*c
= cs
->c
;
991 struct mouse_event
*m
= cs
->m
;
992 struct window_copy_mode_data
*data
= wme
->data
;
995 window_copy_start_drag(c
, m
);
996 return (WINDOW_COPY_CMD_NOTHING
);
999 data
->lineflag
= LINE_SEL_NONE
;
1000 data
->selflag
= SEL_CHAR
;
1001 window_copy_start_selection(wme
);
1002 return (WINDOW_COPY_CMD_REDRAW
);
1005 static enum window_copy_cmd_action
1006 window_copy_cmd_stop_selection(struct window_copy_cmd_state
*cs
)
1008 struct window_mode_entry
*wme
= cs
->wme
;
1009 struct window_copy_mode_data
*data
= wme
->data
;
1011 data
->cursordrag
= CURSORDRAG_NONE
;
1012 data
->lineflag
= LINE_SEL_NONE
;
1013 data
->selflag
= SEL_CHAR
;
1014 return (WINDOW_COPY_CMD_NOTHING
);
1017 static enum window_copy_cmd_action
1018 window_copy_cmd_bottom_line(struct window_copy_cmd_state
*cs
)
1020 struct window_mode_entry
*wme
= cs
->wme
;
1021 struct window_copy_mode_data
*data
= wme
->data
;
1024 data
->cy
= screen_size_y(&data
->screen
) - 1;
1026 window_copy_update_selection(wme
, 1, 0);
1027 return (WINDOW_COPY_CMD_REDRAW
);
1030 static enum window_copy_cmd_action
1031 window_copy_cmd_cancel(__unused
struct window_copy_cmd_state
*cs
)
1033 return (WINDOW_COPY_CMD_CANCEL
);
1036 static enum window_copy_cmd_action
1037 window_copy_cmd_clear_selection(struct window_copy_cmd_state
*cs
)
1039 struct window_mode_entry
*wme
= cs
->wme
;
1041 window_copy_clear_selection(wme
);
1042 return (WINDOW_COPY_CMD_REDRAW
);
1045 static enum window_copy_cmd_action
1046 window_copy_do_copy_end_of_line(struct window_copy_cmd_state
*cs
, int pipe
,
1049 struct window_mode_entry
*wme
= cs
->wme
;
1050 struct client
*c
= cs
->c
;
1051 struct session
*s
= cs
->s
;
1052 struct winlink
*wl
= cs
->wl
;
1053 struct window_pane
*wp
= wme
->wp
;
1054 u_int count
= args_count(cs
->wargs
);
1055 u_int np
= wme
->prefix
, ocx
, ocy
, ooy
;
1056 struct window_copy_mode_data
*data
= wme
->data
;
1057 char *prefix
= NULL
, *command
= NULL
;
1058 const char *arg0
= args_string(cs
->wargs
, 0);
1059 const char *arg1
= args_string(cs
->wargs
, 1);
1060 int set_paste
= !args_has(cs
->wargs
, 'P');
1061 int set_clip
= !args_has(cs
->wargs
, 'C');
1065 prefix
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1066 if (s
!= NULL
&& count
> 0 && *arg0
!= '\0')
1067 command
= format_single(NULL
, arg0
, c
, s
, wl
, wp
);
1070 prefix
= format_single(NULL
, arg0
, c
, s
, wl
, wp
);
1077 window_copy_start_selection(wme
);
1078 for (; np
> 1; np
--)
1079 window_copy_cursor_down(wme
, 0);
1080 window_copy_cursor_end_of_line(wme
);
1084 window_copy_copy_pipe(wme
, s
, prefix
, command
,
1085 set_paste
, set_clip
);
1087 window_copy_copy_selection(wme
, prefix
,
1088 set_paste
, set_clip
);
1093 return (WINDOW_COPY_CMD_CANCEL
);
1096 window_copy_clear_selection(wme
);
1104 return (WINDOW_COPY_CMD_REDRAW
);
1107 static enum window_copy_cmd_action
1108 window_copy_cmd_copy_end_of_line(struct window_copy_cmd_state
*cs
)
1110 return (window_copy_do_copy_end_of_line(cs
, 0, 0));
1113 static enum window_copy_cmd_action
1114 window_copy_cmd_copy_end_of_line_and_cancel(struct window_copy_cmd_state
*cs
)
1116 return (window_copy_do_copy_end_of_line(cs
, 0, 1));
1119 static enum window_copy_cmd_action
1120 window_copy_cmd_copy_pipe_end_of_line(struct window_copy_cmd_state
*cs
)
1122 return (window_copy_do_copy_end_of_line(cs
, 1, 0));
1125 static enum window_copy_cmd_action
1126 window_copy_cmd_copy_pipe_end_of_line_and_cancel(
1127 struct window_copy_cmd_state
*cs
)
1129 return (window_copy_do_copy_end_of_line(cs
, 1, 1));
1132 static enum window_copy_cmd_action
1133 window_copy_do_copy_line(struct window_copy_cmd_state
*cs
, int pipe
, int cancel
)
1135 struct window_mode_entry
*wme
= cs
->wme
;
1136 struct client
*c
= cs
->c
;
1137 struct session
*s
= cs
->s
;
1138 struct winlink
*wl
= cs
->wl
;
1139 struct window_pane
*wp
= wme
->wp
;
1140 struct window_copy_mode_data
*data
= wme
->data
;
1141 u_int count
= args_count(cs
->wargs
);
1142 u_int np
= wme
->prefix
, ocx
, ocy
, ooy
;
1143 char *prefix
= NULL
, *command
= NULL
;
1144 const char *arg0
= args_string(cs
->wargs
, 0);
1145 const char *arg1
= args_string(cs
->wargs
, 1);
1146 int set_paste
= !args_has(cs
->wargs
, 'P');
1147 int set_clip
= !args_has(cs
->wargs
, 'C');
1151 prefix
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
1152 if (s
!= NULL
&& count
> 0 && *arg0
!= '\0')
1153 command
= format_single(NULL
, arg0
, c
, s
, wl
, wp
);
1156 prefix
= format_single(NULL
, arg0
, c
, s
, wl
, wp
);
1163 data
->selflag
= SEL_CHAR
;
1164 window_copy_cursor_start_of_line(wme
);
1165 window_copy_start_selection(wme
);
1166 for (; np
> 1; np
--)
1167 window_copy_cursor_down(wme
, 0);
1168 window_copy_cursor_end_of_line(wme
);
1172 window_copy_copy_pipe(wme
, s
, prefix
, command
,
1173 set_paste
, set_clip
);
1175 window_copy_copy_selection(wme
, prefix
,
1176 set_paste
, set_clip
);
1181 return (WINDOW_COPY_CMD_CANCEL
);
1184 window_copy_clear_selection(wme
);
1192 return (WINDOW_COPY_CMD_REDRAW
);
1195 static enum window_copy_cmd_action
1196 window_copy_cmd_copy_line(struct window_copy_cmd_state
*cs
)
1198 return (window_copy_do_copy_line(cs
, 0, 0));
1201 static enum window_copy_cmd_action
1202 window_copy_cmd_copy_line_and_cancel(struct window_copy_cmd_state
*cs
)
1204 return (window_copy_do_copy_line(cs
, 0, 1));
1207 static enum window_copy_cmd_action
1208 window_copy_cmd_copy_pipe_line(struct window_copy_cmd_state
*cs
)
1210 return (window_copy_do_copy_line(cs
, 1, 0));
1213 static enum window_copy_cmd_action
1214 window_copy_cmd_copy_pipe_line_and_cancel(struct window_copy_cmd_state
*cs
)
1216 return (window_copy_do_copy_line(cs
, 1, 1));
1219 static enum window_copy_cmd_action
1220 window_copy_cmd_copy_selection_no_clear(struct window_copy_cmd_state
*cs
)
1222 struct window_mode_entry
*wme
= cs
->wme
;
1223 struct client
*c
= cs
->c
;
1224 struct session
*s
= cs
->s
;
1225 struct winlink
*wl
= cs
->wl
;
1226 struct window_pane
*wp
= wme
->wp
;
1227 char *prefix
= NULL
;
1228 const char *arg0
= args_string(cs
->wargs
, 0);
1229 int set_paste
= !args_has(cs
->wargs
, 'P');
1230 int set_clip
= !args_has(cs
->wargs
, 'C');
1233 prefix
= format_single(NULL
, arg0
, c
, s
, wl
, wp
);
1236 window_copy_copy_selection(wme
, prefix
, set_paste
, set_clip
);
1239 return (WINDOW_COPY_CMD_NOTHING
);
1242 static enum window_copy_cmd_action
1243 window_copy_cmd_copy_selection(struct window_copy_cmd_state
*cs
)
1245 struct window_mode_entry
*wme
= cs
->wme
;
1247 window_copy_cmd_copy_selection_no_clear(cs
);
1248 window_copy_clear_selection(wme
);
1249 return (WINDOW_COPY_CMD_REDRAW
);
1252 static enum window_copy_cmd_action
1253 window_copy_cmd_copy_selection_and_cancel(struct window_copy_cmd_state
*cs
)
1255 struct window_mode_entry
*wme
= cs
->wme
;
1257 window_copy_cmd_copy_selection_no_clear(cs
);
1258 window_copy_clear_selection(wme
);
1259 return (WINDOW_COPY_CMD_CANCEL
);
1262 static enum window_copy_cmd_action
1263 window_copy_cmd_cursor_down(struct window_copy_cmd_state
*cs
)
1265 struct window_mode_entry
*wme
= cs
->wme
;
1266 u_int np
= wme
->prefix
;
1268 for (; np
!= 0; np
--)
1269 window_copy_cursor_down(wme
, 0);
1270 return (WINDOW_COPY_CMD_NOTHING
);
1273 static enum window_copy_cmd_action
1274 window_copy_cmd_cursor_down_and_cancel(struct window_copy_cmd_state
*cs
)
1276 struct window_mode_entry
*wme
= cs
->wme
;
1277 struct window_copy_mode_data
*data
= wme
->data
;
1278 u_int np
= wme
->prefix
, cy
;
1281 for (; np
!= 0; np
--)
1282 window_copy_cursor_down(wme
, 0);
1283 if (cy
== data
->cy
&& data
->oy
== 0)
1284 return (WINDOW_COPY_CMD_CANCEL
);
1285 return (WINDOW_COPY_CMD_NOTHING
);
1288 static enum window_copy_cmd_action
1289 window_copy_cmd_cursor_left(struct window_copy_cmd_state
*cs
)
1291 struct window_mode_entry
*wme
= cs
->wme
;
1292 u_int np
= wme
->prefix
;
1294 for (; np
!= 0; np
--)
1295 window_copy_cursor_left(wme
);
1296 return (WINDOW_COPY_CMD_NOTHING
);
1299 static enum window_copy_cmd_action
1300 window_copy_cmd_cursor_right(struct window_copy_cmd_state
*cs
)
1302 struct window_mode_entry
*wme
= cs
->wme
;
1303 struct window_copy_mode_data
*data
= wme
->data
;
1304 u_int np
= wme
->prefix
;
1306 for (; np
!= 0; np
--) {
1307 window_copy_cursor_right(wme
, data
->screen
.sel
!= NULL
&&
1310 return (WINDOW_COPY_CMD_NOTHING
);
1313 /* Scroll line containing the cursor to the given position. */
1314 static enum window_copy_cmd_action
1315 window_copy_cmd_scroll_to(struct window_copy_cmd_state
*cs
, u_int to
)
1317 struct window_mode_entry
*wme
= cs
->wme
;
1318 struct window_copy_mode_data
*data
= wme
->data
;
1320 int scroll_up
; /* >0 up, <0 down */
1322 scroll_up
= data
->cy
- to
;
1323 delta
= abs(scroll_up
);
1324 oy
= screen_hsize(data
->backing
) - data
->oy
;
1327 * oy is the maximum scroll down amount, while data->oy is the maximum
1330 if (scroll_up
> 0 && data
->oy
>= delta
) {
1331 window_copy_scroll_up(wme
, delta
);
1333 } else if (scroll_up
< 0 && oy
>= delta
) {
1334 window_copy_scroll_down(wme
, delta
);
1338 window_copy_update_selection(wme
, 0, 0);
1339 return (WINDOW_COPY_CMD_REDRAW
);
1342 /* Scroll line containing the cursor to the bottom. */
1343 static enum window_copy_cmd_action
1344 window_copy_cmd_scroll_bottom(struct window_copy_cmd_state
*cs
)
1346 struct window_copy_mode_data
*data
= cs
->wme
->data
;
1349 bottom
= screen_size_y(&data
->screen
) - 1;
1350 return (window_copy_cmd_scroll_to(cs
, bottom
));
1353 /* Scroll line containing the cursor to the middle. */
1354 static enum window_copy_cmd_action
1355 window_copy_cmd_scroll_middle(struct window_copy_cmd_state
*cs
)
1357 struct window_copy_mode_data
*data
= cs
->wme
->data
;
1360 mid_value
= (screen_size_y(&data
->screen
) - 1) / 2;
1361 return (window_copy_cmd_scroll_to(cs
, mid_value
));
1364 /* Scroll line containing the cursor to the top. */
1365 static enum window_copy_cmd_action
1366 window_copy_cmd_scroll_top(struct window_copy_cmd_state
*cs
)
1368 return (window_copy_cmd_scroll_to(cs
, 0));
1371 static enum window_copy_cmd_action
1372 window_copy_cmd_cursor_up(struct window_copy_cmd_state
*cs
)
1374 struct window_mode_entry
*wme
= cs
->wme
;
1375 u_int np
= wme
->prefix
;
1377 for (; np
!= 0; np
--)
1378 window_copy_cursor_up(wme
, 0);
1379 return (WINDOW_COPY_CMD_NOTHING
);
1382 static enum window_copy_cmd_action
1383 window_copy_cmd_end_of_line(struct window_copy_cmd_state
*cs
)
1385 struct window_mode_entry
*wme
= cs
->wme
;
1387 window_copy_cursor_end_of_line(wme
);
1388 return (WINDOW_COPY_CMD_NOTHING
);
1391 static enum window_copy_cmd_action
1392 window_copy_cmd_halfpage_down(struct window_copy_cmd_state
*cs
)
1394 struct window_mode_entry
*wme
= cs
->wme
;
1395 struct window_copy_mode_data
*data
= wme
->data
;
1396 u_int np
= wme
->prefix
;
1398 for (; np
!= 0; np
--) {
1399 if (window_copy_pagedown1(wme
, 1, data
->scroll_exit
))
1400 return (WINDOW_COPY_CMD_CANCEL
);
1402 return (WINDOW_COPY_CMD_NOTHING
);
1405 static enum window_copy_cmd_action
1406 window_copy_cmd_halfpage_down_and_cancel(struct window_copy_cmd_state
*cs
)
1409 struct window_mode_entry
*wme
= cs
->wme
;
1410 u_int np
= wme
->prefix
;
1412 for (; np
!= 0; np
--) {
1413 if (window_copy_pagedown1(wme
, 1, 1))
1414 return (WINDOW_COPY_CMD_CANCEL
);
1416 return (WINDOW_COPY_CMD_NOTHING
);
1419 static enum window_copy_cmd_action
1420 window_copy_cmd_halfpage_up(struct window_copy_cmd_state
*cs
)
1422 struct window_mode_entry
*wme
= cs
->wme
;
1423 u_int np
= wme
->prefix
;
1425 for (; np
!= 0; np
--)
1426 window_copy_pageup1(wme
, 1);
1427 return (WINDOW_COPY_CMD_NOTHING
);
1430 static enum window_copy_cmd_action
1431 window_copy_cmd_toggle_position(struct window_copy_cmd_state
*cs
)
1433 struct window_mode_entry
*wme
= cs
->wme
;
1434 struct window_copy_mode_data
*data
= wme
->data
;
1436 data
->hide_position
= !data
->hide_position
;
1437 return (WINDOW_COPY_CMD_REDRAW
);
1440 static enum window_copy_cmd_action
1441 window_copy_cmd_history_bottom(struct window_copy_cmd_state
*cs
)
1443 struct window_mode_entry
*wme
= cs
->wme
;
1444 struct window_copy_mode_data
*data
= wme
->data
;
1445 struct screen
*s
= data
->backing
;
1448 oy
= screen_hsize(s
) + data
->cy
- data
->oy
;
1449 if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
&& oy
== data
->endsely
)
1450 window_copy_other_end(wme
);
1452 data
->cy
= screen_size_y(&data
->screen
) - 1;
1453 data
->cx
= window_copy_find_length(wme
, screen_hsize(s
) + data
->cy
);
1456 if (data
->searchmark
!= NULL
&& !data
->timeout
)
1457 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
1458 window_copy_update_selection(wme
, 1, 0);
1459 return (WINDOW_COPY_CMD_REDRAW
);
1462 static enum window_copy_cmd_action
1463 window_copy_cmd_history_top(struct window_copy_cmd_state
*cs
)
1465 struct window_mode_entry
*wme
= cs
->wme
;
1466 struct window_copy_mode_data
*data
= wme
->data
;
1469 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
1470 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
&& oy
== data
->sely
)
1471 window_copy_other_end(wme
);
1475 data
->oy
= screen_hsize(data
->backing
);
1477 if (data
->searchmark
!= NULL
&& !data
->timeout
)
1478 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
1479 window_copy_update_selection(wme
, 1, 0);
1480 return (WINDOW_COPY_CMD_REDRAW
);
1483 static enum window_copy_cmd_action
1484 window_copy_cmd_jump_again(struct window_copy_cmd_state
*cs
)
1486 struct window_mode_entry
*wme
= cs
->wme
;
1487 struct window_copy_mode_data
*data
= wme
->data
;
1488 u_int np
= wme
->prefix
;
1490 switch (data
->jumptype
) {
1491 case WINDOW_COPY_JUMPFORWARD
:
1492 for (; np
!= 0; np
--)
1493 window_copy_cursor_jump(wme
);
1495 case WINDOW_COPY_JUMPBACKWARD
:
1496 for (; np
!= 0; np
--)
1497 window_copy_cursor_jump_back(wme
);
1499 case WINDOW_COPY_JUMPTOFORWARD
:
1500 for (; np
!= 0; np
--)
1501 window_copy_cursor_jump_to(wme
);
1503 case WINDOW_COPY_JUMPTOBACKWARD
:
1504 for (; np
!= 0; np
--)
1505 window_copy_cursor_jump_to_back(wme
);
1508 return (WINDOW_COPY_CMD_NOTHING
);
1511 static enum window_copy_cmd_action
1512 window_copy_cmd_jump_reverse(struct window_copy_cmd_state
*cs
)
1514 struct window_mode_entry
*wme
= cs
->wme
;
1515 struct window_copy_mode_data
*data
= wme
->data
;
1516 u_int np
= wme
->prefix
;
1518 switch (data
->jumptype
) {
1519 case WINDOW_COPY_JUMPFORWARD
:
1520 for (; np
!= 0; np
--)
1521 window_copy_cursor_jump_back(wme
);
1523 case WINDOW_COPY_JUMPBACKWARD
:
1524 for (; np
!= 0; np
--)
1525 window_copy_cursor_jump(wme
);
1527 case WINDOW_COPY_JUMPTOFORWARD
:
1528 for (; np
!= 0; np
--)
1529 window_copy_cursor_jump_to_back(wme
);
1531 case WINDOW_COPY_JUMPTOBACKWARD
:
1532 for (; np
!= 0; np
--)
1533 window_copy_cursor_jump_to(wme
);
1536 return (WINDOW_COPY_CMD_NOTHING
);
1539 static enum window_copy_cmd_action
1540 window_copy_cmd_middle_line(struct window_copy_cmd_state
*cs
)
1542 struct window_mode_entry
*wme
= cs
->wme
;
1543 struct window_copy_mode_data
*data
= wme
->data
;
1546 data
->cy
= (screen_size_y(&data
->screen
) - 1) / 2;
1548 window_copy_update_selection(wme
, 1, 0);
1549 return (WINDOW_COPY_CMD_REDRAW
);
1552 static enum window_copy_cmd_action
1553 window_copy_cmd_previous_matching_bracket(struct window_copy_cmd_state
*cs
)
1555 struct window_mode_entry
*wme
= cs
->wme
;
1556 u_int np
= wme
->prefix
;
1557 struct window_copy_mode_data
*data
= wme
->data
;
1558 struct screen
*s
= data
->backing
;
1559 char open
[] = "{[(", close
[] = "}])";
1560 char tried
, found
, start
, *cp
;
1561 u_int px
, py
, xx
, n
;
1562 struct grid_cell gc
;
1565 for (; np
!= 0; np
--) {
1566 /* Get cursor position and line length. */
1568 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1569 xx
= window_copy_find_length(wme
, py
);
1574 * Get the current character. If not on a bracket, try the
1575 * previous. If still not, then behave like previous-word.
1579 grid_get_cell(s
->grid
, px
, py
, &gc
);
1580 if (gc
.data
.size
!= 1 || (gc
.flags
& GRID_FLAG_PADDING
))
1583 found
= *gc
.data
.data
;
1584 cp
= strchr(close
, found
);
1587 if (data
->modekeys
== MODEKEY_EMACS
) {
1588 if (!tried
&& px
> 0) {
1593 window_copy_cursor_previous_word(wme
, close
, 1);
1597 start
= open
[cp
- close
];
1599 /* Walk backward until the matching bracket is reached. */
1610 xx
= window_copy_find_length(wme
, py
);
1611 } while (xx
== 0 && py
> 0);
1612 if (xx
== 0 && py
== 0) {
1620 grid_get_cell(s
->grid
, px
, py
, &gc
);
1621 if (gc
.data
.size
== 1 &&
1622 (~gc
.flags
& GRID_FLAG_PADDING
)) {
1623 if (*gc
.data
.data
== found
)
1625 else if (*gc
.data
.data
== start
)
1630 /* Move the cursor to the found location if any. */
1632 window_copy_scroll_to(wme
, px
, py
, 0);
1635 return (WINDOW_COPY_CMD_NOTHING
);
1638 static enum window_copy_cmd_action
1639 window_copy_cmd_next_matching_bracket(struct window_copy_cmd_state
*cs
)
1641 struct window_mode_entry
*wme
= cs
->wme
;
1642 u_int np
= wme
->prefix
;
1643 struct window_copy_mode_data
*data
= wme
->data
;
1644 struct screen
*s
= data
->backing
;
1645 char open
[] = "{[(", close
[] = "}])";
1646 char tried
, found
, end
, *cp
;
1647 u_int px
, py
, xx
, yy
, sx
, sy
, n
;
1648 struct grid_cell gc
;
1650 struct grid_line
*gl
;
1652 for (; np
!= 0; np
--) {
1653 /* Get cursor position and line length. */
1655 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1656 xx
= window_copy_find_length(wme
, py
);
1657 yy
= screen_hsize(s
) + screen_size_y(s
) - 1;
1662 * Get the current character. If not on a bracket, try the
1663 * next. If still not, then behave like next-word.
1667 grid_get_cell(s
->grid
, px
, py
, &gc
);
1668 if (gc
.data
.size
!= 1 || (gc
.flags
& GRID_FLAG_PADDING
))
1671 found
= *gc
.data
.data
;
1674 * In vi mode, attempt to move to previous bracket if a
1675 * closing bracket is found first. If this fails,
1676 * return to the original cursor position.
1678 cp
= strchr(close
, found
);
1679 if (cp
!= NULL
&& data
->modekeys
== MODEKEY_VI
) {
1681 sy
= screen_hsize(s
) + data
->cy
- data
->oy
;
1683 window_copy_scroll_to(wme
, px
, py
, 0);
1684 window_copy_cmd_previous_matching_bracket(cs
);
1687 py
= screen_hsize(s
) + data
->cy
- data
->oy
;
1688 grid_get_cell(s
->grid
, px
, py
, &gc
);
1689 if (gc
.data
.size
== 1 &&
1690 (~gc
.flags
& GRID_FLAG_PADDING
) &&
1691 strchr(close
, *gc
.data
.data
) != NULL
)
1692 window_copy_scroll_to(wme
, sx
, sy
, 0);
1696 cp
= strchr(open
, found
);
1699 if (data
->modekeys
== MODEKEY_EMACS
) {
1700 if (!tried
&& px
<= xx
) {
1705 window_copy_cursor_next_word_end(wme
, open
, 0);
1708 /* For vi, continue searching for bracket until EOL. */
1712 gl
= grid_get_line(s
->grid
, py
);
1713 if (~gl
->flags
& GRID_LINE_WRAPPED
)
1715 if (gl
->cellsize
> s
->grid
->sx
)
1719 xx
= window_copy_find_length(wme
, py
);
1724 end
= close
[cp
- open
];
1726 /* Walk forward until the matching bracket is reached. */
1737 xx
= window_copy_find_length(wme
, py
);
1741 grid_get_cell(s
->grid
, px
, py
, &gc
);
1742 if (gc
.data
.size
== 1 &&
1743 (~gc
.flags
& GRID_FLAG_PADDING
)) {
1744 if (*gc
.data
.data
== found
)
1746 else if (*gc
.data
.data
== end
)
1751 /* Move the cursor to the found location if any. */
1753 window_copy_scroll_to(wme
, px
, py
, 0);
1756 return (WINDOW_COPY_CMD_NOTHING
);
1759 static enum window_copy_cmd_action
1760 window_copy_cmd_next_paragraph(struct window_copy_cmd_state
*cs
)
1762 struct window_mode_entry
*wme
= cs
->wme
;
1763 u_int np
= wme
->prefix
;
1765 for (; np
!= 0; np
--)
1766 window_copy_next_paragraph(wme
);
1767 return (WINDOW_COPY_CMD_NOTHING
);
1770 static enum window_copy_cmd_action
1771 window_copy_cmd_next_space(struct window_copy_cmd_state
*cs
)
1773 struct window_mode_entry
*wme
= cs
->wme
;
1774 u_int np
= wme
->prefix
;
1776 for (; np
!= 0; np
--)
1777 window_copy_cursor_next_word(wme
, "");
1778 return (WINDOW_COPY_CMD_NOTHING
);
1781 static enum window_copy_cmd_action
1782 window_copy_cmd_next_space_end(struct window_copy_cmd_state
*cs
)
1784 struct window_mode_entry
*wme
= cs
->wme
;
1785 u_int np
= wme
->prefix
;
1787 for (; np
!= 0; np
--)
1788 window_copy_cursor_next_word_end(wme
, "", 0);
1789 return (WINDOW_COPY_CMD_NOTHING
);
1792 static enum window_copy_cmd_action
1793 window_copy_cmd_next_word(struct window_copy_cmd_state
*cs
)
1795 struct window_mode_entry
*wme
= cs
->wme
;
1796 u_int np
= wme
->prefix
;
1797 const char *separators
;
1799 separators
= options_get_string(cs
->s
->options
, "word-separators");
1801 for (; np
!= 0; np
--)
1802 window_copy_cursor_next_word(wme
, separators
);
1803 return (WINDOW_COPY_CMD_NOTHING
);
1806 static enum window_copy_cmd_action
1807 window_copy_cmd_next_word_end(struct window_copy_cmd_state
*cs
)
1809 struct window_mode_entry
*wme
= cs
->wme
;
1810 u_int np
= wme
->prefix
;
1811 const char *separators
;
1813 separators
= options_get_string(cs
->s
->options
, "word-separators");
1815 for (; np
!= 0; np
--)
1816 window_copy_cursor_next_word_end(wme
, separators
, 0);
1817 return (WINDOW_COPY_CMD_NOTHING
);
1820 static enum window_copy_cmd_action
1821 window_copy_cmd_other_end(struct window_copy_cmd_state
*cs
)
1823 struct window_mode_entry
*wme
= cs
->wme
;
1824 u_int np
= wme
->prefix
;
1825 struct window_copy_mode_data
*data
= wme
->data
;
1827 data
->selflag
= SEL_CHAR
;
1829 window_copy_other_end(wme
);
1830 return (WINDOW_COPY_CMD_NOTHING
);
1833 static enum window_copy_cmd_action
1834 window_copy_cmd_page_down(struct window_copy_cmd_state
*cs
)
1836 struct window_mode_entry
*wme
= cs
->wme
;
1837 struct window_copy_mode_data
*data
= wme
->data
;
1838 u_int np
= wme
->prefix
;
1840 for (; np
!= 0; np
--) {
1841 if (window_copy_pagedown1(wme
, 0, data
->scroll_exit
))
1842 return (WINDOW_COPY_CMD_CANCEL
);
1844 return (WINDOW_COPY_CMD_NOTHING
);
1847 static enum window_copy_cmd_action
1848 window_copy_cmd_page_down_and_cancel(struct window_copy_cmd_state
*cs
)
1850 struct window_mode_entry
*wme
= cs
->wme
;
1851 u_int np
= wme
->prefix
;
1853 for (; np
!= 0; np
--) {
1854 if (window_copy_pagedown1(wme
, 0, 1))
1855 return (WINDOW_COPY_CMD_CANCEL
);
1857 return (WINDOW_COPY_CMD_NOTHING
);
1860 static enum window_copy_cmd_action
1861 window_copy_cmd_page_up(struct window_copy_cmd_state
*cs
)
1863 struct window_mode_entry
*wme
= cs
->wme
;
1864 u_int np
= wme
->prefix
;
1866 for (; np
!= 0; np
--)
1867 window_copy_pageup1(wme
, 0);
1868 return (WINDOW_COPY_CMD_NOTHING
);
1871 static enum window_copy_cmd_action
1872 window_copy_cmd_previous_paragraph(struct window_copy_cmd_state
*cs
)
1874 struct window_mode_entry
*wme
= cs
->wme
;
1875 u_int np
= wme
->prefix
;
1877 for (; np
!= 0; np
--)
1878 window_copy_previous_paragraph(wme
);
1879 return (WINDOW_COPY_CMD_NOTHING
);
1882 static enum window_copy_cmd_action
1883 window_copy_cmd_previous_space(struct window_copy_cmd_state
*cs
)
1885 struct window_mode_entry
*wme
= cs
->wme
;
1886 u_int np
= wme
->prefix
;
1888 for (; np
!= 0; np
--)
1889 window_copy_cursor_previous_word(wme
, "", 1);
1890 return (WINDOW_COPY_CMD_NOTHING
);
1893 static enum window_copy_cmd_action
1894 window_copy_cmd_previous_word(struct window_copy_cmd_state
*cs
)
1896 struct window_mode_entry
*wme
= cs
->wme
;
1897 u_int np
= wme
->prefix
;
1898 const char *separators
;
1900 separators
= options_get_string(cs
->s
->options
, "word-separators");
1902 for (; np
!= 0; np
--)
1903 window_copy_cursor_previous_word(wme
, separators
, 1);
1904 return (WINDOW_COPY_CMD_NOTHING
);
1907 static enum window_copy_cmd_action
1908 window_copy_cmd_rectangle_on(struct window_copy_cmd_state
*cs
)
1910 struct window_mode_entry
*wme
= cs
->wme
;
1911 struct window_copy_mode_data
*data
= wme
->data
;
1913 data
->lineflag
= LINE_SEL_NONE
;
1914 window_copy_rectangle_set(wme
, 1);
1916 return (WINDOW_COPY_CMD_NOTHING
);
1919 static enum window_copy_cmd_action
1920 window_copy_cmd_rectangle_off(struct window_copy_cmd_state
*cs
)
1922 struct window_mode_entry
*wme
= cs
->wme
;
1923 struct window_copy_mode_data
*data
= wme
->data
;
1925 data
->lineflag
= LINE_SEL_NONE
;
1926 window_copy_rectangle_set(wme
, 0);
1928 return (WINDOW_COPY_CMD_NOTHING
);
1931 static enum window_copy_cmd_action
1932 window_copy_cmd_rectangle_toggle(struct window_copy_cmd_state
*cs
)
1934 struct window_mode_entry
*wme
= cs
->wme
;
1935 struct window_copy_mode_data
*data
= wme
->data
;
1937 data
->lineflag
= LINE_SEL_NONE
;
1938 window_copy_rectangle_set(wme
, !data
->rectflag
);
1940 return (WINDOW_COPY_CMD_NOTHING
);
1943 static enum window_copy_cmd_action
1944 window_copy_cmd_scroll_down(struct window_copy_cmd_state
*cs
)
1946 struct window_mode_entry
*wme
= cs
->wme
;
1947 struct window_copy_mode_data
*data
= wme
->data
;
1948 u_int np
= wme
->prefix
;
1950 for (; np
!= 0; np
--)
1951 window_copy_cursor_down(wme
, 1);
1952 if (data
->scroll_exit
&& data
->oy
== 0)
1953 return (WINDOW_COPY_CMD_CANCEL
);
1954 return (WINDOW_COPY_CMD_NOTHING
);
1957 static enum window_copy_cmd_action
1958 window_copy_cmd_scroll_down_and_cancel(struct window_copy_cmd_state
*cs
)
1960 struct window_mode_entry
*wme
= cs
->wme
;
1961 struct window_copy_mode_data
*data
= wme
->data
;
1962 u_int np
= wme
->prefix
;
1964 for (; np
!= 0; np
--)
1965 window_copy_cursor_down(wme
, 1);
1967 return (WINDOW_COPY_CMD_CANCEL
);
1968 return (WINDOW_COPY_CMD_NOTHING
);
1971 static enum window_copy_cmd_action
1972 window_copy_cmd_scroll_up(struct window_copy_cmd_state
*cs
)
1974 struct window_mode_entry
*wme
= cs
->wme
;
1975 u_int np
= wme
->prefix
;
1977 for (; np
!= 0; np
--)
1978 window_copy_cursor_up(wme
, 1);
1979 return (WINDOW_COPY_CMD_NOTHING
);
1982 static enum window_copy_cmd_action
1983 window_copy_cmd_search_again(struct window_copy_cmd_state
*cs
)
1985 struct window_mode_entry
*wme
= cs
->wme
;
1986 struct window_copy_mode_data
*data
= wme
->data
;
1987 u_int np
= wme
->prefix
;
1989 if (data
->searchtype
== WINDOW_COPY_SEARCHUP
) {
1990 for (; np
!= 0; np
--)
1991 window_copy_search_up(wme
, data
->searchregex
);
1992 } else if (data
->searchtype
== WINDOW_COPY_SEARCHDOWN
) {
1993 for (; np
!= 0; np
--)
1994 window_copy_search_down(wme
, data
->searchregex
);
1996 return (WINDOW_COPY_CMD_NOTHING
);
1999 static enum window_copy_cmd_action
2000 window_copy_cmd_search_reverse(struct window_copy_cmd_state
*cs
)
2002 struct window_mode_entry
*wme
= cs
->wme
;
2003 struct window_copy_mode_data
*data
= wme
->data
;
2004 u_int np
= wme
->prefix
;
2006 if (data
->searchtype
== WINDOW_COPY_SEARCHUP
) {
2007 for (; np
!= 0; np
--)
2008 window_copy_search_down(wme
, data
->searchregex
);
2009 } else if (data
->searchtype
== WINDOW_COPY_SEARCHDOWN
) {
2010 for (; np
!= 0; np
--)
2011 window_copy_search_up(wme
, data
->searchregex
);
2013 return (WINDOW_COPY_CMD_NOTHING
);
2016 static enum window_copy_cmd_action
2017 window_copy_cmd_select_line(struct window_copy_cmd_state
*cs
)
2019 struct window_mode_entry
*wme
= cs
->wme
;
2020 struct window_copy_mode_data
*data
= wme
->data
;
2021 u_int np
= wme
->prefix
;
2023 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
2025 data
->selflag
= SEL_LINE
;
2026 data
->dx
= data
->cx
;
2027 data
->dy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2029 window_copy_cursor_start_of_line(wme
);
2030 data
->selrx
= data
->cx
;
2031 data
->selry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2032 data
->endselry
= data
->selry
;
2033 window_copy_start_selection(wme
);
2034 window_copy_cursor_end_of_line(wme
);
2035 data
->endselry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2036 data
->endselrx
= window_copy_find_length(wme
, data
->endselry
);
2037 for (; np
> 1; np
--) {
2038 window_copy_cursor_down(wme
, 0);
2039 window_copy_cursor_end_of_line(wme
);
2042 return (WINDOW_COPY_CMD_REDRAW
);
2045 static enum window_copy_cmd_action
2046 window_copy_cmd_select_word(struct window_copy_cmd_state
*cs
)
2048 struct window_mode_entry
*wme
= cs
->wme
;
2049 struct options
*session_options
= cs
->s
->options
;
2050 struct window_copy_mode_data
*data
= wme
->data
;
2051 u_int px
, py
, nextx
, nexty
;
2053 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
2055 data
->selflag
= SEL_WORD
;
2056 data
->dx
= data
->cx
;
2057 data
->dy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2059 data
->separators
= options_get_string(session_options
,
2061 window_copy_cursor_previous_word(wme
, data
->separators
, 0);
2063 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2066 window_copy_start_selection(wme
);
2068 /* Handle single character words. */
2071 if (grid_get_line(data
->backing
->grid
, nexty
)->flags
&
2072 GRID_LINE_WRAPPED
&& nextx
> screen_size_x(data
->backing
) - 1) {
2076 if (px
>= window_copy_find_length(wme
, py
) ||
2077 !window_copy_in_set(wme
, nextx
, nexty
, WHITESPACE
))
2078 window_copy_cursor_next_word_end(wme
, data
->separators
, 1);
2080 window_copy_update_cursor(wme
, px
, data
->cy
);
2081 if (window_copy_update_selection(wme
, 1, 1))
2082 window_copy_redraw_lines(wme
, data
->cy
, 1);
2084 data
->endselrx
= data
->cx
;
2085 data
->endselry
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2086 if (data
->dy
> data
->endselry
) {
2087 data
->dy
= data
->endselry
;
2088 data
->dx
= data
->endselrx
;
2089 } else if (data
->dx
> data
->endselrx
)
2090 data
->dx
= data
->endselrx
;
2092 return (WINDOW_COPY_CMD_REDRAW
);
2095 static enum window_copy_cmd_action
2096 window_copy_cmd_set_mark(struct window_copy_cmd_state
*cs
)
2098 struct window_copy_mode_data
*data
= cs
->wme
->data
;
2100 data
->mx
= data
->cx
;
2101 data
->my
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
2103 return (WINDOW_COPY_CMD_REDRAW
);
2106 static enum window_copy_cmd_action
2107 window_copy_cmd_start_of_line(struct window_copy_cmd_state
*cs
)
2109 struct window_mode_entry
*wme
= cs
->wme
;
2111 window_copy_cursor_start_of_line(wme
);
2112 return (WINDOW_COPY_CMD_NOTHING
);
2115 static enum window_copy_cmd_action
2116 window_copy_cmd_top_line(struct window_copy_cmd_state
*cs
)
2118 struct window_mode_entry
*wme
= cs
->wme
;
2119 struct window_copy_mode_data
*data
= wme
->data
;
2124 window_copy_update_selection(wme
, 1, 0);
2125 return (WINDOW_COPY_CMD_REDRAW
);
2128 static enum window_copy_cmd_action
2129 window_copy_cmd_copy_pipe_no_clear(struct window_copy_cmd_state
*cs
)
2131 struct window_mode_entry
*wme
= cs
->wme
;
2132 struct client
*c
= cs
->c
;
2133 struct session
*s
= cs
->s
;
2134 struct winlink
*wl
= cs
->wl
;
2135 struct window_pane
*wp
= wme
->wp
;
2136 char *command
= NULL
, *prefix
= NULL
;
2137 const char *arg0
= args_string(cs
->wargs
, 0);
2138 const char *arg1
= args_string(cs
->wargs
, 1);
2139 int set_paste
= !args_has(cs
->wargs
, 'P');
2140 int set_clip
= !args_has(cs
->wargs
, 'C');
2143 prefix
= format_single(NULL
, arg1
, c
, s
, wl
, wp
);
2145 if (s
!= NULL
&& arg0
!= NULL
&& *arg0
!= '\0')
2146 command
= format_single(NULL
, arg0
, c
, s
, wl
, wp
);
2147 window_copy_copy_pipe(wme
, s
, prefix
, command
,
2148 set_paste
, set_clip
);
2152 return (WINDOW_COPY_CMD_NOTHING
);
2155 static enum window_copy_cmd_action
2156 window_copy_cmd_copy_pipe(struct window_copy_cmd_state
*cs
)
2158 struct window_mode_entry
*wme
= cs
->wme
;
2160 window_copy_cmd_copy_pipe_no_clear(cs
);
2161 window_copy_clear_selection(wme
);
2162 return (WINDOW_COPY_CMD_REDRAW
);
2165 static enum window_copy_cmd_action
2166 window_copy_cmd_copy_pipe_and_cancel(struct window_copy_cmd_state
*cs
)
2168 struct window_mode_entry
*wme
= cs
->wme
;
2170 window_copy_cmd_copy_pipe_no_clear(cs
);
2171 window_copy_clear_selection(wme
);
2172 return (WINDOW_COPY_CMD_CANCEL
);
2175 static enum window_copy_cmd_action
2176 window_copy_cmd_pipe_no_clear(struct window_copy_cmd_state
*cs
)
2178 struct window_mode_entry
*wme
= cs
->wme
;
2179 struct client
*c
= cs
->c
;
2180 struct session
*s
= cs
->s
;
2181 struct winlink
*wl
= cs
->wl
;
2182 struct window_pane
*wp
= wme
->wp
;
2183 char *command
= NULL
;
2184 const char *arg0
= args_string(cs
->wargs
, 0);
2186 if (s
!= NULL
&& arg0
!= NULL
&& *arg0
!= '\0')
2187 command
= format_single(NULL
, arg0
, c
, s
, wl
, wp
);
2188 window_copy_pipe(wme
, s
, command
);
2191 return (WINDOW_COPY_CMD_NOTHING
);
2194 static enum window_copy_cmd_action
2195 window_copy_cmd_pipe(struct window_copy_cmd_state
*cs
)
2197 struct window_mode_entry
*wme
= cs
->wme
;
2199 window_copy_cmd_pipe_no_clear(cs
);
2200 window_copy_clear_selection(wme
);
2201 return (WINDOW_COPY_CMD_REDRAW
);
2204 static enum window_copy_cmd_action
2205 window_copy_cmd_pipe_and_cancel(struct window_copy_cmd_state
*cs
)
2207 struct window_mode_entry
*wme
= cs
->wme
;
2209 window_copy_cmd_pipe_no_clear(cs
);
2210 window_copy_clear_selection(wme
);
2211 return (WINDOW_COPY_CMD_CANCEL
);
2214 static enum window_copy_cmd_action
2215 window_copy_cmd_goto_line(struct window_copy_cmd_state
*cs
)
2217 struct window_mode_entry
*wme
= cs
->wme
;
2218 const char *arg0
= args_string(cs
->wargs
, 0);
2221 window_copy_goto_line(wme
, arg0
);
2222 return (WINDOW_COPY_CMD_NOTHING
);
2225 static enum window_copy_cmd_action
2226 window_copy_cmd_jump_backward(struct window_copy_cmd_state
*cs
)
2228 struct window_mode_entry
*wme
= cs
->wme
;
2229 struct window_copy_mode_data
*data
= wme
->data
;
2230 u_int np
= wme
->prefix
;
2231 const char *arg0
= args_string(cs
->wargs
, 0);
2233 if (*arg0
!= '\0') {
2234 data
->jumptype
= WINDOW_COPY_JUMPBACKWARD
;
2235 free(data
->jumpchar
);
2236 data
->jumpchar
= utf8_fromcstr(arg0
);
2237 for (; np
!= 0; np
--)
2238 window_copy_cursor_jump_back(wme
);
2240 return (WINDOW_COPY_CMD_NOTHING
);
2243 static enum window_copy_cmd_action
2244 window_copy_cmd_jump_forward(struct window_copy_cmd_state
*cs
)
2246 struct window_mode_entry
*wme
= cs
->wme
;
2247 struct window_copy_mode_data
*data
= wme
->data
;
2248 u_int np
= wme
->prefix
;
2249 const char *arg0
= args_string(cs
->wargs
, 0);
2251 if (*arg0
!= '\0') {
2252 data
->jumptype
= WINDOW_COPY_JUMPFORWARD
;
2253 free(data
->jumpchar
);
2254 data
->jumpchar
= utf8_fromcstr(arg0
);
2255 for (; np
!= 0; np
--)
2256 window_copy_cursor_jump(wme
);
2258 return (WINDOW_COPY_CMD_NOTHING
);
2261 static enum window_copy_cmd_action
2262 window_copy_cmd_jump_to_backward(struct window_copy_cmd_state
*cs
)
2264 struct window_mode_entry
*wme
= cs
->wme
;
2265 struct window_copy_mode_data
*data
= wme
->data
;
2266 u_int np
= wme
->prefix
;
2267 const char *arg0
= args_string(cs
->wargs
, 0);
2269 if (*arg0
!= '\0') {
2270 data
->jumptype
= WINDOW_COPY_JUMPTOBACKWARD
;
2271 free(data
->jumpchar
);
2272 data
->jumpchar
= utf8_fromcstr(arg0
);
2273 for (; np
!= 0; np
--)
2274 window_copy_cursor_jump_to_back(wme
);
2276 return (WINDOW_COPY_CMD_NOTHING
);
2279 static enum window_copy_cmd_action
2280 window_copy_cmd_jump_to_forward(struct window_copy_cmd_state
*cs
)
2282 struct window_mode_entry
*wme
= cs
->wme
;
2283 struct window_copy_mode_data
*data
= wme
->data
;
2284 u_int np
= wme
->prefix
;
2285 const char *arg0
= args_string(cs
->wargs
, 0);
2287 if (*arg0
!= '\0') {
2288 data
->jumptype
= WINDOW_COPY_JUMPTOFORWARD
;
2289 free(data
->jumpchar
);
2290 data
->jumpchar
= utf8_fromcstr(arg0
);
2291 for (; np
!= 0; np
--)
2292 window_copy_cursor_jump_to(wme
);
2294 return (WINDOW_COPY_CMD_NOTHING
);
2297 static enum window_copy_cmd_action
2298 window_copy_cmd_jump_to_mark(struct window_copy_cmd_state
*cs
)
2300 struct window_mode_entry
*wme
= cs
->wme
;
2302 window_copy_jump_to_mark(wme
);
2303 return (WINDOW_COPY_CMD_NOTHING
);
2306 static enum window_copy_cmd_action
2307 window_copy_cmd_next_prompt(struct window_copy_cmd_state
*cs
)
2309 struct window_mode_entry
*wme
= cs
->wme
;
2311 window_copy_cursor_prompt(wme
, 1, args_has(cs
->wargs
, 'o'));
2312 return (WINDOW_COPY_CMD_NOTHING
);
2315 static enum window_copy_cmd_action
2316 window_copy_cmd_previous_prompt(struct window_copy_cmd_state
*cs
)
2318 struct window_mode_entry
*wme
= cs
->wme
;
2320 window_copy_cursor_prompt(wme
, 0, args_has(cs
->wargs
, 'o'));
2321 return (WINDOW_COPY_CMD_NOTHING
);
2324 static enum window_copy_cmd_action
2325 window_copy_cmd_search_backward(struct window_copy_cmd_state
*cs
)
2327 struct window_mode_entry
*wme
= cs
->wme
;
2328 struct window_copy_mode_data
*data
= wme
->data
;
2329 u_int np
= wme
->prefix
;
2331 if (!window_copy_expand_search_string(cs
))
2332 return (WINDOW_COPY_CMD_NOTHING
);
2334 if (data
->searchstr
!= NULL
) {
2335 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2336 data
->searchregex
= 1;
2338 for (; np
!= 0; np
--)
2339 window_copy_search_up(wme
, 1);
2341 return (WINDOW_COPY_CMD_NOTHING
);
2344 static enum window_copy_cmd_action
2345 window_copy_cmd_search_backward_text(struct window_copy_cmd_state
*cs
)
2347 struct window_mode_entry
*wme
= cs
->wme
;
2348 struct window_copy_mode_data
*data
= wme
->data
;
2349 u_int np
= wme
->prefix
;
2351 if (!window_copy_expand_search_string(cs
))
2352 return (WINDOW_COPY_CMD_NOTHING
);
2354 if (data
->searchstr
!= NULL
) {
2355 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2356 data
->searchregex
= 0;
2358 for (; np
!= 0; np
--)
2359 window_copy_search_up(wme
, 0);
2361 return (WINDOW_COPY_CMD_NOTHING
);
2364 static enum window_copy_cmd_action
2365 window_copy_cmd_search_forward(struct window_copy_cmd_state
*cs
)
2367 struct window_mode_entry
*wme
= cs
->wme
;
2368 struct window_copy_mode_data
*data
= wme
->data
;
2369 u_int np
= wme
->prefix
;
2371 if (!window_copy_expand_search_string(cs
))
2372 return (WINDOW_COPY_CMD_NOTHING
);
2374 if (data
->searchstr
!= NULL
) {
2375 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2376 data
->searchregex
= 1;
2378 for (; np
!= 0; np
--)
2379 window_copy_search_down(wme
, 1);
2381 return (WINDOW_COPY_CMD_NOTHING
);
2384 static enum window_copy_cmd_action
2385 window_copy_cmd_search_forward_text(struct window_copy_cmd_state
*cs
)
2387 struct window_mode_entry
*wme
= cs
->wme
;
2388 struct window_copy_mode_data
*data
= wme
->data
;
2389 u_int np
= wme
->prefix
;
2391 if (!window_copy_expand_search_string(cs
))
2392 return (WINDOW_COPY_CMD_NOTHING
);
2394 if (data
->searchstr
!= NULL
) {
2395 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2396 data
->searchregex
= 0;
2398 for (; np
!= 0; np
--)
2399 window_copy_search_down(wme
, 0);
2401 return (WINDOW_COPY_CMD_NOTHING
);
2404 static enum window_copy_cmd_action
2405 window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state
*cs
)
2407 struct window_mode_entry
*wme
= cs
->wme
;
2408 struct window_copy_mode_data
*data
= wme
->data
;
2409 const char *arg0
= args_string(cs
->wargs
, 0);
2410 const char *ss
= data
->searchstr
;
2412 enum window_copy_cmd_action action
= WINDOW_COPY_CMD_NOTHING
;
2416 log_debug("%s: %s", __func__
, arg0
);
2419 if (data
->searchx
== -1 || data
->searchy
== -1) {
2420 data
->searchx
= data
->cx
;
2421 data
->searchy
= data
->cy
;
2422 data
->searcho
= data
->oy
;
2423 } else if (ss
!= NULL
&& strcmp(arg0
, ss
) != 0) {
2424 data
->cx
= data
->searchx
;
2425 data
->cy
= data
->searchy
;
2426 data
->oy
= data
->searcho
;
2427 action
= WINDOW_COPY_CMD_REDRAW
;
2429 if (*arg0
== '\0') {
2430 window_copy_clear_marks(wme
);
2431 return (WINDOW_COPY_CMD_REDRAW
);
2436 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2437 data
->searchregex
= 0;
2438 free(data
->searchstr
);
2439 data
->searchstr
= xstrdup(arg0
);
2440 if (!window_copy_search_up(wme
, 0)) {
2441 window_copy_clear_marks(wme
);
2442 return (WINDOW_COPY_CMD_REDRAW
);
2446 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2447 data
->searchregex
= 0;
2448 free(data
->searchstr
);
2449 data
->searchstr
= xstrdup(arg0
);
2450 if (!window_copy_search_down(wme
, 0)) {
2451 window_copy_clear_marks(wme
);
2452 return (WINDOW_COPY_CMD_REDRAW
);
2459 static enum window_copy_cmd_action
2460 window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state
*cs
)
2462 struct window_mode_entry
*wme
= cs
->wme
;
2463 struct window_copy_mode_data
*data
= wme
->data
;
2464 const char *arg0
= args_string(cs
->wargs
, 0);
2465 const char *ss
= data
->searchstr
;
2467 enum window_copy_cmd_action action
= WINDOW_COPY_CMD_NOTHING
;
2471 log_debug("%s: %s", __func__
, arg0
);
2474 if (data
->searchx
== -1 || data
->searchy
== -1) {
2475 data
->searchx
= data
->cx
;
2476 data
->searchy
= data
->cy
;
2477 data
->searcho
= data
->oy
;
2478 } else if (ss
!= NULL
&& strcmp(arg0
, ss
) != 0) {
2479 data
->cx
= data
->searchx
;
2480 data
->cy
= data
->searchy
;
2481 data
->oy
= data
->searcho
;
2482 action
= WINDOW_COPY_CMD_REDRAW
;
2484 if (*arg0
== '\0') {
2485 window_copy_clear_marks(wme
);
2486 return (WINDOW_COPY_CMD_REDRAW
);
2491 data
->searchtype
= WINDOW_COPY_SEARCHDOWN
;
2492 data
->searchregex
= 0;
2493 free(data
->searchstr
);
2494 data
->searchstr
= xstrdup(arg0
);
2495 if (!window_copy_search_down(wme
, 0)) {
2496 window_copy_clear_marks(wme
);
2497 return (WINDOW_COPY_CMD_REDRAW
);
2501 data
->searchtype
= WINDOW_COPY_SEARCHUP
;
2502 data
->searchregex
= 0;
2503 free(data
->searchstr
);
2504 data
->searchstr
= xstrdup(arg0
);
2505 if (!window_copy_search_up(wme
, 0)) {
2506 window_copy_clear_marks(wme
);
2507 return (WINDOW_COPY_CMD_REDRAW
);
2513 static enum window_copy_cmd_action
2514 window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state
*cs
)
2516 struct window_mode_entry
*wme
= cs
->wme
;
2517 struct window_pane
*wp
= wme
->swp
;
2518 struct window_copy_mode_data
*data
= wme
->data
;
2521 return (WINDOW_COPY_CMD_NOTHING
);
2523 screen_free(data
->backing
);
2524 free(data
->backing
);
2525 data
->backing
= window_copy_clone_screen(&wp
->base
, &data
->screen
, NULL
,
2526 NULL
, wme
->swp
!= wme
->wp
);
2528 window_copy_size_changed(wme
);
2529 return (WINDOW_COPY_CMD_REDRAW
);
2532 static const struct {
2533 const char *command
;
2536 struct args_parse args
;
2537 enum window_copy_cmd_clear clear
;
2538 enum window_copy_cmd_action (*f
)(struct window_copy_cmd_state
*);
2539 } window_copy_cmd_table
[] = {
2540 { .command
= "append-selection",
2541 .args
= { "", 0, 0, NULL
},
2542 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2543 .f
= window_copy_cmd_append_selection
2545 { .command
= "append-selection-and-cancel",
2546 .args
= { "", 0, 0, NULL
},
2547 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2548 .f
= window_copy_cmd_append_selection_and_cancel
2550 { .command
= "back-to-indentation",
2551 .args
= { "", 0, 0, NULL
},
2552 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2553 .f
= window_copy_cmd_back_to_indentation
2555 { .command
= "begin-selection",
2556 .args
= { "", 0, 0, NULL
},
2557 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2558 .f
= window_copy_cmd_begin_selection
2560 { .command
= "bottom-line",
2561 .args
= { "", 0, 0, NULL
},
2562 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2563 .f
= window_copy_cmd_bottom_line
2565 { .command
= "cancel",
2566 .args
= { "", 0, 0, NULL
},
2567 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2568 .f
= window_copy_cmd_cancel
2570 { .command
= "clear-selection",
2571 .args
= { "", 0, 0, NULL
},
2572 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2573 .f
= window_copy_cmd_clear_selection
2575 { .command
= "copy-end-of-line",
2576 .args
= { "CP", 0, 1, NULL
},
2577 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2578 .f
= window_copy_cmd_copy_end_of_line
2580 { .command
= "copy-end-of-line-and-cancel",
2581 .args
= { "CP", 0, 1, NULL
},
2582 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2583 .f
= window_copy_cmd_copy_end_of_line_and_cancel
2585 { .command
= "copy-pipe-end-of-line",
2586 .args
= { "CP", 0, 2, NULL
},
2587 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2588 .f
= window_copy_cmd_copy_pipe_end_of_line
2590 { .command
= "copy-pipe-end-of-line-and-cancel",
2591 .args
= { "CP", 0, 2, NULL
},
2592 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2593 .f
= window_copy_cmd_copy_pipe_end_of_line_and_cancel
2595 { .command
= "copy-line",
2596 .args
= { "CP", 0, 1, NULL
},
2597 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2598 .f
= window_copy_cmd_copy_line
2600 { .command
= "copy-line-and-cancel",
2601 .args
= { "CP", 0, 1, NULL
},
2602 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2603 .f
= window_copy_cmd_copy_line_and_cancel
2605 { .command
= "copy-pipe-line",
2606 .args
= { "CP", 0, 2, NULL
},
2607 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2608 .f
= window_copy_cmd_copy_pipe_line
2610 { .command
= "copy-pipe-line-and-cancel",
2611 .args
= { "CP", 0, 2, NULL
},
2612 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2613 .f
= window_copy_cmd_copy_pipe_line_and_cancel
2615 { .command
= "copy-pipe-no-clear",
2616 .args
= { "CP", 0, 2, NULL
},
2617 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2618 .f
= window_copy_cmd_copy_pipe_no_clear
2620 { .command
= "copy-pipe",
2621 .args
= { "CP", 0, 2, NULL
},
2622 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2623 .f
= window_copy_cmd_copy_pipe
2625 { .command
= "copy-pipe-and-cancel",
2626 .args
= { "CP", 0, 2, NULL
},
2627 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2628 .f
= window_copy_cmd_copy_pipe_and_cancel
2630 { .command
= "copy-selection-no-clear",
2631 .args
= { "CP", 0, 1, NULL
},
2632 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2633 .f
= window_copy_cmd_copy_selection_no_clear
2635 { .command
= "copy-selection",
2636 .args
= { "CP", 0, 1, NULL
},
2637 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2638 .f
= window_copy_cmd_copy_selection
2640 { .command
= "copy-selection-and-cancel",
2641 .args
= { "CP", 0, 1, NULL
},
2642 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2643 .f
= window_copy_cmd_copy_selection_and_cancel
2645 { .command
= "cursor-down",
2646 .args
= { "", 0, 0, NULL
},
2647 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2648 .f
= window_copy_cmd_cursor_down
2650 { .command
= "cursor-down-and-cancel",
2651 .args
= { "", 0, 0, NULL
},
2652 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2653 .f
= window_copy_cmd_cursor_down_and_cancel
2655 { .command
= "cursor-left",
2656 .args
= { "", 0, 0, NULL
},
2657 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2658 .f
= window_copy_cmd_cursor_left
2660 { .command
= "cursor-right",
2661 .args
= { "", 0, 0, NULL
},
2662 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2663 .f
= window_copy_cmd_cursor_right
2665 { .command
= "cursor-up",
2666 .args
= { "", 0, 0, NULL
},
2667 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2668 .f
= window_copy_cmd_cursor_up
2670 { .command
= "end-of-line",
2671 .args
= { "", 0, 0, NULL
},
2672 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2673 .f
= window_copy_cmd_end_of_line
2675 { .command
= "goto-line",
2676 .args
= { "", 1, 1, NULL
},
2677 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2678 .f
= window_copy_cmd_goto_line
2680 { .command
= "halfpage-down",
2681 .args
= { "", 0, 0, NULL
},
2682 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2683 .f
= window_copy_cmd_halfpage_down
2685 { .command
= "halfpage-down-and-cancel",
2686 .args
= { "", 0, 0, NULL
},
2687 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2688 .f
= window_copy_cmd_halfpage_down_and_cancel
2690 { .command
= "halfpage-up",
2691 .args
= { "", 0, 0, NULL
},
2692 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2693 .f
= window_copy_cmd_halfpage_up
2695 { .command
= "history-bottom",
2696 .args
= { "", 0, 0, NULL
},
2697 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2698 .f
= window_copy_cmd_history_bottom
2700 { .command
= "history-top",
2701 .args
= { "", 0, 0, NULL
},
2702 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2703 .f
= window_copy_cmd_history_top
2705 { .command
= "jump-again",
2706 .args
= { "", 0, 0, NULL
},
2707 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2708 .f
= window_copy_cmd_jump_again
2710 { .command
= "jump-backward",
2711 .args
= { "", 1, 1, NULL
},
2712 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2713 .f
= window_copy_cmd_jump_backward
2715 { .command
= "jump-forward",
2716 .args
= { "", 1, 1, NULL
},
2717 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2718 .f
= window_copy_cmd_jump_forward
2720 { .command
= "jump-reverse",
2721 .args
= { "", 0, 0, NULL
},
2722 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2723 .f
= window_copy_cmd_jump_reverse
2725 { .command
= "jump-to-backward",
2726 .args
= { "", 1, 1, NULL
},
2727 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2728 .f
= window_copy_cmd_jump_to_backward
2730 { .command
= "jump-to-forward",
2731 .args
= { "", 1, 1, NULL
},
2732 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2733 .f
= window_copy_cmd_jump_to_forward
2735 { .command
= "jump-to-mark",
2736 .args
= { "", 0, 0, NULL
},
2737 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2738 .f
= window_copy_cmd_jump_to_mark
2740 { .command
= "next-prompt",
2741 .args
= { "o", 0, 0, NULL
},
2742 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2743 .f
= window_copy_cmd_next_prompt
2745 { .command
= "previous-prompt",
2746 .args
= { "o", 0, 0, NULL
},
2747 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2748 .f
= window_copy_cmd_previous_prompt
2750 { .command
= "middle-line",
2751 .args
= { "", 0, 0, NULL
},
2752 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2753 .f
= window_copy_cmd_middle_line
2755 { .command
= "next-matching-bracket",
2756 .args
= { "", 0, 0, NULL
},
2757 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2758 .f
= window_copy_cmd_next_matching_bracket
2760 { .command
= "next-paragraph",
2761 .args
= { "", 0, 0, NULL
},
2762 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2763 .f
= window_copy_cmd_next_paragraph
2765 { .command
= "next-space",
2766 .args
= { "", 0, 0, NULL
},
2767 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2768 .f
= window_copy_cmd_next_space
2770 { .command
= "next-space-end",
2771 .args
= { "", 0, 0, NULL
},
2772 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2773 .f
= window_copy_cmd_next_space_end
2775 { .command
= "next-word",
2776 .args
= { "", 0, 0, NULL
},
2777 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2778 .f
= window_copy_cmd_next_word
2780 { .command
= "next-word-end",
2781 .args
= { "", 0, 0, NULL
},
2782 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2783 .f
= window_copy_cmd_next_word_end
2785 { .command
= "other-end",
2786 .args
= { "", 0, 0, NULL
},
2787 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2788 .f
= window_copy_cmd_other_end
2790 { .command
= "page-down",
2791 .args
= { "", 0, 0, NULL
},
2792 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2793 .f
= window_copy_cmd_page_down
2795 { .command
= "page-down-and-cancel",
2796 .args
= { "", 0, 0, NULL
},
2797 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2798 .f
= window_copy_cmd_page_down_and_cancel
2800 { .command
= "page-up",
2801 .args
= { "", 0, 0, NULL
},
2802 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2803 .f
= window_copy_cmd_page_up
2805 { .command
= "pipe-no-clear",
2806 .args
= { "", 0, 1, NULL
},
2807 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2808 .f
= window_copy_cmd_pipe_no_clear
2810 { .command
= "pipe",
2811 .args
= { "", 0, 1, NULL
},
2812 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2813 .f
= window_copy_cmd_pipe
2815 { .command
= "pipe-and-cancel",
2816 .args
= { "", 0, 1, NULL
},
2817 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2818 .f
= window_copy_cmd_pipe_and_cancel
2820 { .command
= "previous-matching-bracket",
2821 .args
= { "", 0, 0, NULL
},
2822 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2823 .f
= window_copy_cmd_previous_matching_bracket
2825 { .command
= "previous-paragraph",
2826 .args
= { "", 0, 0, NULL
},
2827 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2828 .f
= window_copy_cmd_previous_paragraph
2830 { .command
= "previous-space",
2831 .args
= { "", 0, 0, NULL
},
2832 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2833 .f
= window_copy_cmd_previous_space
2835 { .command
= "previous-word",
2836 .args
= { "", 0, 0, NULL
},
2837 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2838 .f
= window_copy_cmd_previous_word
2840 { .command
= "rectangle-on",
2841 .args
= { "", 0, 0, NULL
},
2842 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2843 .f
= window_copy_cmd_rectangle_on
2845 { .command
= "rectangle-off",
2846 .args
= { "", 0, 0, NULL
},
2847 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2848 .f
= window_copy_cmd_rectangle_off
2850 { .command
= "rectangle-toggle",
2851 .args
= { "", 0, 0, NULL
},
2852 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2853 .f
= window_copy_cmd_rectangle_toggle
2855 { .command
= "refresh-from-pane",
2856 .args
= { "", 0, 0, NULL
},
2857 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2858 .f
= window_copy_cmd_refresh_from_pane
2860 { .command
= "scroll-bottom",
2861 .args
= { "", 0, 0, NULL
},
2862 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2863 .f
= window_copy_cmd_scroll_bottom
2865 { .command
= "scroll-down",
2866 .args
= { "", 0, 0, NULL
},
2867 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2868 .f
= window_copy_cmd_scroll_down
2870 { .command
= "scroll-down-and-cancel",
2871 .args
= { "", 0, 0, NULL
},
2872 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2873 .f
= window_copy_cmd_scroll_down_and_cancel
2875 { .command
= "scroll-middle",
2876 .args
= { "", 0, 0, NULL
},
2877 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2878 .f
= window_copy_cmd_scroll_middle
2880 { .command
= "scroll-top",
2881 .args
= { "", 0, 0, NULL
},
2882 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2883 .f
= window_copy_cmd_scroll_top
2885 { .command
= "scroll-up",
2886 .args
= { "", 0, 0, NULL
},
2887 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2888 .f
= window_copy_cmd_scroll_up
2890 { .command
= "search-again",
2891 .args
= { "", 0, 0, NULL
},
2892 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2893 .f
= window_copy_cmd_search_again
2895 { .command
= "search-backward",
2896 .args
= { "", 0, 1, NULL
},
2897 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2898 .f
= window_copy_cmd_search_backward
2900 { .command
= "search-backward-text",
2901 .args
= { "", 0, 1, NULL
},
2902 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2903 .f
= window_copy_cmd_search_backward_text
2905 { .command
= "search-backward-incremental",
2906 .args
= { "", 1, 1, NULL
},
2907 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2908 .f
= window_copy_cmd_search_backward_incremental
2910 { .command
= "search-forward",
2911 .args
= { "", 0, 1, NULL
},
2912 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2913 .f
= window_copy_cmd_search_forward
2915 { .command
= "search-forward-text",
2916 .args
= { "", 0, 1, NULL
},
2917 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2918 .f
= window_copy_cmd_search_forward_text
2920 { .command
= "search-forward-incremental",
2921 .args
= { "", 1, 1, NULL
},
2922 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2923 .f
= window_copy_cmd_search_forward_incremental
2925 { .command
= "search-reverse",
2926 .args
= { "", 0, 0, NULL
},
2927 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2928 .f
= window_copy_cmd_search_reverse
2930 { .command
= "select-line",
2931 .args
= { "", 0, 0, NULL
},
2932 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2933 .f
= window_copy_cmd_select_line
2935 { .command
= "select-word",
2936 .args
= { "", 0, 0, NULL
},
2937 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2938 .f
= window_copy_cmd_select_word
2940 { .command
= "set-mark",
2941 .args
= { "", 0, 0, NULL
},
2942 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2943 .f
= window_copy_cmd_set_mark
2945 { .command
= "start-of-line",
2946 .args
= { "", 0, 0, NULL
},
2947 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2948 .f
= window_copy_cmd_start_of_line
2950 { .command
= "stop-selection",
2951 .args
= { "", 0, 0, NULL
},
2952 .clear
= WINDOW_COPY_CMD_CLEAR_ALWAYS
,
2953 .f
= window_copy_cmd_stop_selection
2955 { .command
= "toggle-position",
2956 .args
= { "", 0, 0, NULL
},
2957 .clear
= WINDOW_COPY_CMD_CLEAR_NEVER
,
2958 .f
= window_copy_cmd_toggle_position
2960 { .command
= "top-line",
2961 .args
= { "", 0, 0, NULL
},
2962 .clear
= WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
,
2963 .f
= window_copy_cmd_top_line
2968 window_copy_command(struct window_mode_entry
*wme
, struct client
*c
,
2969 struct session
*s
, struct winlink
*wl
, struct args
*args
,
2970 struct mouse_event
*m
)
2972 struct window_copy_mode_data
*data
= wme
->data
;
2973 struct window_pane
*wp
= wme
->wp
;
2974 struct window_copy_cmd_state cs
;
2975 enum window_copy_cmd_action action
;
2976 enum window_copy_cmd_clear clear
= WINDOW_COPY_CMD_CLEAR_NEVER
;
2977 const char *command
;
2978 u_int i
, count
= args_count(args
);
2984 command
= args_string(args
, 0);
2986 if (m
!= NULL
&& m
->valid
&& !MOUSE_WHEEL(m
->b
))
2987 window_copy_move_mouse(m
);
2998 action
= WINDOW_COPY_CMD_NOTHING
;
2999 for (i
= 0; i
< nitems(window_copy_cmd_table
); i
++) {
3000 if (strcmp(window_copy_cmd_table
[i
].command
, command
) == 0) {
3001 cs
.wargs
= args_parse(&window_copy_cmd_table
[i
].args
,
3002 args_values(args
), count
, &error
);
3004 if (error
!= NULL
) {
3008 if (cs
.wargs
== NULL
)
3011 clear
= window_copy_cmd_table
[i
].clear
;
3012 action
= window_copy_cmd_table
[i
].f(&cs
);
3013 args_free(cs
.wargs
);
3019 if (strncmp(command
, "search-", 7) != 0 && data
->searchmark
!= NULL
) {
3020 keys
= options_get_number(wp
->window
->options
, "mode-keys");
3021 if (clear
== WINDOW_COPY_CMD_CLEAR_EMACS_ONLY
&&
3023 clear
= WINDOW_COPY_CMD_CLEAR_NEVER
;
3024 if (clear
!= WINDOW_COPY_CMD_CLEAR_NEVER
) {
3025 window_copy_clear_marks(wme
);
3026 data
->searchx
= data
->searchy
= -1;
3028 if (action
== WINDOW_COPY_CMD_NOTHING
)
3029 action
= WINDOW_COPY_CMD_REDRAW
;
3033 if (action
== WINDOW_COPY_CMD_CANCEL
)
3034 window_pane_reset_mode(wp
);
3035 else if (action
== WINDOW_COPY_CMD_REDRAW
)
3036 window_copy_redraw_screen(wme
);
3040 window_copy_scroll_to(struct window_mode_entry
*wme
, u_int px
, u_int py
,
3043 struct window_copy_mode_data
*data
= wme
->data
;
3044 struct grid
*gd
= data
->backing
->grid
;
3049 if (py
>= gd
->hsize
- data
->oy
&& py
< gd
->hsize
- data
->oy
+ gd
->sy
)
3050 data
->cy
= py
- (gd
->hsize
- data
->oy
);
3056 } else if (py
> gd
->hsize
+ gd
->sy
- gap
) {
3058 data
->cy
= py
- gd
->hsize
;
3060 offset
= py
+ gap
- gd
->sy
;
3061 data
->cy
= py
- offset
;
3063 data
->oy
= gd
->hsize
- offset
;
3066 if (!no_redraw
&& data
->searchmark
!= NULL
&& !data
->timeout
)
3067 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
3068 window_copy_update_selection(wme
, 1, 0);
3070 window_copy_redraw_screen(wme
);
3074 window_copy_search_compare(struct grid
*gd
, u_int px
, u_int py
,
3075 struct grid
*sgd
, u_int spx
, int cis
)
3077 struct grid_cell gc
, sgc
;
3078 const struct utf8_data
*ud
, *sud
;
3080 grid_get_cell(gd
, px
, py
, &gc
);
3082 grid_get_cell(sgd
, spx
, 0, &sgc
);
3085 if (ud
->size
!= sud
->size
|| ud
->width
!= sud
->width
)
3088 if (cis
&& ud
->size
== 1)
3089 return (tolower(ud
->data
[0]) == sud
->data
[0]);
3091 return (memcmp(ud
->data
, sud
->data
, ud
->size
) == 0);
3095 window_copy_search_lr(struct grid
*gd
, struct grid
*sgd
, u_int
*ppx
, u_int py
,
3096 u_int first
, u_int last
, int cis
)
3098 u_int ax
, bx
, px
, pywrap
, endline
;
3100 struct grid_line
*gl
;
3102 endline
= gd
->hsize
+ gd
->sy
- 1;
3103 for (ax
= first
; ax
< last
; ax
++) {
3104 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
3108 while (px
>= gd
->sx
&& pywrap
< endline
) {
3109 gl
= grid_get_line(gd
, pywrap
);
3110 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3115 /* We have run off the end of the grid. */
3118 matched
= window_copy_search_compare(gd
, px
, pywrap
,
3123 if (bx
== sgd
->sx
) {
3132 window_copy_search_rl(struct grid
*gd
,
3133 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
, int cis
)
3135 u_int ax
, bx
, px
, pywrap
, endline
;
3137 struct grid_line
*gl
;
3139 endline
= gd
->hsize
+ gd
->sy
- 1;
3140 for (ax
= last
; ax
> first
; ax
--) {
3141 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
3145 while (px
>= gd
->sx
&& pywrap
< endline
) {
3146 gl
= grid_get_line(gd
, pywrap
);
3147 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3152 /* We have run off the end of the grid. */
3155 matched
= window_copy_search_compare(gd
, px
, pywrap
,
3160 if (bx
== sgd
->sx
) {
3169 window_copy_search_lr_regex(struct grid
*gd
, u_int
*ppx
, u_int
*psx
, u_int py
,
3170 u_int first
, u_int last
, regex_t
*reg
)
3173 u_int endline
, foundx
, foundy
, len
, pywrap
, size
= 1;
3175 regmatch_t regmatch
;
3176 struct grid_line
*gl
;
3179 * This can happen during search if the last match was the last
3180 * character on a line.
3185 /* Set flags for regex search. */
3187 eflags
|= REG_NOTBOL
;
3189 /* Need to look at the entire string. */
3190 buf
= xmalloc(size
);
3192 buf
= window_copy_stringify(gd
, py
, first
, gd
->sx
, buf
, &size
);
3193 len
= gd
->sx
- first
;
3194 endline
= gd
->hsize
+ gd
->sy
- 1;
3196 while (buf
!= NULL
&&
3197 pywrap
<= endline
&&
3198 len
< WINDOW_COPY_SEARCH_MAX_LINE
) {
3199 gl
= grid_get_line(gd
, pywrap
);
3200 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3203 buf
= window_copy_stringify(gd
, pywrap
, 0, gd
->sx
, buf
, &size
);
3207 if (regexec(reg
, buf
, 1, ®match
, eflags
) == 0 &&
3208 regmatch
.rm_so
!= regmatch
.rm_eo
) {
3211 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3212 buf
+ regmatch
.rm_so
);
3213 if (foundy
== py
&& foundx
< last
) {
3215 len
-= foundx
- first
;
3216 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3217 buf
+ regmatch
.rm_eo
);
3219 while (foundy
> py
) {
3236 window_copy_search_rl_regex(struct grid
*gd
, u_int
*ppx
, u_int
*psx
, u_int py
,
3237 u_int first
, u_int last
, regex_t
*reg
)
3240 u_int endline
, len
, pywrap
, size
= 1;
3242 struct grid_line
*gl
;
3244 /* Set flags for regex search. */
3246 eflags
|= REG_NOTBOL
;
3248 /* Need to look at the entire string. */
3249 buf
= xmalloc(size
);
3251 buf
= window_copy_stringify(gd
, py
, first
, gd
->sx
, buf
, &size
);
3252 len
= gd
->sx
- first
;
3253 endline
= gd
->hsize
+ gd
->sy
- 1;
3255 while (buf
!= NULL
&&
3256 pywrap
<= endline
&&
3257 len
< WINDOW_COPY_SEARCH_MAX_LINE
) {
3258 gl
= grid_get_line(gd
, pywrap
);
3259 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3262 buf
= window_copy_stringify(gd
, pywrap
, 0, gd
->sx
, buf
, &size
);
3266 if (window_copy_last_regex(gd
, py
, first
, last
, len
, ppx
, psx
, buf
,
3280 window_copy_cellstring(const struct grid_line
*gl
, u_int px
, size_t *size
,
3283 static struct utf8_data ud
;
3284 struct grid_cell_entry
*gce
;
3287 if (px
>= gl
->cellsize
) {
3293 gce
= &gl
->celldata
[px
];
3294 if (gce
->flags
& GRID_FLAG_PADDING
) {
3299 if (~gce
->flags
& GRID_FLAG_EXTENDED
) {
3302 return (&gce
->data
.data
);
3305 utf8_to_data(gl
->extddata
[gce
->offset
].data
, &ud
);
3314 copy
= xmalloc(ud
.size
);
3315 memcpy(copy
, ud
.data
, ud
.size
);
3319 /* Find last match in given range. */
3321 window_copy_last_regex(struct grid
*gd
, u_int py
, u_int first
, u_int last
,
3322 u_int len
, u_int
*ppx
, u_int
*psx
, const char *buf
, const regex_t
*preg
,
3325 u_int foundx
, foundy
, oldx
, px
= 0, savepx
, savesx
= 0;
3326 regmatch_t regmatch
;
3331 while (regexec(preg
, buf
+ px
, 1, ®match
, eflags
) == 0) {
3332 if (regmatch
.rm_so
== regmatch
.rm_eo
)
3334 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3335 buf
+ px
+ regmatch
.rm_so
);
3336 if (foundy
> py
|| foundx
>= last
)
3338 len
-= foundx
- oldx
;
3340 window_copy_cstrtocellpos(gd
, len
, &foundx
, &foundy
,
3341 buf
+ px
+ regmatch
.rm_eo
);
3342 if (foundy
> py
|| foundx
>= last
) {
3345 while (foundy
> py
) {
3352 savesx
= foundx
- savepx
;
3356 px
+= regmatch
.rm_eo
;
3370 /* Stringify line and append to input buffer. Caller frees. */
3372 window_copy_stringify(struct grid
*gd
, u_int py
, u_int first
, u_int last
,
3373 char *buf
, u_int
*size
)
3375 u_int ax
, bx
, newsize
= *size
;
3376 const struct grid_line
*gl
;
3378 size_t bufsize
= 1024, dlen
;
3381 while (bufsize
< newsize
)
3383 buf
= xrealloc(buf
, bufsize
);
3385 gl
= grid_peek_line(gd
, py
);
3387 for (ax
= first
; ax
< last
; ax
++) {
3388 d
= window_copy_cellstring(gl
, ax
, &dlen
, &allocated
);
3390 while (bufsize
< newsize
) {
3392 buf
= xrealloc(buf
, bufsize
);
3397 memcpy(buf
+ bx
, d
, dlen
);
3403 buf
[newsize
- 1] = '\0';
3409 /* Map start of C string containing UTF-8 data to grid cell position. */
3411 window_copy_cstrtocellpos(struct grid
*gd
, u_int ncells
, u_int
*ppx
, u_int
*ppy
,
3414 u_int cell
, ccell
, px
, pywrap
, pos
, len
;
3416 const struct grid_line
*gl
;
3425 /* Populate the array of cell data. */
3426 cells
= xreallocarray(NULL
, ncells
, sizeof cells
[0]);
3430 gl
= grid_peek_line(gd
, pywrap
);
3431 while (cell
< ncells
) {
3432 cells
[cell
].d
= window_copy_cellstring(gl
, px
,
3433 &cells
[cell
].dlen
, &cells
[cell
].allocated
);
3439 gl
= grid_peek_line(gd
, pywrap
);
3443 /* Locate starting cell. */
3446 while (cell
< ncells
) {
3450 while (ccell
< ncells
) {
3451 if (str
[pos
] == '\0') {
3456 dlen
= cells
[ccell
].dlen
;
3458 if (str
[pos
] != *d
) {
3464 if (dlen
> len
- pos
)
3466 if (memcmp(str
+ pos
, d
, dlen
) != 0) {
3479 /* If not found this will be one past the end. */
3482 while (px
>= gd
->sx
) {
3490 /* Free cell data. */
3491 for (cell
= 0; cell
< ncells
; cell
++) {
3492 if (cells
[cell
].allocated
)
3493 free((void *)cells
[cell
].d
);
3499 window_copy_move_left(struct screen
*s
, u_int
*fx
, u_int
*fy
, int wrapflag
)
3501 if (*fx
== 0) { /* left */
3502 if (*fy
== 0) { /* top */
3504 *fx
= screen_size_x(s
) - 1;
3505 *fy
= screen_hsize(s
) + screen_size_y(s
) - 1;
3509 *fx
= screen_size_x(s
) - 1;
3516 window_copy_move_right(struct screen
*s
, u_int
*fx
, u_int
*fy
, int wrapflag
)
3518 if (*fx
== screen_size_x(s
) - 1) { /* right */
3519 if (*fy
== screen_hsize(s
) + screen_size_y(s
) - 1) { /* bottom */
3533 window_copy_is_lowercase(const char *ptr
)
3535 while (*ptr
!= '\0') {
3536 if (*ptr
!= tolower((u_char
)*ptr
))
3544 * Handle backward wrapped regex searches with overlapping matches. In this case
3545 * find the longest overlapping match from previous wrapped lines.
3548 window_copy_search_back_overlap(struct grid
*gd
, regex_t
*preg
, u_int
*ppx
,
3549 u_int
*psx
, u_int
*ppy
, u_int endline
)
3551 u_int endx
, endy
, oldendx
, oldendy
, px
, py
, sx
;
3554 oldendx
= *ppx
+ *psx
;
3556 while (oldendx
> gd
->sx
- 1) {
3564 while (found
&& px
== 0 && py
- 1 > endline
&&
3565 grid_get_line(gd
, py
- 2)->flags
& GRID_LINE_WRAPPED
&&
3566 endx
== oldendx
&& endy
== oldendy
) {
3568 found
= window_copy_search_rl_regex(gd
, &px
, &sx
, py
- 1, 0,
3573 while (endx
> gd
->sx
- 1) {
3577 if (endx
== oldendx
&& endy
== oldendy
) {
3586 * Search for text stored in sgd starting from position fx,fy up to endline. If
3587 * found, jump to it. If cis then ignore case. The direction is 0 for searching
3588 * up, down otherwise. If wrap then go to begin/end of grid and try again if
3592 window_copy_search_jump(struct window_mode_entry
*wme
, struct grid
*gd
,
3593 struct grid
*sgd
, u_int fx
, u_int fy
, u_int endline
, int cis
, int wrap
,
3594 int direction
, int regex
)
3596 u_int i
, px
, sx
, ssize
= 1;
3597 int found
= 0, cflags
= REG_EXTENDED
;
3602 sbuf
= xmalloc(ssize
);
3604 sbuf
= window_copy_stringify(sgd
, 0, 0, sgd
->sx
, sbuf
, &ssize
);
3606 cflags
|= REG_ICASE
;
3607 if (regcomp(®
, sbuf
, cflags
) != 0) {
3615 for (i
= fy
; i
<= endline
; i
++) {
3617 found
= window_copy_search_lr_regex(gd
,
3618 &px
, &sx
, i
, fx
, gd
->sx
, ®
);
3620 found
= window_copy_search_lr(gd
, sgd
,
3621 &px
, i
, fx
, gd
->sx
, cis
);
3628 for (i
= fy
+ 1; endline
< i
; i
--) {
3630 found
= window_copy_search_rl_regex(gd
,
3631 &px
, &sx
, i
- 1, 0, fx
+ 1, ®
);
3633 window_copy_search_back_overlap(gd
,
3634 ®
, &px
, &sx
, &i
, endline
);
3637 found
= window_copy_search_rl(gd
, sgd
,
3638 &px
, i
- 1, 0, fx
+ 1, cis
);
3651 window_copy_scroll_to(wme
, px
, i
, 1);
3655 return (window_copy_search_jump(wme
, gd
, sgd
,
3656 direction
? 0 : gd
->sx
- 1,
3657 direction
? 0 : gd
->hsize
+ gd
->sy
- 1, fy
, cis
, 0,
3664 window_copy_move_after_search_mark(struct window_copy_mode_data
*data
,
3665 u_int
*fx
, u_int
*fy
, int wrapflag
)
3667 struct screen
*s
= data
->backing
;
3670 if (window_copy_search_mark_at(data
, *fx
, *fy
, &start
) == 0 &&
3671 data
->searchmark
[start
] != 0) {
3672 while (window_copy_search_mark_at(data
, *fx
, *fy
, &at
) == 0) {
3673 if (data
->searchmark
[at
] != data
->searchmark
[start
])
3675 /* Stop if not wrapping and at the end of the grid. */
3677 *fx
== screen_size_x(s
) - 1 &&
3678 *fy
== screen_hsize(s
) + screen_size_y(s
) - 1)
3681 window_copy_move_right(s
, fx
, fy
, wrapflag
);
3687 * Search in for text searchstr. If direction is 0 then search up, otherwise
3691 window_copy_search(struct window_mode_entry
*wme
, int direction
, int regex
)
3693 struct window_pane
*wp
= wme
->wp
;
3694 struct window_copy_mode_data
*data
= wme
->data
;
3695 struct screen
*s
= data
->backing
, ss
;
3696 struct screen_write_ctx ctx
;
3697 struct grid
*gd
= s
->grid
;
3698 const char *str
= data
->searchstr
;
3699 u_int at
, endline
, fx
, fy
, start
;
3700 int cis
, found
, keys
, visible_only
;
3703 if (regex
&& str
[strcspn(str
, "^$*+()?[].\\")] == '\0')
3706 data
->searchdirection
= direction
;
3711 if (data
->searchall
|| wp
->searchstr
== NULL
||
3712 wp
->searchregex
!= regex
) {
3714 data
->searchall
= 0;
3716 visible_only
= (strcmp(wp
->searchstr
, str
) == 0);
3717 if (visible_only
== 0 && data
->searchmark
!= NULL
)
3718 window_copy_clear_marks(wme
);
3719 free(wp
->searchstr
);
3720 wp
->searchstr
= xstrdup(str
);
3721 wp
->searchregex
= regex
;
3724 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3726 screen_init(&ss
, screen_write_strlen("%s", str
), 1, 0);
3727 screen_write_start(&ctx
, &ss
);
3728 screen_write_nputs(&ctx
, -1, &grid_default_cell
, "%s", str
);
3729 screen_write_stop(&ctx
);
3731 wrapflag
= options_get_number(wp
->window
->options
, "wrap-search");
3732 cis
= window_copy_is_lowercase(str
);
3734 keys
= options_get_number(wp
->window
->options
, "mode-keys");
3738 * Behave according to mode-keys. If it is emacs, search forward
3739 * leaves the cursor after the match. If it is vi, the cursor
3740 * remains at the beginning of the match, regardless of
3741 * direction, which means that we need to start the next search
3742 * after the term the cursor is currently on when searching
3745 if (keys
== MODEKEY_VI
) {
3746 if (data
->searchmark
!= NULL
)
3747 window_copy_move_after_search_mark(data
, &fx
,
3751 * When there are no search marks, start the
3752 * search after the current cursor position.
3754 window_copy_move_right(s
, &fx
, &fy
, wrapflag
);
3757 endline
= gd
->hsize
+ gd
->sy
- 1;
3759 window_copy_move_left(s
, &fx
, &fy
, wrapflag
);
3763 found
= window_copy_search_jump(wme
, gd
, ss
.grid
, fx
, fy
, endline
, cis
,
3764 wrapflag
, direction
, regex
);
3766 window_copy_search_marks(wme
, &ss
, regex
, visible_only
);
3768 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3771 * When searching forward, if the cursor is not at the beginning
3772 * of the mark, search again.
3775 window_copy_search_mark_at(data
, fx
, fy
, &at
) == 0 &&
3777 data
->searchmark
!= NULL
&&
3778 data
->searchmark
[at
] == data
->searchmark
[at
- 1]) {
3779 window_copy_move_after_search_mark(data
, &fx
, &fy
,
3781 window_copy_search_jump(wme
, gd
, ss
.grid
, fx
,
3782 fy
, endline
, cis
, wrapflag
, direction
,
3785 fy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
3790 * When in Emacs mode, position the cursor just after
3793 if (keys
== MODEKEY_EMACS
) {
3794 window_copy_move_after_search_mark(data
, &fx
,
3797 data
->cy
= fy
- screen_hsize(data
->backing
) +
3802 * When searching backward, position the cursor at the
3803 * beginning of the mark.
3805 if (window_copy_search_mark_at(data
, fx
, fy
,
3807 while (window_copy_search_mark_at(data
, fx
, fy
,
3809 data
->searchmark
!= NULL
&&
3810 data
->searchmark
[at
] ==
3811 data
->searchmark
[start
]) {
3814 screen_hsize(data
->backing
) +
3819 window_copy_move_left(s
, &fx
, &fy
, 0);
3824 window_copy_redraw_screen(wme
);
3831 window_copy_visible_lines(struct window_copy_mode_data
*data
, u_int
*start
,
3834 struct grid
*gd
= data
->backing
->grid
;
3835 const struct grid_line
*gl
;
3837 for (*start
= gd
->hsize
- data
->oy
; *start
> 0; (*start
)--) {
3838 gl
= grid_peek_line(gd
, (*start
) - 1);
3839 if (~gl
->flags
& GRID_LINE_WRAPPED
)
3842 *end
= gd
->hsize
- data
->oy
+ gd
->sy
;
3846 window_copy_search_mark_at(struct window_copy_mode_data
*data
, u_int px
,
3847 u_int py
, u_int
*at
)
3849 struct screen
*s
= data
->backing
;
3850 struct grid
*gd
= s
->grid
;
3852 if (py
< gd
->hsize
- data
->oy
)
3854 if (py
> gd
->hsize
- data
->oy
+ gd
->sy
- 1)
3856 *at
= ((py
- (gd
->hsize
- data
->oy
)) * gd
->sx
) + px
;
3861 window_copy_search_marks(struct window_mode_entry
*wme
, struct screen
*ssp
,
3862 int regex
, int visible_only
)
3864 struct window_copy_mode_data
*data
= wme
->data
;
3865 struct screen
*s
= data
->backing
, ss
;
3866 struct screen_write_ctx ctx
;
3867 struct grid
*gd
= s
->grid
;
3868 int found
, cis
, stopped
= 0;
3869 int cflags
= REG_EXTENDED
;
3870 u_int px
, py
, i
, b
, nfound
= 0, width
;
3871 u_int ssize
= 1, start
, end
;
3874 uint64_t stop
= 0, tstart
, t
;
3877 width
= screen_write_strlen("%s", data
->searchstr
);
3878 screen_init(&ss
, width
, 1, 0);
3879 screen_write_start(&ctx
, &ss
);
3880 screen_write_nputs(&ctx
, -1, &grid_default_cell
, "%s",
3882 screen_write_stop(&ctx
);
3885 width
= screen_size_x(ssp
);
3887 cis
= window_copy_is_lowercase(data
->searchstr
);
3890 sbuf
= xmalloc(ssize
);
3892 sbuf
= window_copy_stringify(ssp
->grid
, 0, 0, ssp
->grid
->sx
,
3895 cflags
|= REG_ICASE
;
3896 if (regcomp(®
, sbuf
, cflags
) != 0) {
3902 tstart
= get_timer();
3905 window_copy_visible_lines(data
, &start
, &end
);
3908 end
= gd
->hsize
+ gd
->sy
;
3909 stop
= get_timer() + WINDOW_COPY_SEARCH_ALL_TIMEOUT
;
3913 free(data
->searchmark
);
3914 data
->searchmark
= xcalloc(gd
->sx
, gd
->sy
);
3915 data
->searchgen
= 1;
3917 for (py
= start
; py
< end
; py
++) {
3921 found
= window_copy_search_lr_regex(gd
,
3922 &px
, &width
, py
, px
, gd
->sx
, ®
);
3926 found
= window_copy_search_lr(gd
, ssp
->grid
,
3927 &px
, py
, px
, gd
->sx
, cis
);
3933 if (window_copy_search_mark_at(data
, px
, py
, &b
) == 0) {
3934 if (b
+ width
> gd
->sx
* gd
->sy
)
3935 width
= (gd
->sx
* gd
->sy
) - b
;
3936 for (i
= b
; i
< b
+ width
; i
++) {
3937 if (data
->searchmark
[i
] != 0)
3939 data
->searchmark
[i
] = data
->searchgen
;
3941 if (data
->searchgen
== UCHAR_MAX
)
3942 data
->searchgen
= 1;
3950 if (t
- tstart
> WINDOW_COPY_SEARCH_TIMEOUT
) {
3954 if (stop
!= 0 && t
> stop
) {
3959 if (data
->timeout
) {
3960 window_copy_clear_marks(wme
);
3964 if (stopped
&& stop
!= 0) {
3965 /* Try again but just the visible context. */
3966 window_copy_visible_lines(data
, &start
, &end
);
3971 if (!visible_only
) {
3974 data
->searchcount
= 1000;
3975 else if (nfound
> 100)
3976 data
->searchcount
= 100;
3977 else if (nfound
> 10)
3978 data
->searchcount
= 10;
3980 data
->searchcount
= -1;
3981 data
->searchmore
= 1;
3983 data
->searchcount
= nfound
;
3984 data
->searchmore
= 0;
3997 window_copy_clear_marks(struct window_mode_entry
*wme
)
3999 struct window_copy_mode_data
*data
= wme
->data
;
4001 free(data
->searchmark
);
4002 data
->searchmark
= NULL
;
4006 window_copy_search_up(struct window_mode_entry
*wme
, int regex
)
4008 return (window_copy_search(wme
, 0, regex
));
4012 window_copy_search_down(struct window_mode_entry
*wme
, int regex
)
4014 return (window_copy_search(wme
, 1, regex
));
4018 window_copy_goto_line(struct window_mode_entry
*wme
, const char *linestr
)
4020 struct window_copy_mode_data
*data
= wme
->data
;
4024 lineno
= strtonum(linestr
, -1, INT_MAX
, &errstr
);
4027 if (lineno
< 0 || (u_int
)lineno
> screen_hsize(data
->backing
))
4028 lineno
= screen_hsize(data
->backing
);
4031 window_copy_update_selection(wme
, 1, 0);
4032 window_copy_redraw_screen(wme
);
4036 window_copy_match_start_end(struct window_copy_mode_data
*data
, u_int at
,
4037 u_int
*start
, u_int
*end
)
4039 struct grid
*gd
= data
->backing
->grid
;
4040 u_int last
= (gd
->sy
* gd
->sx
) - 1;
4041 u_char mark
= data
->searchmark
[at
];
4044 while (*start
!= 0 && data
->searchmark
[*start
] == mark
)
4046 if (data
->searchmark
[*start
] != mark
)
4048 while (*end
!= last
&& data
->searchmark
[*end
] == mark
)
4050 if (data
->searchmark
[*end
] != mark
)
4055 window_copy_match_at_cursor(struct window_copy_mode_data
*data
)
4057 struct grid
*gd
= data
->backing
->grid
;
4058 struct grid_cell gc
;
4059 u_int at
, start
, end
, cy
, px
, py
;
4060 u_int sx
= screen_size_x(data
->backing
);
4064 if (data
->searchmark
== NULL
)
4067 cy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
4068 if (window_copy_search_mark_at(data
, data
->cx
, cy
, &at
) != 0)
4070 if (data
->searchmark
[at
] == 0) {
4071 /* Allow one position after the match. */
4072 if (at
== 0 || data
->searchmark
[--at
] == 0)
4075 window_copy_match_start_end(data
, at
, &start
, &end
);
4078 * Cells will not be set in the marked array unless they are valid text
4079 * and wrapping will be taken care of, so we can just copy.
4081 for (at
= start
; at
<= end
; at
++) {
4083 px
= at
- (py
* sx
);
4085 grid_get_cell(gd
, px
, gd
->hsize
+ py
- data
->oy
, &gc
);
4086 buf
= xrealloc(buf
, len
+ gc
.data
.size
+ 1);
4087 memcpy(buf
+ len
, gc
.data
.data
, gc
.data
.size
);
4088 len
+= gc
.data
.size
;
4096 window_copy_update_style(struct window_mode_entry
*wme
, u_int fx
, u_int fy
,
4097 struct grid_cell
*gc
, const struct grid_cell
*mgc
,
4098 const struct grid_cell
*cgc
, const struct grid_cell
*mkgc
)
4100 struct window_pane
*wp
= wme
->wp
;
4101 struct window_copy_mode_data
*data
= wme
->data
;
4102 u_int mark
, start
, end
, cy
, cursor
, current
;
4103 int inv
= 0, found
= 0;
4106 if (data
->showmark
&& fy
== data
->my
) {
4107 gc
->attr
= mkgc
->attr
;
4120 if (data
->searchmark
== NULL
)
4123 if (window_copy_search_mark_at(data
, fx
, fy
, ¤t
) != 0)
4125 mark
= data
->searchmark
[current
];
4129 cy
= screen_hsize(data
->backing
) - data
->oy
+ data
->cy
;
4130 if (window_copy_search_mark_at(data
, data
->cx
, cy
, &cursor
) == 0) {
4131 keys
= options_get_number(wp
->window
->options
, "mode-keys");
4133 keys
== MODEKEY_EMACS
&&
4134 data
->searchdirection
) {
4135 if (data
->searchmark
[cursor
- 1] == mark
) {
4139 } else if (data
->searchmark
[cursor
] == mark
)
4142 window_copy_match_start_end(data
, cursor
, &start
, &end
);
4143 if (current
>= start
&& current
<= end
) {
4144 gc
->attr
= cgc
->attr
;
4158 gc
->attr
= mgc
->attr
;
4170 window_copy_write_one(struct window_mode_entry
*wme
,
4171 struct screen_write_ctx
*ctx
, u_int py
, u_int fy
, u_int nx
,
4172 const struct grid_cell
*mgc
, const struct grid_cell
*cgc
,
4173 const struct grid_cell
*mkgc
)
4175 struct window_copy_mode_data
*data
= wme
->data
;
4176 struct grid
*gd
= data
->backing
->grid
;
4177 struct grid_cell gc
;
4180 screen_write_cursormove(ctx
, 0, py
, 0);
4181 for (fx
= 0; fx
< nx
; fx
++) {
4182 grid_get_cell(gd
, fx
, fy
, &gc
);
4183 if (fx
+ gc
.data
.width
<= nx
) {
4184 window_copy_update_style(wme
, fx
, fy
, &gc
, mgc
, cgc
,
4186 screen_write_cell(ctx
, &gc
);
4192 window_copy_get_current_offset(struct window_pane
*wp
, u_int
*offset
,
4195 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
4196 struct window_copy_mode_data
*data
= wme
->data
;
4201 hsize
= screen_hsize(data
->backing
);
4203 *offset
= hsize
- data
->oy
;
4209 window_copy_write_line(struct window_mode_entry
*wme
,
4210 struct screen_write_ctx
*ctx
, u_int py
)
4212 struct window_pane
*wp
= wme
->wp
;
4213 struct window_copy_mode_data
*data
= wme
->data
;
4214 struct screen
*s
= &data
->screen
;
4215 struct options
*oo
= wp
->window
->options
;
4216 struct grid_cell gc
, mgc
, cgc
, mkgc
;
4217 u_int sx
= screen_size_x(s
);
4218 u_int hsize
= screen_hsize(data
->backing
);
4221 struct format_tree
*ft
;
4223 style_apply(&gc
, oo
, "mode-style", NULL
);
4224 gc
.flags
|= GRID_FLAG_NOPALETTE
;
4225 style_apply(&mgc
, oo
, "copy-mode-match-style", NULL
);
4226 mgc
.flags
|= GRID_FLAG_NOPALETTE
;
4227 style_apply(&cgc
, oo
, "copy-mode-current-match-style", NULL
);
4228 cgc
.flags
|= GRID_FLAG_NOPALETTE
;
4229 style_apply(&mkgc
, oo
, "copy-mode-mark-style", NULL
);
4230 mkgc
.flags
|= GRID_FLAG_NOPALETTE
;
4232 window_copy_write_one(wme
, ctx
, py
, hsize
- data
->oy
+ py
,
4233 screen_size_x(s
), &mgc
, &cgc
, &mkgc
);
4235 if (py
== 0 && s
->rupper
< s
->rlower
&& !data
->hide_position
) {
4236 value
= options_get_string(oo
, "copy-mode-position-format");
4237 if (*value
!= '\0') {
4238 ft
= format_create_defaults(NULL
, NULL
, NULL
, NULL
, wp
);
4239 expanded
= format_expand(ft
, value
);
4240 if (*expanded
!= '\0') {
4241 screen_write_cursormove(ctx
, 0, 0, 0);
4242 format_draw(ctx
, &gc
, sx
, expanded
, NULL
, 0);
4249 if (py
== data
->cy
&& data
->cx
== screen_size_x(s
)) {
4250 screen_write_cursormove(ctx
, screen_size_x(s
) - 1, py
, 0);
4251 screen_write_putc(ctx
, &grid_default_cell
, '$');
4256 window_copy_write_lines(struct window_mode_entry
*wme
,
4257 struct screen_write_ctx
*ctx
, u_int py
, u_int ny
)
4261 for (yy
= py
; yy
< py
+ ny
; yy
++)
4262 window_copy_write_line(wme
, ctx
, py
);
4266 window_copy_redraw_selection(struct window_mode_entry
*wme
, u_int old_y
)
4268 struct window_copy_mode_data
*data
= wme
->data
;
4269 struct grid
*gd
= data
->backing
->grid
;
4270 u_int new_y
, start
, end
;
4273 if (old_y
<= new_y
) {
4282 * In word selection mode the first word on the line below the cursor
4283 * might be selected, so add this line to the redraw area.
4285 if (data
->selflag
== SEL_WORD
) {
4286 /* Last grid line in data coordinates. */
4287 if (end
< gd
->sy
+ data
->oy
- 1)
4290 window_copy_redraw_lines(wme
, start
, end
- start
+ 1);
4294 window_copy_redraw_lines(struct window_mode_entry
*wme
, u_int py
, u_int ny
)
4296 struct window_pane
*wp
= wme
->wp
;
4297 struct window_copy_mode_data
*data
= wme
->data
;
4298 struct screen_write_ctx ctx
;
4301 screen_write_start_pane(&ctx
, wp
, NULL
);
4302 for (i
= py
; i
< py
+ ny
; i
++)
4303 window_copy_write_line(wme
, &ctx
, i
);
4304 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
4305 screen_write_stop(&ctx
);
4309 window_copy_redraw_screen(struct window_mode_entry
*wme
)
4311 struct window_copy_mode_data
*data
= wme
->data
;
4313 window_copy_redraw_lines(wme
, 0, screen_size_y(&data
->screen
));
4317 window_copy_synchronize_cursor_end(struct window_mode_entry
*wme
, int begin
,
4320 struct window_copy_mode_data
*data
= wme
->data
;
4324 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4325 switch (data
->selflag
) {
4330 if (data
->dy
> yy
|| (data
->dy
== yy
&& data
->dx
> xx
)) {
4331 /* Right to left selection. */
4332 window_copy_cursor_previous_word_pos(wme
,
4333 data
->separators
, &xx
, &yy
);
4336 /* Reset the end. */
4337 data
->endselx
= data
->endselrx
;
4338 data
->endsely
= data
->endselry
;
4340 /* Left to right selection. */
4341 if (xx
>= window_copy_find_length(wme
, yy
) ||
4342 !window_copy_in_set(wme
, xx
+ 1, yy
, WHITESPACE
)) {
4343 window_copy_cursor_next_word_end_pos(wme
,
4344 data
->separators
, &xx
, &yy
);
4347 /* Reset the start. */
4348 data
->selx
= data
->selrx
;
4349 data
->sely
= data
->selry
;
4356 if (data
->dy
> yy
) {
4357 /* Right to left selection. */
4361 /* Reset the end. */
4362 data
->endselx
= data
->endselrx
;
4363 data
->endsely
= data
->endselry
;
4365 /* Left to right selection. */
4366 if (yy
< data
->endselry
)
4367 yy
= data
->endselry
;
4368 xx
= window_copy_find_length(wme
, yy
);
4370 /* Reset the start. */
4371 data
->selx
= data
->selrx
;
4372 data
->sely
= data
->selry
;
4388 window_copy_synchronize_cursor(struct window_mode_entry
*wme
, int no_reset
)
4390 struct window_copy_mode_data
*data
= wme
->data
;
4392 switch (data
->cursordrag
) {
4393 case CURSORDRAG_ENDSEL
:
4394 window_copy_synchronize_cursor_end(wme
, 0, no_reset
);
4396 case CURSORDRAG_SEL
:
4397 window_copy_synchronize_cursor_end(wme
, 1, no_reset
);
4399 case CURSORDRAG_NONE
:
4405 window_copy_update_cursor(struct window_mode_entry
*wme
, u_int cx
, u_int cy
)
4407 struct window_pane
*wp
= wme
->wp
;
4408 struct window_copy_mode_data
*data
= wme
->data
;
4409 struct screen
*s
= &data
->screen
;
4410 struct screen_write_ctx ctx
;
4411 u_int old_cx
, old_cy
;
4413 old_cx
= data
->cx
; old_cy
= data
->cy
;
4414 data
->cx
= cx
; data
->cy
= cy
;
4415 if (old_cx
== screen_size_x(s
))
4416 window_copy_redraw_lines(wme
, old_cy
, 1);
4417 if (data
->cx
== screen_size_x(s
))
4418 window_copy_redraw_lines(wme
, data
->cy
, 1);
4420 screen_write_start_pane(&ctx
, wp
, NULL
);
4421 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
4422 screen_write_stop(&ctx
);
4427 window_copy_start_selection(struct window_mode_entry
*wme
)
4429 struct window_copy_mode_data
*data
= wme
->data
;
4431 data
->selx
= data
->cx
;
4432 data
->sely
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4434 data
->endselx
= data
->selx
;
4435 data
->endsely
= data
->sely
;
4437 data
->cursordrag
= CURSORDRAG_ENDSEL
;
4439 window_copy_set_selection(wme
, 1, 0);
4443 window_copy_adjust_selection(struct window_mode_entry
*wme
, u_int
*selx
,
4446 struct window_copy_mode_data
*data
= wme
->data
;
4447 struct screen
*s
= &data
->screen
;
4454 ty
= screen_hsize(data
->backing
) - data
->oy
;
4456 relpos
= WINDOW_COPY_REL_POS_ABOVE
;
4457 if (!data
->rectflag
)
4460 } else if (sy
> ty
+ screen_size_y(s
) - 1) {
4461 relpos
= WINDOW_COPY_REL_POS_BELOW
;
4462 if (!data
->rectflag
)
4463 sx
= screen_size_x(s
) - 1;
4464 sy
= screen_size_y(s
) - 1;
4466 relpos
= WINDOW_COPY_REL_POS_ON_SCREEN
;
4476 window_copy_update_selection(struct window_mode_entry
*wme
, int may_redraw
,
4479 struct window_copy_mode_data
*data
= wme
->data
;
4480 struct screen
*s
= &data
->screen
;
4482 if (s
->sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
)
4484 return (window_copy_set_selection(wme
, may_redraw
, no_reset
));
4488 window_copy_set_selection(struct window_mode_entry
*wme
, int may_redraw
,
4491 struct window_pane
*wp
= wme
->wp
;
4492 struct window_copy_mode_data
*data
= wme
->data
;
4493 struct screen
*s
= &data
->screen
;
4494 struct options
*oo
= wp
->window
->options
;
4495 struct grid_cell gc
;
4496 u_int sx
, sy
, cy
, endsx
, endsy
;
4497 int startrelpos
, endrelpos
;
4499 window_copy_synchronize_cursor(wme
, no_reset
);
4501 /* Adjust the selection. */
4504 startrelpos
= window_copy_adjust_selection(wme
, &sx
, &sy
);
4506 /* Adjust the end of selection. */
4507 endsx
= data
->endselx
;
4508 endsy
= data
->endsely
;
4509 endrelpos
= window_copy_adjust_selection(wme
, &endsx
, &endsy
);
4511 /* Selection is outside of the current screen */
4512 if (startrelpos
== endrelpos
&&
4513 startrelpos
!= WINDOW_COPY_REL_POS_ON_SCREEN
) {
4514 screen_hide_selection(s
);
4518 /* Set colours and selection. */
4519 style_apply(&gc
, oo
, "mode-style", NULL
);
4520 gc
.flags
|= GRID_FLAG_NOPALETTE
;
4521 screen_set_selection(s
, sx
, sy
, endsx
, endsy
, data
->rectflag
,
4522 data
->modekeys
, &gc
);
4524 if (data
->rectflag
&& may_redraw
) {
4526 * Can't rely on the caller to redraw the right lines for
4527 * rectangle selection - find the highest line and the number
4528 * of lines, and redraw just past that in both directions
4531 if (data
->cursordrag
== CURSORDRAG_ENDSEL
) {
4533 window_copy_redraw_lines(wme
, sy
, cy
- sy
+ 1);
4535 window_copy_redraw_lines(wme
, cy
, sy
- cy
+ 1);
4538 window_copy_redraw_lines(wme
, endsy
,
4541 window_copy_redraw_lines(wme
, cy
,
4551 window_copy_get_selection(struct window_mode_entry
*wme
, size_t *len
)
4553 struct window_pane
*wp
= wme
->wp
;
4554 struct window_copy_mode_data
*data
= wme
->data
;
4555 struct screen
*s
= &data
->screen
;
4558 u_int i
, xx
, yy
, sx
, sy
, ex
, ey
, ey_last
;
4559 u_int firstsx
, lastex
, restex
, restsx
, selx
;
4562 if (data
->screen
.sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
) {
4563 buf
= window_copy_match_at_cursor(data
);
4577 * The selection extends from selx,sely to (adjusted) cx,cy on
4581 /* Find start and end. */
4584 if (yy
< data
->sely
|| (yy
== data
->sely
&& xx
< data
->selx
)) {
4586 ex
= data
->selx
; ey
= data
->sely
;
4588 sx
= data
->selx
; sy
= data
->sely
;
4592 /* Trim ex to end of line. */
4593 ey_last
= window_copy_find_length(wme
, ey
);
4598 * Deal with rectangle-copy if necessary; four situations: start of
4599 * first line (firstsx), end of last line (lastex), start (restsx) and
4600 * end (restex) of all other lines.
4602 xx
= screen_size_x(s
);
4605 * Behave according to mode-keys. If it is emacs, copy like emacs,
4606 * keeping the top-left-most character, and dropping the
4607 * bottom-right-most, regardless of copy direction. If it is vi, also
4608 * keep bottom-right-most character.
4610 keys
= options_get_number(wp
->window
->options
, "mode-keys");
4611 if (data
->rectflag
) {
4613 * Need to ignore the column with the cursor in it, which for
4614 * rectangular copy means knowing which side the cursor is on.
4616 if (data
->cursordrag
== CURSORDRAG_ENDSEL
)
4619 selx
= data
->endselx
;
4620 if (selx
< data
->cx
) {
4621 /* Selection start is on the left. */
4622 if (keys
== MODEKEY_EMACS
) {
4627 lastex
= data
->cx
+ 1;
4628 restex
= data
->cx
+ 1;
4633 /* Cursor is on the left. */
4640 if (keys
== MODEKEY_EMACS
)
4649 /* Copy the lines. */
4650 for (i
= sy
; i
<= ey
; i
++) {
4651 window_copy_copy_line(wme
, &buf
, &off
, i
,
4652 (i
== sy
? firstsx
: restsx
),
4653 (i
== ey
? lastex
: restex
));
4656 /* Don't bother if no data. */
4662 /* Remove final \n (unless at end in vi mode). */
4663 if (keys
== MODEKEY_EMACS
|| lastex
<= ey_last
) {
4664 if (~grid_get_line(data
->backing
->grid
, ey
)->flags
&
4665 GRID_LINE_WRAPPED
|| lastex
!= ey_last
)
4673 window_copy_copy_buffer(struct window_mode_entry
*wme
, const char *prefix
,
4674 void *buf
, size_t len
, int set_paste
, int set_clip
)
4676 struct window_pane
*wp
= wme
->wp
;
4677 struct screen_write_ctx ctx
;
4680 options_get_number(global_options
, "set-clipboard") != 0) {
4681 screen_write_start_pane(&ctx
, wp
, NULL
);
4682 screen_write_setselection(&ctx
, "", buf
, len
);
4683 screen_write_stop(&ctx
);
4684 notify_pane("pane-set-clipboard", wp
);
4688 paste_add(prefix
, buf
, len
);
4692 window_copy_pipe_run(struct window_mode_entry
*wme
, struct session
*s
,
4693 const char *cmd
, size_t *len
)
4698 buf
= window_copy_get_selection(wme
, len
);
4699 if (cmd
== NULL
|| *cmd
== '\0')
4700 cmd
= options_get_string(global_options
, "copy-command");
4701 if (cmd
!= NULL
&& *cmd
!= '\0') {
4702 job
= job_run(cmd
, 0, NULL
, NULL
, s
, NULL
, NULL
, NULL
, NULL
,
4703 NULL
, JOB_NOWAIT
, -1, -1);
4704 bufferevent_write(job_get_event(job
), buf
, *len
);
4710 window_copy_pipe(struct window_mode_entry
*wme
, struct session
*s
,
4715 window_copy_pipe_run(wme
, s
, cmd
, &len
);
4719 window_copy_copy_pipe(struct window_mode_entry
*wme
, struct session
*s
,
4720 const char *prefix
, const char *cmd
, int set_paste
, int set_clip
)
4725 buf
= window_copy_pipe_run(wme
, s
, cmd
, &len
);
4727 window_copy_copy_buffer(wme
, prefix
, buf
, len
, set_paste
,
4732 window_copy_copy_selection(struct window_mode_entry
*wme
, const char *prefix
,
4733 int set_paste
, int set_clip
)
4738 buf
= window_copy_get_selection(wme
, &len
);
4740 window_copy_copy_buffer(wme
, prefix
, buf
, len
, set_paste
,
4745 window_copy_append_selection(struct window_mode_entry
*wme
)
4747 struct window_pane
*wp
= wme
->wp
;
4749 struct paste_buffer
*pb
;
4750 const char *bufdata
, *bufname
= NULL
;
4751 size_t len
, bufsize
;
4752 struct screen_write_ctx ctx
;
4754 buf
= window_copy_get_selection(wme
, &len
);
4758 if (options_get_number(global_options
, "set-clipboard") != 0) {
4759 screen_write_start_pane(&ctx
, wp
, NULL
);
4760 screen_write_setselection(&ctx
, "", buf
, len
);
4761 screen_write_stop(&ctx
);
4762 notify_pane("pane-set-clipboard", wp
);
4765 pb
= paste_get_top(&bufname
);
4767 bufdata
= paste_buffer_data(pb
, &bufsize
);
4768 buf
= xrealloc(buf
, len
+ bufsize
);
4769 memmove(buf
+ bufsize
, buf
, len
);
4770 memcpy(buf
, bufdata
, bufsize
);
4773 if (paste_set(buf
, len
, bufname
, NULL
) != 0)
4778 window_copy_copy_line(struct window_mode_entry
*wme
, char **buf
, size_t *off
,
4779 u_int sy
, u_int sx
, u_int ex
)
4781 struct window_copy_mode_data
*data
= wme
->data
;
4782 struct grid
*gd
= data
->backing
->grid
;
4783 struct grid_cell gc
;
4784 struct grid_line
*gl
;
4785 struct utf8_data ud
;
4786 u_int i
, xx
, wrapped
= 0;
4793 * Work out if the line was wrapped at the screen edge and all of it is
4796 gl
= grid_get_line(gd
, sy
);
4797 if (gl
->flags
& GRID_LINE_WRAPPED
&& gl
->cellsize
<= gd
->sx
)
4800 /* If the line was wrapped, don't strip spaces (use the full length). */
4804 xx
= window_copy_find_length(wme
, sy
);
4811 for (i
= sx
; i
< ex
; i
++) {
4812 grid_get_cell(gd
, i
, sy
, &gc
);
4813 if (gc
.flags
& GRID_FLAG_PADDING
)
4815 utf8_copy(&ud
, &gc
.data
);
4816 if (ud
.size
== 1 && (gc
.attr
& GRID_ATTR_CHARSET
)) {
4817 s
= tty_acs_get(NULL
, ud
.data
[0]);
4818 if (s
!= NULL
&& strlen(s
) <= sizeof ud
.data
) {
4819 ud
.size
= strlen(s
);
4820 memcpy(ud
.data
, s
, ud
.size
);
4824 *buf
= xrealloc(*buf
, (*off
) + ud
.size
);
4825 memcpy(*buf
+ *off
, ud
.data
, ud
.size
);
4830 /* Only add a newline if the line wasn't wrapped. */
4831 if (!wrapped
|| ex
!= xx
) {
4832 *buf
= xrealloc(*buf
, (*off
) + 1);
4833 (*buf
)[(*off
)++] = '\n';
4838 window_copy_clear_selection(struct window_mode_entry
*wme
)
4840 struct window_copy_mode_data
*data
= wme
->data
;
4843 screen_clear_selection(&data
->screen
);
4845 data
->cursordrag
= CURSORDRAG_NONE
;
4846 data
->lineflag
= LINE_SEL_NONE
;
4847 data
->selflag
= SEL_CHAR
;
4849 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4850 px
= window_copy_find_length(wme
, py
);
4852 window_copy_update_cursor(wme
, px
, data
->cy
);
4856 window_copy_in_set(struct window_mode_entry
*wme
, u_int px
, u_int py
,
4859 struct window_copy_mode_data
*data
= wme
->data
;
4860 struct grid_cell gc
;
4862 grid_get_cell(data
->backing
->grid
, px
, py
, &gc
);
4863 if (gc
.flags
& GRID_FLAG_PADDING
)
4865 return (utf8_cstrhas(set
, &gc
.data
));
4869 window_copy_find_length(struct window_mode_entry
*wme
, u_int py
)
4871 struct window_copy_mode_data
*data
= wme
->data
;
4873 return (grid_line_length(data
->backing
->grid
, py
));
4877 window_copy_cursor_start_of_line(struct window_mode_entry
*wme
)
4879 struct window_copy_mode_data
*data
= wme
->data
;
4880 struct screen
*back_s
= data
->backing
;
4881 struct grid_reader gr
;
4882 u_int px
, py
, oldy
, hsize
;
4885 hsize
= screen_hsize(back_s
);
4886 py
= hsize
+ data
->cy
- data
->oy
;
4889 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4890 grid_reader_cursor_start_of_line(&gr
, 1);
4891 grid_reader_get_cursor(&gr
, &px
, &py
);
4892 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
4896 window_copy_cursor_back_to_indentation(struct window_mode_entry
*wme
)
4898 struct window_copy_mode_data
*data
= wme
->data
;
4899 struct screen
*back_s
= data
->backing
;
4900 struct grid_reader gr
;
4901 u_int px
, py
, oldy
, hsize
;
4904 hsize
= screen_hsize(back_s
);
4905 py
= hsize
+ data
->cy
- data
->oy
;
4908 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4909 grid_reader_cursor_back_to_indentation(&gr
);
4910 grid_reader_get_cursor(&gr
, &px
, &py
);
4911 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
4915 window_copy_cursor_end_of_line(struct window_mode_entry
*wme
)
4917 struct window_copy_mode_data
*data
= wme
->data
;
4918 struct screen
*back_s
= data
->backing
;
4919 struct grid_reader gr
;
4920 u_int px
, py
, oldy
, hsize
;
4923 hsize
= screen_hsize(back_s
);
4924 py
= hsize
+ data
->cy
- data
->oy
;
4927 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
4928 if (data
->screen
.sel
!= NULL
&& data
->rectflag
)
4929 grid_reader_cursor_end_of_line(&gr
, 1, 1);
4931 grid_reader_cursor_end_of_line(&gr
, 1, 0);
4932 grid_reader_get_cursor(&gr
, &px
, &py
);
4933 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
4934 data
->oy
, oldy
, px
, py
, 0);
4938 window_copy_other_end(struct window_mode_entry
*wme
)
4940 struct window_copy_mode_data
*data
= wme
->data
;
4941 struct screen
*s
= &data
->screen
;
4942 u_int selx
, sely
, cy
, yy
, hsize
;
4944 if (s
->sel
== NULL
&& data
->lineflag
== LINE_SEL_NONE
)
4947 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
4948 data
->lineflag
= LINE_SEL_RIGHT_LEFT
;
4949 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
4950 data
->lineflag
= LINE_SEL_LEFT_RIGHT
;
4952 switch (data
->cursordrag
) {
4953 case CURSORDRAG_NONE
:
4954 case CURSORDRAG_SEL
:
4955 data
->cursordrag
= CURSORDRAG_ENDSEL
;
4957 case CURSORDRAG_ENDSEL
:
4958 data
->cursordrag
= CURSORDRAG_SEL
;
4962 selx
= data
->endselx
;
4963 sely
= data
->endsely
;
4964 if (data
->cursordrag
== CURSORDRAG_SEL
) {
4970 yy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
4974 hsize
= screen_hsize(data
->backing
);
4975 if (sely
< hsize
- data
->oy
) { /* above */
4976 data
->oy
= hsize
- sely
;
4978 } else if (sely
> hsize
- data
->oy
+ screen_size_y(s
)) { /* below */
4979 data
->oy
= hsize
- sely
+ screen_size_y(s
) - 1;
4980 data
->cy
= screen_size_y(s
) - 1;
4982 data
->cy
= cy
+ sely
- yy
;
4984 window_copy_update_selection(wme
, 1, 1);
4985 window_copy_redraw_screen(wme
);
4989 window_copy_cursor_left(struct window_mode_entry
*wme
)
4991 struct window_copy_mode_data
*data
= wme
->data
;
4992 struct screen
*back_s
= data
->backing
;
4993 struct grid_reader gr
;
4994 u_int px
, py
, oldy
, hsize
;
4997 hsize
= screen_hsize(back_s
);
4998 py
= hsize
+ data
->cy
- data
->oy
;
5001 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5002 grid_reader_cursor_left(&gr
, 1);
5003 grid_reader_get_cursor(&gr
, &px
, &py
);
5004 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
5008 window_copy_cursor_right(struct window_mode_entry
*wme
, int all
)
5010 struct window_copy_mode_data
*data
= wme
->data
;
5011 struct screen
*back_s
= data
->backing
;
5012 struct grid_reader gr
;
5013 u_int px
, py
, oldy
, hsize
;
5016 hsize
= screen_hsize(back_s
);
5017 py
= hsize
+ data
->cy
- data
->oy
;
5020 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5021 grid_reader_cursor_right(&gr
, 1, all
);
5022 grid_reader_get_cursor(&gr
, &px
, &py
);
5023 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
5024 data
->oy
, oldy
, px
, py
, 0);
5028 window_copy_cursor_up(struct window_mode_entry
*wme
, int scroll_only
)
5030 struct window_copy_mode_data
*data
= wme
->data
;
5031 struct screen
*s
= &data
->screen
;
5032 u_int ox
, oy
, px
, py
;
5035 norectsel
= data
->screen
.sel
== NULL
|| !data
->rectflag
;
5036 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5037 ox
= window_copy_find_length(wme
, oy
);
5038 if (norectsel
&& data
->cx
!= ox
) {
5039 data
->lastcx
= data
->cx
;
5043 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
&& oy
== data
->sely
)
5044 window_copy_other_end(wme
);
5046 if (scroll_only
|| data
->cy
== 0) {
5048 data
->cx
= data
->lastcx
;
5049 window_copy_scroll_down(wme
, 1);
5051 if (data
->cy
== screen_size_y(s
) - 1)
5052 window_copy_redraw_lines(wme
, data
->cy
, 1);
5054 window_copy_redraw_lines(wme
, data
->cy
, 2);
5058 window_copy_update_cursor(wme
, data
->lastcx
,
5061 window_copy_update_cursor(wme
, data
->cx
, data
->cy
- 1);
5062 if (window_copy_update_selection(wme
, 1, 0)) {
5063 if (data
->cy
== screen_size_y(s
) - 1)
5064 window_copy_redraw_lines(wme
, data
->cy
, 1);
5066 window_copy_redraw_lines(wme
, data
->cy
, 2);
5071 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5072 px
= window_copy_find_length(wme
, py
);
5073 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
5076 window_copy_update_cursor(wme
, px
, data
->cy
);
5077 if (window_copy_update_selection(wme
, 1, 0))
5078 window_copy_redraw_lines(wme
, data
->cy
, 1);
5082 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
5084 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5086 px
= screen_size_x(data
->backing
);
5088 px
= window_copy_find_length(wme
, py
);
5089 window_copy_update_cursor(wme
, px
, data
->cy
);
5090 if (window_copy_update_selection(wme
, 1, 0))
5091 window_copy_redraw_lines(wme
, data
->cy
, 1);
5093 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
5095 window_copy_update_cursor(wme
, 0, data
->cy
);
5096 if (window_copy_update_selection(wme
, 1, 0))
5097 window_copy_redraw_lines(wme
, data
->cy
, 1);
5102 window_copy_cursor_down(struct window_mode_entry
*wme
, int scroll_only
)
5104 struct window_copy_mode_data
*data
= wme
->data
;
5105 struct screen
*s
= &data
->screen
;
5106 u_int ox
, oy
, px
, py
;
5109 norectsel
= data
->screen
.sel
== NULL
|| !data
->rectflag
;
5110 oy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5111 ox
= window_copy_find_length(wme
, oy
);
5112 if (norectsel
&& data
->cx
!= ox
) {
5113 data
->lastcx
= data
->cx
;
5117 if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
&& oy
== data
->endsely
)
5118 window_copy_other_end(wme
);
5120 if (scroll_only
|| data
->cy
== screen_size_y(s
) - 1) {
5122 data
->cx
= data
->lastcx
;
5123 window_copy_scroll_up(wme
, 1);
5124 if (scroll_only
&& data
->cy
> 0)
5125 window_copy_redraw_lines(wme
, data
->cy
- 1, 2);
5128 window_copy_update_cursor(wme
, data
->lastcx
,
5131 window_copy_update_cursor(wme
, data
->cx
, data
->cy
+ 1);
5132 if (window_copy_update_selection(wme
, 1, 0))
5133 window_copy_redraw_lines(wme
, data
->cy
- 1, 2);
5137 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5138 px
= window_copy_find_length(wme
, py
);
5139 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
5142 window_copy_update_cursor(wme
, px
, data
->cy
);
5143 if (window_copy_update_selection(wme
, 1, 0))
5144 window_copy_redraw_lines(wme
, data
->cy
, 1);
5148 if (data
->lineflag
== LINE_SEL_LEFT_RIGHT
)
5150 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5152 px
= screen_size_x(data
->backing
);
5154 px
= window_copy_find_length(wme
, py
);
5155 window_copy_update_cursor(wme
, px
, data
->cy
);
5156 if (window_copy_update_selection(wme
, 1, 0))
5157 window_copy_redraw_lines(wme
, data
->cy
, 1);
5159 else if (data
->lineflag
== LINE_SEL_RIGHT_LEFT
)
5161 window_copy_update_cursor(wme
, 0, data
->cy
);
5162 if (window_copy_update_selection(wme
, 1, 0))
5163 window_copy_redraw_lines(wme
, data
->cy
, 1);
5168 window_copy_cursor_jump(struct window_mode_entry
*wme
)
5170 struct window_copy_mode_data
*data
= wme
->data
;
5171 struct screen
*back_s
= data
->backing
;
5172 struct grid_reader gr
;
5173 u_int px
, py
, oldy
, hsize
;
5176 hsize
= screen_hsize(back_s
);
5177 py
= hsize
+ data
->cy
- data
->oy
;
5180 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5181 if (grid_reader_cursor_jump(&gr
, data
->jumpchar
)) {
5182 grid_reader_get_cursor(&gr
, &px
, &py
);
5183 window_copy_acquire_cursor_down(wme
, hsize
,
5184 screen_size_y(back_s
), data
->oy
, oldy
, px
, py
, 0);
5189 window_copy_cursor_jump_back(struct window_mode_entry
*wme
)
5191 struct window_copy_mode_data
*data
= wme
->data
;
5192 struct screen
*back_s
= data
->backing
;
5193 struct grid_reader gr
;
5194 u_int px
, py
, oldy
, hsize
;
5197 hsize
= screen_hsize(back_s
);
5198 py
= hsize
+ data
->cy
- data
->oy
;
5201 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5202 grid_reader_cursor_left(&gr
, 0);
5203 if (grid_reader_cursor_jump_back(&gr
, data
->jumpchar
)) {
5204 grid_reader_get_cursor(&gr
, &px
, &py
);
5205 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
,
5211 window_copy_cursor_jump_to(struct window_mode_entry
*wme
)
5213 struct window_copy_mode_data
*data
= wme
->data
;
5214 struct screen
*back_s
= data
->backing
;
5215 struct grid_reader gr
;
5216 u_int px
, py
, oldy
, hsize
;
5219 hsize
= screen_hsize(back_s
);
5220 py
= hsize
+ data
->cy
- data
->oy
;
5223 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5224 if (grid_reader_cursor_jump(&gr
, data
->jumpchar
)) {
5225 grid_reader_cursor_left(&gr
, 1);
5226 grid_reader_get_cursor(&gr
, &px
, &py
);
5227 window_copy_acquire_cursor_down(wme
, hsize
,
5228 screen_size_y(back_s
), data
->oy
, oldy
, px
, py
, 0);
5233 window_copy_cursor_jump_to_back(struct window_mode_entry
*wme
)
5235 struct window_copy_mode_data
*data
= wme
->data
;
5236 struct screen
*back_s
= data
->backing
;
5237 struct grid_reader gr
;
5238 u_int px
, py
, oldy
, hsize
;
5241 hsize
= screen_hsize(back_s
);
5242 py
= hsize
+ data
->cy
- data
->oy
;
5245 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5246 grid_reader_cursor_left(&gr
, 0);
5247 grid_reader_cursor_left(&gr
, 0);
5248 if (grid_reader_cursor_jump_back(&gr
, data
->jumpchar
)) {
5249 grid_reader_cursor_right(&gr
, 1, 0);
5250 grid_reader_get_cursor(&gr
, &px
, &py
);
5251 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
,
5257 window_copy_cursor_next_word(struct window_mode_entry
*wme
,
5258 const char *separators
)
5260 struct window_copy_mode_data
*data
= wme
->data
;
5261 struct screen
*back_s
= data
->backing
;
5262 struct grid_reader gr
;
5263 u_int px
, py
, oldy
, hsize
;
5266 hsize
= screen_hsize(back_s
);
5267 py
= hsize
+ data
->cy
- data
->oy
;
5270 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5271 grid_reader_cursor_next_word(&gr
, separators
);
5272 grid_reader_get_cursor(&gr
, &px
, &py
);
5273 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
5274 data
->oy
, oldy
, px
, py
, 0);
5277 /* Compute the next place where a word ends. */
5279 window_copy_cursor_next_word_end_pos(struct window_mode_entry
*wme
,
5280 const char *separators
, u_int
*ppx
, u_int
*ppy
)
5282 struct window_pane
*wp
= wme
->wp
;
5283 struct window_copy_mode_data
*data
= wme
->data
;
5284 struct options
*oo
= wp
->window
->options
;
5285 struct screen
*back_s
= data
->backing
;
5286 struct grid_reader gr
;
5287 u_int px
, py
, hsize
;
5290 hsize
= screen_hsize(back_s
);
5291 py
= hsize
+ data
->cy
- data
->oy
;
5293 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5294 if (options_get_number(oo
, "mode-keys") == MODEKEY_VI
) {
5295 if (!grid_reader_in_set(&gr
, WHITESPACE
))
5296 grid_reader_cursor_right(&gr
, 0, 0);
5297 grid_reader_cursor_next_word_end(&gr
, separators
);
5298 grid_reader_cursor_left(&gr
, 1);
5300 grid_reader_cursor_next_word_end(&gr
, separators
);
5301 grid_reader_get_cursor(&gr
, &px
, &py
);
5306 /* Move to the next place where a word ends. */
5308 window_copy_cursor_next_word_end(struct window_mode_entry
*wme
,
5309 const char *separators
, int no_reset
)
5311 struct window_pane
*wp
= wme
->wp
;
5312 struct window_copy_mode_data
*data
= wme
->data
;
5313 struct options
*oo
= wp
->window
->options
;
5314 struct screen
*back_s
= data
->backing
;
5315 struct grid_reader gr
;
5316 u_int px
, py
, oldy
, hsize
;
5319 hsize
= screen_hsize(back_s
);
5320 py
= hsize
+ data
->cy
- data
->oy
;
5323 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5324 if (options_get_number(oo
, "mode-keys") == MODEKEY_VI
) {
5325 if (!grid_reader_in_set(&gr
, WHITESPACE
))
5326 grid_reader_cursor_right(&gr
, 0, 0);
5327 grid_reader_cursor_next_word_end(&gr
, separators
);
5328 grid_reader_cursor_left(&gr
, 1);
5330 grid_reader_cursor_next_word_end(&gr
, separators
);
5331 grid_reader_get_cursor(&gr
, &px
, &py
);
5332 window_copy_acquire_cursor_down(wme
, hsize
, screen_size_y(back_s
),
5333 data
->oy
, oldy
, px
, py
, no_reset
);
5336 /* Compute the previous place where a word begins. */
5338 window_copy_cursor_previous_word_pos(struct window_mode_entry
*wme
,
5339 const char *separators
, u_int
*ppx
, u_int
*ppy
)
5341 struct window_copy_mode_data
*data
= wme
->data
;
5342 struct screen
*back_s
= data
->backing
;
5343 struct grid_reader gr
;
5344 u_int px
, py
, hsize
;
5347 hsize
= screen_hsize(back_s
);
5348 py
= hsize
+ data
->cy
- data
->oy
;
5350 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5351 grid_reader_cursor_previous_word(&gr
, separators
, /* already= */ 0,
5352 /* stop_at_eol= */ 1);
5353 grid_reader_get_cursor(&gr
, &px
, &py
);
5358 /* Move to the previous place where a word begins. */
5360 window_copy_cursor_previous_word(struct window_mode_entry
*wme
,
5361 const char *separators
, int already
)
5363 struct window_copy_mode_data
*data
= wme
->data
;
5364 struct window
*w
= wme
->wp
->window
;
5365 struct screen
*back_s
= data
->backing
;
5366 struct grid_reader gr
;
5367 u_int px
, py
, oldy
, hsize
;
5370 if (options_get_number(w
->options
, "mode-keys") == MODEKEY_EMACS
)
5376 hsize
= screen_hsize(back_s
);
5377 py
= hsize
+ data
->cy
- data
->oy
;
5380 grid_reader_start(&gr
, back_s
->grid
, px
, py
);
5381 grid_reader_cursor_previous_word(&gr
, separators
, already
, stop_at_eol
);
5382 grid_reader_get_cursor(&gr
, &px
, &py
);
5383 window_copy_acquire_cursor_up(wme
, hsize
, data
->oy
, oldy
, px
, py
);
5387 window_copy_cursor_prompt(struct window_mode_entry
*wme
, int direction
,
5390 struct window_copy_mode_data
*data
= wme
->data
;
5391 struct screen
*s
= data
->backing
;
5392 struct grid
*gd
= s
->grid
;
5394 u_int line
= gd
->hsize
- data
->oy
+ data
->cy
;
5398 line_flag
= GRID_LINE_START_OUTPUT
;
5400 line_flag
= GRID_LINE_START_PROMPT
;
5402 if (direction
== 0) { /* up */
5407 end_line
= gd
->hsize
+ gd
->sy
- 1;
5410 if (line
== end_line
)
5413 if (line
== end_line
)
5417 if (grid_get_line(gd
, line
)->flags
& line_flag
)
5422 if (line
> gd
->hsize
) {
5423 data
->cy
= line
- gd
->hsize
;
5427 data
->oy
= gd
->hsize
- line
;
5430 window_copy_update_selection(wme
, 1, 0);
5431 window_copy_redraw_screen(wme
);
5435 window_copy_scroll_up(struct window_mode_entry
*wme
, u_int ny
)
5437 struct window_pane
*wp
= wme
->wp
;
5438 struct window_copy_mode_data
*data
= wme
->data
;
5439 struct screen
*s
= &data
->screen
;
5440 struct screen_write_ctx ctx
;
5448 if (data
->searchmark
!= NULL
&& !data
->timeout
)
5449 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
5450 window_copy_update_selection(wme
, 0, 0);
5452 screen_write_start_pane(&ctx
, wp
, NULL
);
5453 screen_write_cursormove(&ctx
, 0, 0, 0);
5454 screen_write_deleteline(&ctx
, ny
, 8);
5455 window_copy_write_lines(wme
, &ctx
, screen_size_y(s
) - ny
, ny
);
5456 window_copy_write_line(wme
, &ctx
, 0);
5457 if (screen_size_y(s
) > 1)
5458 window_copy_write_line(wme
, &ctx
, 1);
5459 if (screen_size_y(s
) > 3)
5460 window_copy_write_line(wme
, &ctx
, screen_size_y(s
) - 2);
5461 if (s
->sel
!= NULL
&& screen_size_y(s
) > ny
)
5462 window_copy_write_line(wme
, &ctx
, screen_size_y(s
) - ny
- 1);
5463 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
5464 screen_write_stop(&ctx
);
5468 window_copy_scroll_down(struct window_mode_entry
*wme
, u_int ny
)
5470 struct window_pane
*wp
= wme
->wp
;
5471 struct window_copy_mode_data
*data
= wme
->data
;
5472 struct screen
*s
= &data
->screen
;
5473 struct screen_write_ctx ctx
;
5475 if (ny
> screen_hsize(data
->backing
))
5478 if (data
->oy
> screen_hsize(data
->backing
) - ny
)
5479 ny
= screen_hsize(data
->backing
) - data
->oy
;
5484 if (data
->searchmark
!= NULL
&& !data
->timeout
)
5485 window_copy_search_marks(wme
, NULL
, data
->searchregex
, 1);
5486 window_copy_update_selection(wme
, 0, 0);
5488 screen_write_start_pane(&ctx
, wp
, NULL
);
5489 screen_write_cursormove(&ctx
, 0, 0, 0);
5490 screen_write_insertline(&ctx
, ny
, 8);
5491 window_copy_write_lines(wme
, &ctx
, 0, ny
);
5492 if (s
->sel
!= NULL
&& screen_size_y(s
) > ny
)
5493 window_copy_write_line(wme
, &ctx
, ny
);
5494 else if (ny
== 1) /* nuke position */
5495 window_copy_write_line(wme
, &ctx
, 1);
5496 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
, 0);
5497 screen_write_stop(&ctx
);
5501 window_copy_rectangle_set(struct window_mode_entry
*wme
, int rectflag
)
5503 struct window_copy_mode_data
*data
= wme
->data
;
5506 data
->rectflag
= rectflag
;
5508 py
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5509 px
= window_copy_find_length(wme
, py
);
5511 window_copy_update_cursor(wme
, px
, data
->cy
);
5513 window_copy_update_selection(wme
, 1, 0);
5514 window_copy_redraw_screen(wme
);
5518 window_copy_move_mouse(struct mouse_event
*m
)
5520 struct window_pane
*wp
;
5521 struct window_mode_entry
*wme
;
5524 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5527 wme
= TAILQ_FIRST(&wp
->modes
);
5530 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5533 if (cmd_mouse_at(wp
, m
, &x
, &y
, 0) != 0)
5536 window_copy_update_cursor(wme
, x
, y
);
5540 window_copy_start_drag(struct client
*c
, struct mouse_event
*m
)
5542 struct window_pane
*wp
;
5543 struct window_mode_entry
*wme
;
5544 struct window_copy_mode_data
*data
;
5550 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5553 wme
= TAILQ_FIRST(&wp
->modes
);
5556 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5559 if (cmd_mouse_at(wp
, m
, &x
, &y
, 1) != 0)
5562 c
->tty
.mouse_drag_update
= window_copy_drag_update
;
5563 c
->tty
.mouse_drag_release
= window_copy_drag_release
;
5566 yg
= screen_hsize(data
->backing
) + y
- data
->oy
;
5567 if (x
< data
->selrx
|| x
> data
->endselrx
|| yg
!= data
->selry
)
5568 data
->selflag
= SEL_CHAR
;
5569 switch (data
->selflag
) {
5571 if (data
->separators
!= NULL
) {
5572 window_copy_update_cursor(wme
, x
, y
);
5573 window_copy_cursor_previous_word_pos(wme
,
5574 data
->separators
, &x
, &y
);
5575 y
-= screen_hsize(data
->backing
) - data
->oy
;
5577 window_copy_update_cursor(wme
, x
, y
);
5580 window_copy_update_cursor(wme
, 0, y
);
5583 window_copy_update_cursor(wme
, x
, y
);
5584 window_copy_start_selection(wme
);
5588 window_copy_redraw_screen(wme
);
5589 window_copy_drag_update(c
, m
);
5593 window_copy_drag_update(struct client
*c
, struct mouse_event
*m
)
5595 struct window_pane
*wp
;
5596 struct window_mode_entry
*wme
;
5597 struct window_copy_mode_data
*data
;
5598 u_int x
, y
, old_cx
, old_cy
;
5599 struct timeval tv
= {
5600 .tv_usec
= WINDOW_COPY_DRAG_REPEAT_TIME
5606 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5609 wme
= TAILQ_FIRST(&wp
->modes
);
5612 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5616 evtimer_del(&data
->dragtimer
);
5618 if (cmd_mouse_at(wp
, m
, &x
, &y
, 0) != 0)
5623 window_copy_update_cursor(wme
, x
, y
);
5624 if (window_copy_update_selection(wme
, 1, 0))
5625 window_copy_redraw_selection(wme
, old_cy
);
5626 if (old_cy
!= data
->cy
|| old_cx
== data
->cx
) {
5628 evtimer_add(&data
->dragtimer
, &tv
);
5629 window_copy_cursor_up(wme
, 1);
5630 } else if (y
== screen_size_y(&data
->screen
) - 1) {
5631 evtimer_add(&data
->dragtimer
, &tv
);
5632 window_copy_cursor_down(wme
, 1);
5638 window_copy_drag_release(struct client
*c
, struct mouse_event
*m
)
5640 struct window_pane
*wp
;
5641 struct window_mode_entry
*wme
;
5642 struct window_copy_mode_data
*data
;
5647 wp
= cmd_mouse_pane(m
, NULL
, NULL
);
5650 wme
= TAILQ_FIRST(&wp
->modes
);
5653 if (wme
->mode
!= &window_copy_mode
&& wme
->mode
!= &window_view_mode
)
5657 evtimer_del(&data
->dragtimer
);
5661 window_copy_jump_to_mark(struct window_mode_entry
*wme
)
5663 struct window_copy_mode_data
*data
= wme
->data
;
5667 tmy
= screen_hsize(data
->backing
) + data
->cy
- data
->oy
;
5668 data
->cx
= data
->mx
;
5669 if (data
->my
< screen_hsize(data
->backing
)) {
5671 data
->oy
= screen_hsize(data
->backing
) - data
->my
;
5673 data
->cy
= data
->my
- screen_hsize(data
->backing
);
5679 window_copy_update_selection(wme
, 0, 0);
5680 window_copy_redraw_screen(wme
);
5683 /* Scroll up if the cursor went off the visible screen. */
5685 window_copy_acquire_cursor_up(struct window_mode_entry
*wme
, u_int hsize
,
5686 u_int oy
, u_int oldy
, u_int px
, u_int py
)
5688 u_int cy
, yy
, ny
, nd
;
5701 window_copy_cursor_up(wme
, 1);
5704 window_copy_update_cursor(wme
, px
, cy
);
5705 if (window_copy_update_selection(wme
, 1, 0))
5706 window_copy_redraw_lines(wme
, cy
, nd
);
5709 /* Scroll down if the cursor went off the visible screen. */
5711 window_copy_acquire_cursor_down(struct window_mode_entry
*wme
, u_int hsize
,
5712 u_int sy
, u_int oy
, u_int oldy
, u_int px
, u_int py
, int no_reset
)
5714 u_int cy
, yy
, ny
, nd
;
5716 cy
= py
- hsize
+ oy
;
5727 window_copy_cursor_down(wme
, 1);
5731 window_copy_update_cursor(wme
, px
, yy
);
5733 window_copy_update_cursor(wme
, px
, cy
);
5734 if (window_copy_update_selection(wme
, 1, no_reset
))
5735 window_copy_redraw_lines(wme
, oldy
, nd
);