1 /* $Id: window-copy.c,v 1.109 2010-03-08 15:02:07 tcunha Exp $ */
4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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>
26 struct screen
*window_copy_init(struct window_pane
*);
27 void window_copy_free(struct window_pane
*);
28 void window_copy_resize(struct window_pane
*, u_int
, u_int
);
29 void window_copy_key(struct window_pane
*, struct client
*, int);
30 int window_copy_key_input(struct window_pane
*, int);
31 int window_copy_key_numeric_prefix(struct window_pane
*, int);
32 void window_copy_mouse(
33 struct window_pane
*, struct client
*, struct mouse_event
*);
35 void window_copy_redraw_lines(struct window_pane
*, u_int
, u_int
);
36 void window_copy_redraw_screen(struct window_pane
*);
37 void window_copy_write_line(
38 struct window_pane
*, struct screen_write_ctx
*, u_int
);
39 void window_copy_write_lines(
40 struct window_pane
*, struct screen_write_ctx
*, u_int
, u_int
);
42 void window_copy_scroll_to(struct window_pane
*, u_int
, u_int
);
43 int window_copy_search_compare(
44 struct grid
*, u_int
, u_int
, struct grid
*, u_int
);
45 int window_copy_search_lr(
46 struct grid
*, struct grid
*, u_int
*, u_int
, u_int
, u_int
);
47 int window_copy_search_rl(
48 struct grid
*, struct grid
*, u_int
*, u_int
, u_int
, u_int
);
49 void window_copy_search_up(struct window_pane
*, const char *);
50 void window_copy_search_down(struct window_pane
*, const char *);
51 void window_copy_goto_line(struct window_pane
*, const char *);
52 void window_copy_update_cursor(struct window_pane
*, u_int
, u_int
);
53 void window_copy_start_selection(struct window_pane
*);
54 int window_copy_update_selection(struct window_pane
*);
55 void window_copy_copy_selection(struct window_pane
*, struct client
*);
56 void window_copy_clear_selection(struct window_pane
*);
57 void window_copy_copy_line(
58 struct window_pane
*, char **, size_t *, u_int
, u_int
, u_int
);
59 int window_copy_in_set(struct window_pane
*, u_int
, u_int
, const char *);
60 u_int
window_copy_find_length(struct window_pane
*, u_int
);
61 void window_copy_cursor_start_of_line(struct window_pane
*);
62 void window_copy_cursor_back_to_indentation(struct window_pane
*);
63 void window_copy_cursor_end_of_line(struct window_pane
*);
64 void window_copy_cursor_left(struct window_pane
*);
65 void window_copy_cursor_right(struct window_pane
*);
66 void window_copy_cursor_up(struct window_pane
*, int);
67 void window_copy_cursor_down(struct window_pane
*, int);
68 void window_copy_cursor_next_word(struct window_pane
*, const char *);
69 void window_copy_cursor_next_word_end(struct window_pane
*, const char *);
70 void window_copy_cursor_previous_word(struct window_pane
*, const char *);
71 void window_copy_scroll_up(struct window_pane
*, u_int
);
72 void window_copy_scroll_down(struct window_pane
*, u_int
);
73 void window_copy_rectangle_toggle(struct window_pane
*);
75 const struct window_mode window_copy_mode
= {
84 enum window_copy_input_type
{
86 WINDOW_COPY_NUMERICPREFIX
,
88 WINDOW_COPY_SEARCHDOWN
,
92 struct window_copy_mode_data
{
95 struct mode_key_data mdata
;
102 u_int rectflag
; /* are we in rectangle copy mode? */
107 u_int lastcx
; /* position in last line with content */
108 u_int lastsx
; /* size of last line with content */
110 enum window_copy_input_type inputtype
;
111 const char *inputprompt
;
116 enum window_copy_input_type searchtype
;
121 window_copy_init(struct window_pane
*wp
)
123 struct window_copy_mode_data
*data
;
125 struct screen_write_ctx ctx
;
129 wp
->modedata
= data
= xmalloc(sizeof *data
);
131 data
->cx
= wp
->base
.cx
;
132 data
->cy
= wp
->base
.cy
;
139 data
->inputtype
= WINDOW_COPY_OFF
;
140 data
->inputprompt
= NULL
;
141 data
->inputstr
= xstrdup("");
144 data
->searchtype
= WINDOW_COPY_OFF
;
145 data
->searchstr
= NULL
;
147 wp
->flags
|= PANE_FREEZE
;
148 bufferevent_disable(wp
->event
, EV_READ
|EV_WRITE
);
151 screen_init(s
, screen_size_x(&wp
->base
), screen_size_y(&wp
->base
), 0);
152 if (options_get_number(&wp
->window
->options
, "mode-mouse"))
153 s
->mode
|= MODE_MOUSE
;
155 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
156 if (keys
== MODEKEY_EMACS
)
157 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_copy
);
159 mode_key_init(&data
->mdata
, &mode_key_tree_vi_copy
);
164 screen_write_start(&ctx
, NULL
, s
);
165 for (i
= 0; i
< screen_size_y(s
); i
++)
166 window_copy_write_line(wp
, &ctx
, i
);
167 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
168 screen_write_stop(&ctx
);
174 window_copy_free(struct window_pane
*wp
)
176 struct window_copy_mode_data
*data
= wp
->modedata
;
178 wp
->flags
&= ~PANE_FREEZE
;
179 bufferevent_enable(wp
->event
, EV_READ
|EV_WRITE
);
181 if (data
->searchstr
!= NULL
)
182 xfree(data
->searchstr
);
183 xfree(data
->inputstr
);
185 screen_free(&data
->screen
);
191 window_copy_pageup(struct window_pane
*wp
)
193 struct window_copy_mode_data
*data
= wp
->modedata
;
194 struct screen
*s
= &data
->screen
;
198 if (screen_size_y(s
) > 2)
199 n
= screen_size_y(s
) - 2;
200 if (data
->oy
+ n
> screen_hsize(&wp
->base
))
201 data
->oy
= screen_hsize(&wp
->base
);
204 window_copy_update_selection(wp
);
205 window_copy_redraw_screen(wp
);
209 window_copy_resize(struct window_pane
*wp
, u_int sx
, u_int sy
)
211 struct window_copy_mode_data
*data
= wp
->modedata
;
212 struct screen
*s
= &data
->screen
;
213 struct screen_write_ctx ctx
;
215 screen_resize(s
, sx
, sy
);
217 if (data
->cy
> sy
- 1)
222 window_copy_clear_selection(wp
);
224 screen_write_start(&ctx
, NULL
, s
);
225 window_copy_write_lines(wp
, &ctx
, 0, screen_size_y(s
) - 1);
226 screen_write_stop(&ctx
);
228 window_copy_redraw_screen(wp
);
232 window_copy_key(struct window_pane
*wp
, struct client
*c
, int key
)
234 const char *word_separators
;
235 struct window_copy_mode_data
*data
= wp
->modedata
;
236 struct screen
*s
= &data
->screen
;
239 enum mode_key_cmd cmd
;
241 np
= data
->numprefix
;
245 if (data
->inputtype
== WINDOW_COPY_NUMERICPREFIX
) {
246 if (window_copy_key_numeric_prefix(wp
, key
) == 0)
248 data
->inputtype
= WINDOW_COPY_OFF
;
249 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
250 } else if (data
->inputtype
!= WINDOW_COPY_OFF
) {
251 if (window_copy_key_input(wp
, key
) != 0)
256 cmd
= mode_key_lookup(&data
->mdata
, key
);
258 case MODEKEYCOPY_CANCEL
:
259 for (; np
!= 0; np
--)
260 window_pane_reset_mode(wp
);
262 case MODEKEYCOPY_LEFT
:
263 for (; np
!= 0; np
--)
264 window_copy_cursor_left(wp
);
266 case MODEKEYCOPY_RIGHT
:
267 for (; np
!= 0; np
--)
268 window_copy_cursor_right(wp
);
271 for (; np
!= 0; np
--)
272 window_copy_cursor_up(wp
, 0);
274 case MODEKEYCOPY_DOWN
:
275 for (; np
!= 0; np
--)
276 window_copy_cursor_down(wp
, 0);
278 case MODEKEYCOPY_SCROLLUP
:
279 for (; np
!= 0; np
--)
280 window_copy_cursor_up(wp
, 1);
282 case MODEKEYCOPY_SCROLLDOWN
:
283 for (; np
!= 0; np
--)
284 window_copy_cursor_down(wp
, 1);
286 case MODEKEYCOPY_PREVIOUSPAGE
:
287 for (; np
!= 0; np
--)
288 window_copy_pageup(wp
);
290 case MODEKEYCOPY_NEXTPAGE
:
292 if (screen_size_y(s
) > 2)
293 n
= screen_size_y(s
) - 2;
294 for (; np
!= 0; np
--) {
300 window_copy_update_selection(wp
);
301 window_copy_redraw_screen(wp
);
303 case MODEKEYCOPY_HALFPAGEUP
:
304 n
= screen_size_y(s
) / 2;
305 for (; np
!= 0; np
--) {
306 if (data
->oy
+ n
> screen_hsize(&wp
->base
))
307 data
->oy
= screen_hsize(&wp
->base
);
311 window_copy_update_selection(wp
);
312 window_copy_redraw_screen(wp
);
314 case MODEKEYCOPY_HALFPAGEDOWN
:
315 n
= screen_size_y(s
) / 2;
316 for (; np
!= 0; np
--) {
322 window_copy_update_selection(wp
);
323 window_copy_redraw_screen(wp
);
325 case MODEKEYCOPY_TOPLINE
:
328 window_copy_update_selection(wp
);
329 window_copy_redraw_screen(wp
);
331 case MODEKEYCOPY_MIDDLELINE
:
333 data
->cy
= (screen_size_y(s
) - 1) / 2;
334 window_copy_update_selection(wp
);
335 window_copy_redraw_screen(wp
);
337 case MODEKEYCOPY_BOTTOMLINE
:
339 data
->cy
= screen_size_y(s
) - 1;
340 window_copy_update_selection(wp
);
341 window_copy_redraw_screen(wp
);
343 case MODEKEYCOPY_HISTORYTOP
:
346 data
->oy
= screen_hsize(&wp
->base
);
347 window_copy_update_selection(wp
);
348 window_copy_redraw_screen(wp
);
350 case MODEKEYCOPY_HISTORYBOTTOM
:
352 data
->cy
= screen_size_y(s
) - 1;
354 window_copy_update_selection(wp
);
355 window_copy_redraw_screen(wp
);
357 case MODEKEYCOPY_STARTSELECTION
:
358 window_copy_start_selection(wp
);
359 window_copy_redraw_screen(wp
);
361 case MODEKEYCOPY_CLEARSELECTION
:
362 window_copy_clear_selection(wp
);
363 window_copy_redraw_screen(wp
);
365 case MODEKEYCOPY_COPYSELECTION
:
366 if (c
!= NULL
&& c
->session
!= NULL
) {
367 window_copy_copy_selection(wp
, c
);
368 window_pane_reset_mode(wp
);
371 case MODEKEYCOPY_STARTOFLINE
:
372 window_copy_cursor_start_of_line(wp
);
374 case MODEKEYCOPY_BACKTOINDENTATION
:
375 window_copy_cursor_back_to_indentation(wp
);
377 case MODEKEYCOPY_ENDOFLINE
:
378 window_copy_cursor_end_of_line(wp
);
380 case MODEKEYCOPY_NEXTSPACE
:
381 for (; np
!= 0; np
--)
382 window_copy_cursor_next_word(wp
, " ");
384 case MODEKEYCOPY_NEXTSPACEEND
:
385 for (; np
!= 0; np
--)
386 window_copy_cursor_next_word_end(wp
, " ");
388 case MODEKEYCOPY_NEXTWORD
:
390 options_get_string(&wp
->window
->options
, "word-separators");
391 for (; np
!= 0; np
--)
392 window_copy_cursor_next_word(wp
, word_separators
);
394 case MODEKEYCOPY_NEXTWORDEND
:
396 options_get_string(&wp
->window
->options
, "word-separators");
397 for (; np
!= 0; np
--)
398 window_copy_cursor_next_word_end(wp
, word_separators
);
400 case MODEKEYCOPY_PREVIOUSSPACE
:
401 for (; np
!= 0; np
--)
402 window_copy_cursor_previous_word(wp
, " ");
404 case MODEKEYCOPY_PREVIOUSWORD
:
406 options_get_string(&wp
->window
->options
, "word-separators");
407 for (; np
!= 0; np
--)
408 window_copy_cursor_previous_word(wp
, word_separators
);
410 case MODEKEYCOPY_SEARCHUP
:
411 data
->inputtype
= WINDOW_COPY_SEARCHUP
;
412 data
->inputprompt
= "Search Up";
414 case MODEKEYCOPY_SEARCHDOWN
:
415 data
->inputtype
= WINDOW_COPY_SEARCHDOWN
;
416 data
->inputprompt
= "Search Down";
418 case MODEKEYCOPY_SEARCHAGAIN
:
419 case MODEKEYCOPY_SEARCHREVERSE
:
420 switch (data
->searchtype
) {
421 case WINDOW_COPY_OFF
:
422 case WINDOW_COPY_GOTOLINE
:
423 case WINDOW_COPY_NUMERICPREFIX
:
425 case WINDOW_COPY_SEARCHUP
:
426 if (cmd
== MODEKEYCOPY_SEARCHAGAIN
) {
427 for (; np
!= 0; np
--) {
428 window_copy_search_up(
429 wp
, data
->searchstr
);
432 for (; np
!= 0; np
--) {
433 window_copy_search_down(
434 wp
, data
->searchstr
);
438 case WINDOW_COPY_SEARCHDOWN
:
439 if (cmd
== MODEKEYCOPY_SEARCHAGAIN
) {
440 for (; np
!= 0; np
--) {
441 window_copy_search_down(
442 wp
, data
->searchstr
);
445 for (; np
!= 0; np
--) {
446 window_copy_search_up(
447 wp
, data
->searchstr
);
453 case MODEKEYCOPY_GOTOLINE
:
454 data
->inputtype
= WINDOW_COPY_GOTOLINE
;
455 data
->inputprompt
= "Goto Line";
456 *data
->inputstr
= '\0';
458 case MODEKEYCOPY_STARTNUMBERPREFIX
:
460 if (key
>= '0' && key
<= '9') {
461 data
->inputtype
= WINDOW_COPY_NUMERICPREFIX
;
463 window_copy_key_numeric_prefix(wp
, key
);
467 case MODEKEYCOPY_RECTANGLETOGGLE
:
468 window_copy_rectangle_toggle(wp
);
478 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
479 if (keys
== MODEKEY_EMACS
)
480 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_edit
);
482 mode_key_init(&data
->mdata
, &mode_key_tree_vi_edit
);
484 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
488 keys
= options_get_number(&wp
->window
->options
, "mode-keys");
489 if (keys
== MODEKEY_EMACS
)
490 mode_key_init(&data
->mdata
, &mode_key_tree_emacs_copy
);
492 mode_key_init(&data
->mdata
, &mode_key_tree_vi_copy
);
494 data
->inputtype
= WINDOW_COPY_OFF
;
495 data
->inputprompt
= NULL
;
497 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
501 window_copy_key_input(struct window_pane
*wp
, int key
)
503 struct window_copy_mode_data
*data
= wp
->modedata
;
504 struct screen
*s
= &data
->screen
;
508 switch (mode_key_lookup(&data
->mdata
, key
)) {
509 case MODEKEYEDIT_CANCEL
:
512 case MODEKEYEDIT_BACKSPACE
:
513 inputlen
= strlen(data
->inputstr
);
515 data
->inputstr
[inputlen
- 1] = '\0';
517 case MODEKEYEDIT_DELETELINE
:
518 *data
->inputstr
= '\0';
520 case MODEKEYEDIT_ENTER
:
521 np
= data
->numprefix
;
525 switch (data
->inputtype
) {
526 case WINDOW_COPY_OFF
:
527 case WINDOW_COPY_NUMERICPREFIX
:
529 case WINDOW_COPY_SEARCHUP
:
530 for (; np
!= 0; np
--)
531 window_copy_search_up(wp
, data
->inputstr
);
532 data
->searchtype
= data
->inputtype
;
533 data
->searchstr
= xstrdup(data
->inputstr
);
535 case WINDOW_COPY_SEARCHDOWN
:
536 for (; np
!= 0; np
--)
537 window_copy_search_down(wp
, data
->inputstr
);
538 data
->searchtype
= data
->inputtype
;
539 data
->searchstr
= xstrdup(data
->inputstr
);
541 case WINDOW_COPY_GOTOLINE
:
542 window_copy_goto_line(wp
, data
->inputstr
);
543 *data
->inputstr
= '\0';
549 if (key
< 32 || key
> 126)
551 inputlen
= strlen(data
->inputstr
) + 2;
553 data
->inputstr
= xrealloc(data
->inputstr
, 1, inputlen
);
554 data
->inputstr
[inputlen
- 2] = key
;
555 data
->inputstr
[inputlen
- 1] = '\0';
561 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
566 window_copy_key_numeric_prefix(struct window_pane
*wp
, int key
)
568 struct window_copy_mode_data
*data
= wp
->modedata
;
569 struct screen
*s
= &data
->screen
;
572 if (key
< '0' || key
> '9')
575 if (data
->numprefix
>= 100) /* no more than three digits */
577 data
->numprefix
= data
->numprefix
* 10 + key
- '0';
579 window_copy_redraw_lines(wp
, screen_size_y(s
) - 1, 1);
586 struct window_pane
*wp
, unused
struct client
*c
, struct mouse_event
*m
)
588 struct window_copy_mode_data
*data
= wp
->modedata
;
589 struct screen
*s
= &data
->screen
;
593 if (m
->x
>= screen_size_x(s
))
595 if (m
->y
>= screen_size_y(s
))
598 window_copy_update_cursor(wp
, m
->x
, m
->y
);
599 if (window_copy_update_selection(wp
))
600 window_copy_redraw_screen(wp
);
604 window_copy_scroll_to(struct window_pane
*wp
, u_int px
, u_int py
)
606 struct window_copy_mode_data
*data
= wp
->modedata
;
607 struct screen
*s
= &wp
->base
;
608 struct grid
*gd
= s
->grid
;
617 } else if (py
> gd
->hsize
+ gd
->sy
- gap
) {
619 data
->cy
= py
- gd
->hsize
;
621 offset
= py
+ gap
- gd
->sy
;
622 data
->cy
= py
- offset
;
624 data
->oy
= gd
->hsize
- offset
;
626 window_copy_update_selection(wp
);
627 window_copy_redraw_screen(wp
);
631 window_copy_search_compare(
632 struct grid
*gd
, u_int px
, u_int py
, struct grid
*sgd
, u_int spx
)
634 const struct grid_cell
*gc
, *sgc
;
635 const struct grid_utf8
*gu
, *sgu
;
637 gc
= grid_peek_cell(gd
, px
, py
);
638 sgc
= grid_peek_cell(sgd
, spx
, 0);
640 if ((gc
->flags
& GRID_FLAG_UTF8
) != (sgc
->flags
& GRID_FLAG_UTF8
))
643 if (gc
->flags
& GRID_FLAG_UTF8
) {
644 gu
= grid_peek_utf8(gd
, px
, py
);
645 sgu
= grid_peek_utf8(sgd
, spx
, 0);
646 if (grid_utf8_compare(gu
, sgu
))
649 if (gc
->data
== sgc
->data
)
656 window_copy_search_lr(struct grid
*gd
,
657 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
)
661 for (ax
= first
; ax
< last
; ax
++) {
662 if (ax
+ sgd
->sx
>= gd
->sx
)
664 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
666 if (!window_copy_search_compare(gd
, px
, py
, sgd
, bx
))
678 window_copy_search_rl(struct grid
*gd
,
679 struct grid
*sgd
, u_int
*ppx
, u_int py
, u_int first
, u_int last
)
683 for (ax
= last
+ 1; ax
> first
; ax
--) {
684 if (gd
->sx
- (ax
- 1) < sgd
->sx
)
686 for (bx
= 0; bx
< sgd
->sx
; bx
++) {
688 if (!window_copy_search_compare(gd
, px
, py
, sgd
, bx
))
700 window_copy_search_up(struct window_pane
*wp
, const char *searchstr
)
702 struct window_copy_mode_data
*data
= wp
->modedata
;
703 struct screen
*s
= &wp
->base
, ss
;
704 struct screen_write_ctx ctx
;
705 struct grid
*gd
= s
->grid
, *sgd
;
708 u_int i
, last
, fx
, fy
, px
;
709 int utf8flag
, n
, wrapped
;
711 if (*searchstr
== '\0')
713 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
714 searchlen
= screen_write_strlen(utf8flag
, "%s", searchstr
);
716 screen_init(&ss
, searchlen
, 1, 0);
717 screen_write_start(&ctx
, NULL
, &ss
);
718 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
719 screen_write_nputs(&ctx
, -1, &gc
, utf8flag
, "%s", searchstr
);
720 screen_write_stop(&ctx
);
723 fy
= gd
->hsize
- data
->oy
+ data
->cy
;
736 for (i
= fy
+ 1; i
> 0; i
--) {
737 last
= screen_size_x(s
);
740 n
= window_copy_search_rl(gd
, sgd
, &px
, i
- 1, 0, last
);
742 window_copy_scroll_to(wp
, px
, i
- 1);
746 if (!n
&& !wrapped
) {
748 fy
= gd
->hsize
+ gd
->sy
- 1;
757 window_copy_search_down(struct window_pane
*wp
, const char *searchstr
)
759 struct window_copy_mode_data
*data
= wp
->modedata
;
760 struct screen
*s
= &wp
->base
, ss
;
761 struct screen_write_ctx ctx
;
762 struct grid
*gd
= s
->grid
, *sgd
;
765 u_int i
, first
, fx
, fy
, px
;
766 int utf8flag
, n
, wrapped
;
768 if (*searchstr
== '\0')
770 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
771 searchlen
= screen_write_strlen(utf8flag
, "%s", searchstr
);
773 screen_init(&ss
, searchlen
, 1, 0);
774 screen_write_start(&ctx
, NULL
, &ss
);
775 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
776 screen_write_nputs(&ctx
, -1, &gc
, utf8flag
, "%s", searchstr
);
777 screen_write_stop(&ctx
);
780 fy
= gd
->hsize
- data
->oy
+ data
->cy
;
782 if (fx
== gd
->sx
- 1) {
783 if (fy
== gd
->hsize
+ gd
->sy
)
793 for (i
= fy
+ 1; i
< gd
->hsize
+ gd
->sy
; i
++) {
797 n
= window_copy_search_lr(gd
, sgd
, &px
, i
- 1, first
, gd
->sx
);
799 window_copy_scroll_to(wp
, px
, i
- 1);
803 if (!n
&& !wrapped
) {
814 window_copy_goto_line(struct window_pane
*wp
, const char *linestr
)
816 struct window_copy_mode_data
*data
= wp
->modedata
;
820 lineno
= strtonum(linestr
, 0, screen_hsize(&wp
->base
), &errstr
);
825 window_copy_update_selection(wp
);
826 window_copy_redraw_screen(wp
);
830 window_copy_write_line(
831 struct window_pane
*wp
, struct screen_write_ctx
*ctx
, u_int py
)
833 struct window_copy_mode_data
*data
= wp
->modedata
;
834 struct screen
*s
= &data
->screen
;
835 struct options
*oo
= &wp
->window
->options
;
838 size_t last
, xoff
= 0, size
= 0;
840 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
841 colour_set_fg(&gc
, options_get_number(oo
, "mode-fg"));
842 colour_set_bg(&gc
, options_get_number(oo
, "mode-bg"));
843 gc
.attr
|= options_get_number(oo
, "mode-attr");
845 last
= screen_size_y(s
) - 1;
847 size
= xsnprintf(hdr
, sizeof hdr
,
848 "[%u/%u]", data
->oy
, screen_hsize(&wp
->base
));
849 screen_write_cursormove(ctx
, screen_size_x(s
) - size
, 0);
850 screen_write_puts(ctx
, &gc
, "%s", hdr
);
851 } else if (py
== last
&& data
->inputtype
!= WINDOW_COPY_OFF
) {
852 if (data
->inputtype
== WINDOW_COPY_NUMERICPREFIX
) {
853 xoff
= size
= xsnprintf(hdr
, sizeof hdr
,
854 "Repeat: %u", data
->numprefix
);
856 xoff
= size
= xsnprintf(hdr
, sizeof hdr
,
857 "%s: %s", data
->inputprompt
, data
->inputstr
);
859 screen_write_cursormove(ctx
, 0, last
);
860 screen_write_puts(ctx
, &gc
, "%s", hdr
);
864 screen_write_cursormove(ctx
, xoff
, py
);
865 screen_write_copy(ctx
, &wp
->base
, xoff
, (screen_hsize(&wp
->base
) -
866 data
->oy
) + py
, screen_size_x(s
) - size
, 1);
868 if (py
== data
->cy
&& data
->cx
== screen_size_x(s
)) {
869 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
870 screen_write_cursormove(ctx
, screen_size_x(s
) - 1, py
);
871 screen_write_putc(ctx
, &gc
, '$');
876 window_copy_write_lines(
877 struct window_pane
*wp
, struct screen_write_ctx
*ctx
, u_int py
, u_int ny
)
881 for (yy
= py
; yy
< py
+ ny
; yy
++)
882 window_copy_write_line(wp
, ctx
, py
);
886 window_copy_redraw_lines(struct window_pane
*wp
, u_int py
, u_int ny
)
888 struct window_copy_mode_data
*data
= wp
->modedata
;
889 struct screen_write_ctx ctx
;
892 screen_write_start(&ctx
, wp
, NULL
);
893 for (i
= py
; i
< py
+ ny
; i
++)
894 window_copy_write_line(wp
, &ctx
, i
);
895 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
896 screen_write_stop(&ctx
);
900 window_copy_redraw_screen(struct window_pane
*wp
)
902 struct window_copy_mode_data
*data
= wp
->modedata
;
904 window_copy_redraw_lines(wp
, 0, screen_size_y(&data
->screen
));
908 window_copy_update_cursor(struct window_pane
*wp
, u_int cx
, u_int cy
)
910 struct window_copy_mode_data
*data
= wp
->modedata
;
911 struct screen
*s
= &data
->screen
;
912 struct screen_write_ctx ctx
;
913 u_int old_cx
, old_cy
;
915 old_cx
= data
->cx
; old_cy
= data
->cy
;
916 data
->cx
= cx
; data
->cy
= cy
;
917 if (old_cx
== screen_size_x(s
))
918 window_copy_redraw_lines(wp
, old_cy
, 1);
919 if (data
->cx
== screen_size_x(s
))
920 window_copy_redraw_lines(wp
, data
->cy
, 1);
922 screen_write_start(&ctx
, wp
, NULL
);
923 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
924 screen_write_stop(&ctx
);
929 window_copy_start_selection(struct window_pane
*wp
)
931 struct window_copy_mode_data
*data
= wp
->modedata
;
932 struct screen
*s
= &data
->screen
;
934 data
->selx
= data
->cx
;
935 data
->sely
= screen_hsize(&wp
->base
) + data
->cy
- data
->oy
;
938 window_copy_update_selection(wp
);
942 window_copy_update_selection(struct window_pane
*wp
)
944 struct window_copy_mode_data
*data
= wp
->modedata
;
945 struct screen
*s
= &data
->screen
;
946 struct options
*oo
= &wp
->window
->options
;
948 u_int sx
, sy
, ty
, cy
;
954 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
955 colour_set_fg(&gc
, options_get_number(oo
, "mode-fg"));
956 colour_set_bg(&gc
, options_get_number(oo
, "mode-bg"));
957 gc
.attr
|= options_get_number(oo
, "mode-attr");
959 /* Find top of screen. */
960 ty
= screen_hsize(&wp
->base
) - data
->oy
;
962 /* Adjust the selection. */
965 if (sy
< ty
) { /* above screen */
969 } else if (sy
> ty
+ screen_size_y(s
) - 1) { /* below screen */
971 sx
= screen_size_x(s
) - 1;
972 sy
= screen_size_y(s
) - 1;
975 sy
= screen_hsize(s
) + sy
;
977 screen_set_selection(s
,
978 sx
, sy
, data
->cx
, screen_hsize(s
) + data
->cy
, data
->rectflag
, &gc
);
980 if (data
->rectflag
) {
982 * Can't rely on the caller to redraw the right lines for
983 * rectangle selection - find the highest line and the number
984 * of lines, and redraw just past that in both directions
988 window_copy_redraw_lines(wp
, sy
, cy
- sy
+ 1);
990 window_copy_redraw_lines(wp
, cy
, sy
- cy
+ 1);
997 window_copy_copy_selection(struct window_pane
*wp
, struct client
*c
)
999 struct window_copy_mode_data
*data
= wp
->modedata
;
1000 struct screen
*s
= &data
->screen
;
1003 u_int i
, xx
, yy
, sx
, sy
, ex
, ey
, limit
;
1004 u_int firstsx
, lastex
, restex
, restsx
;
1015 * The selection extends from selx,sely to (adjusted) cx,cy on
1019 /* Find start and end. */
1021 yy
= screen_hsize(&wp
->base
) + data
->cy
- data
->oy
;
1022 if (yy
< data
->sely
|| (yy
== data
->sely
&& xx
< data
->selx
)) {
1024 ex
= data
->selx
; ey
= data
->sely
;
1026 sx
= data
->selx
; sy
= data
->sely
;
1030 /* Trim ex to end of line. */
1031 xx
= window_copy_find_length(wp
, ey
);
1036 * Deal with rectangle-copy if necessary; four situations: start of
1037 * first line (firstsx), end of last line (lastex), start (restsx) and
1038 * end (restex) of all other lines.
1040 xx
= screen_size_x(s
);
1041 if (data
->rectflag
) {
1043 * Need to ignore the column with the cursor in it, which for
1044 * rectangular copy means knowing which side the cursor is on.
1046 if (data
->selx
< data
->cx
) {
1047 /* Selection start is on the left. */
1050 firstsx
= data
->selx
;
1051 restsx
= data
->selx
;
1053 /* Cursor is on the left. */
1054 lastex
= data
->selx
+ 1;
1055 restex
= data
->selx
+ 1;
1056 firstsx
= data
->cx
+ 1;
1057 restsx
= data
->cx
+ 1;
1061 * Like emacs, keep the top-left-most character, and drop the
1062 * bottom-right-most, regardless of copy direction.
1070 /* Copy the lines. */
1072 window_copy_copy_line(wp
, &buf
, &off
, sy
, firstsx
, lastex
);
1074 window_copy_copy_line(wp
, &buf
, &off
, sy
, firstsx
, restex
);
1076 for (i
= sy
+ 1; i
< ey
; i
++) {
1077 window_copy_copy_line(
1078 wp
, &buf
, &off
, i
, restsx
, restex
);
1081 window_copy_copy_line(wp
, &buf
, &off
, ey
, restsx
, lastex
);
1084 /* Don't bother if no data. */
1089 off
--; /* remove final \n */
1091 /* Add the buffer to the stack. */
1092 limit
= options_get_number(&c
->session
->options
, "buffer-limit");
1093 paste_add(&c
->session
->buffers
, buf
, off
, limit
);
1097 window_copy_copy_line(struct window_pane
*wp
,
1098 char **buf
, size_t *off
, u_int sy
, u_int sx
, u_int ex
)
1100 struct grid
*gd
= wp
->base
.grid
;
1101 const struct grid_cell
*gc
;
1102 const struct grid_utf8
*gu
;
1103 struct grid_line
*gl
;
1104 u_int i
, xx
, wrapped
= 0;
1111 * Work out if the line was wrapped at the screen edge and all of it is
1114 gl
= &gd
->linedata
[sy
];
1115 if (gl
->flags
& GRID_LINE_WRAPPED
&& gl
->cellsize
<= gd
->sx
)
1118 /* If the line was wrapped, don't strip spaces (use the full length). */
1122 xx
= window_copy_find_length(wp
, sy
);
1129 for (i
= sx
; i
< ex
; i
++) {
1130 gc
= grid_peek_cell(gd
, i
, sy
);
1131 if (gc
->flags
& GRID_FLAG_PADDING
)
1133 if (!(gc
->flags
& GRID_FLAG_UTF8
)) {
1134 *buf
= xrealloc(*buf
, 1, (*off
) + 1);
1135 (*buf
)[(*off
)++] = gc
->data
;
1137 gu
= grid_peek_utf8(gd
, i
, sy
);
1138 size
= grid_utf8_size(gu
);
1139 *buf
= xrealloc(*buf
, 1, (*off
) + size
);
1140 *off
+= grid_utf8_copy(gu
, *buf
+ *off
, size
);
1145 /* Only add a newline if the line wasn't wrapped. */
1146 if (!wrapped
|| ex
!= xx
) {
1147 *buf
= xrealloc(*buf
, 1, (*off
) + 1);
1148 (*buf
)[(*off
)++] = '\n';
1153 window_copy_clear_selection(struct window_pane
*wp
)
1155 struct window_copy_mode_data
*data
= wp
->modedata
;
1158 screen_clear_selection(&data
->screen
);
1160 py
= screen_hsize(&wp
->base
) + data
->cy
- data
->oy
;
1161 px
= window_copy_find_length(wp
, py
);
1163 window_copy_update_cursor(wp
, px
, data
->cy
);
1167 window_copy_in_set(struct window_pane
*wp
, u_int px
, u_int py
, const char *set
)
1169 const struct grid_cell
*gc
;
1171 gc
= grid_peek_cell(wp
->base
.grid
, px
, py
);
1172 if (gc
->flags
& (GRID_FLAG_PADDING
|GRID_FLAG_UTF8
))
1174 if (gc
->data
== 0x00 || gc
->data
== 0x7f)
1176 return (strchr(set
, gc
->data
) != NULL
);
1180 window_copy_find_length(struct window_pane
*wp
, u_int py
)
1182 const struct grid_cell
*gc
;
1186 * If the pane has been resized, its grid can contain old overlong
1187 * lines. grid_peek_cell does not allow accessing cells beyond the
1188 * width of the grid, and screen_write_copy treats them as spaces, so
1189 * ignore them here too.
1191 px
= wp
->base
.grid
->linedata
[py
].cellsize
;
1192 if (px
> screen_size_x(&wp
->base
))
1193 px
= screen_size_x(&wp
->base
);
1195 gc
= grid_peek_cell(wp
->base
.grid
, px
- 1, py
);
1196 if (gc
->flags
& GRID_FLAG_UTF8
)
1198 if (gc
->data
!= ' ')
1206 window_copy_cursor_start_of_line(struct window_pane
*wp
)
1208 struct window_copy_mode_data
*data
= wp
->modedata
;
1210 window_copy_update_cursor(wp
, 0, data
->cy
);
1211 if (window_copy_update_selection(wp
))
1212 window_copy_redraw_lines(wp
, data
->cy
, 1);
1216 window_copy_cursor_back_to_indentation(struct window_pane
*wp
)
1218 struct window_copy_mode_data
*data
= wp
->modedata
;
1220 const struct grid_cell
*gc
;
1223 py
= screen_hsize(&wp
->base
) + data
->cy
- data
->oy
;
1224 xx
= window_copy_find_length(wp
, py
);
1227 gc
= grid_peek_cell(wp
->base
.grid
, px
, py
);
1228 if (gc
->flags
& GRID_FLAG_UTF8
)
1230 if (gc
->data
!= ' ')
1235 window_copy_update_cursor(wp
, px
, data
->cy
);
1236 if (window_copy_update_selection(wp
))
1237 window_copy_redraw_lines(wp
, data
->cy
, 1);
1241 window_copy_cursor_end_of_line(struct window_pane
*wp
)
1243 struct window_copy_mode_data
*data
= wp
->modedata
;
1244 struct screen
*base_s
= &wp
->base
;
1245 struct grid
*gd
= base_s
->grid
;
1248 py
= screen_hsize(base_s
) + data
->cy
- data
->oy
;
1249 px
= window_copy_find_length(wp
, py
);
1251 if (data
->cx
== px
) {
1252 if (data
->screen
.sel
.flag
&& data
->rectflag
)
1253 px
= screen_size_x(&wp
->base
);
1254 if (gd
->linedata
[py
].flags
& GRID_LINE_WRAPPED
) {
1255 while (py
< gd
->sy
+ gd
->hsize
&&
1256 gd
->linedata
[py
].flags
& GRID_LINE_WRAPPED
) {
1257 window_copy_cursor_down(wp
, 0);
1258 py
= screen_hsize(base_s
) + data
->cy
- data
->oy
;
1260 px
= window_copy_find_length(wp
, py
);
1263 window_copy_update_cursor(wp
, px
, data
->cy
);
1265 if (window_copy_update_selection(wp
))
1266 window_copy_redraw_lines(wp
, data
->cy
, 1);
1270 window_copy_cursor_left(struct window_pane
*wp
)
1272 struct window_copy_mode_data
*data
= wp
->modedata
;
1274 if (data
->cx
== 0) {
1275 window_copy_cursor_up(wp
, 0);
1276 window_copy_cursor_end_of_line(wp
);
1278 window_copy_update_cursor(wp
, data
->cx
- 1, data
->cy
);
1279 if (window_copy_update_selection(wp
))
1280 window_copy_redraw_lines(wp
, data
->cy
, 1);
1285 window_copy_cursor_right(struct window_pane
*wp
)
1287 struct window_copy_mode_data
*data
= wp
->modedata
;
1290 if (data
->screen
.sel
.flag
&& data
->rectflag
)
1291 px
= screen_size_x(&data
->screen
);
1293 py
= screen_hsize(&wp
->base
) + data
->cy
- data
->oy
;
1294 px
= window_copy_find_length(wp
, py
);
1297 if (data
->cx
>= px
) {
1298 window_copy_cursor_start_of_line(wp
);
1299 window_copy_cursor_down(wp
, 0);
1301 window_copy_update_cursor(wp
, data
->cx
+ 1, data
->cy
);
1302 if (window_copy_update_selection(wp
))
1303 window_copy_redraw_lines(wp
, data
->cy
, 1);
1308 window_copy_cursor_up(struct window_pane
*wp
, int scroll_only
)
1310 struct window_copy_mode_data
*data
= wp
->modedata
;
1311 struct screen
*s
= &data
->screen
;
1312 u_int ox
, oy
, px
, py
;
1314 oy
= screen_hsize(&wp
->base
) + data
->cy
- data
->oy
;
1315 ox
= window_copy_find_length(wp
, oy
);
1317 data
->lastcx
= data
->cx
;
1321 data
->cx
= data
->lastcx
;
1322 if (scroll_only
|| data
->cy
== 0) {
1323 window_copy_scroll_down(wp
, 1);
1325 if (data
->cy
== screen_size_y(s
) - 1)
1326 window_copy_redraw_lines(wp
, data
->cy
, 1);
1328 window_copy_redraw_lines(wp
, data
->cy
, 2);
1331 window_copy_update_cursor(wp
, data
->cx
, data
->cy
- 1);
1332 if (window_copy_update_selection(wp
)) {
1333 if (data
->cy
== screen_size_y(s
) - 1)
1334 window_copy_redraw_lines(wp
, data
->cy
, 1);
1336 window_copy_redraw_lines(wp
, data
->cy
, 2);
1340 if (!data
->screen
.sel
.flag
|| !data
->rectflag
) {
1341 py
= screen_hsize(&wp
->base
) + data
->cy
- data
->oy
;
1342 px
= window_copy_find_length(wp
, py
);
1343 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
1345 window_copy_cursor_end_of_line(wp
);
1350 window_copy_cursor_down(struct window_pane
*wp
, int scroll_only
)
1352 struct window_copy_mode_data
*data
= wp
->modedata
;
1353 struct screen
*s
= &data
->screen
;
1354 u_int ox
, oy
, px
, py
;
1356 oy
= screen_hsize(&wp
->base
) + data
->cy
- data
->oy
;
1357 ox
= window_copy_find_length(wp
, oy
);
1359 data
->lastcx
= data
->cx
;
1363 data
->cx
= data
->lastcx
;
1364 if (scroll_only
|| data
->cy
== screen_size_y(s
) - 1) {
1365 window_copy_scroll_up(wp
, 1);
1366 if (scroll_only
&& data
->cy
> 0)
1367 window_copy_redraw_lines(wp
, data
->cy
- 1, 2);
1369 window_copy_update_cursor(wp
, data
->cx
, data
->cy
+ 1);
1370 if (window_copy_update_selection(wp
))
1371 window_copy_redraw_lines(wp
, data
->cy
- 1, 2);
1374 if (!data
->screen
.sel
.flag
|| !data
->rectflag
) {
1375 py
= screen_hsize(&wp
->base
) + data
->cy
- data
->oy
;
1376 px
= window_copy_find_length(wp
, py
);
1377 if ((data
->cx
>= data
->lastsx
&& data
->cx
!= px
) ||
1379 window_copy_cursor_end_of_line(wp
);
1384 window_copy_cursor_next_word(struct window_pane
*wp
, const char *separators
)
1386 struct window_copy_mode_data
*data
= wp
->modedata
;
1387 struct screen
*base_s
= &wp
->base
;
1388 u_int px
, py
, xx
, yy
;
1392 py
= screen_hsize(base_s
) + data
->cy
- data
->oy
;
1393 xx
= window_copy_find_length(wp
, py
);
1394 yy
= screen_hsize(base_s
) + screen_size_y(base_s
) - 1;
1397 * First skip past any nonword characters and then any word characters.
1399 * expected is initially set to 0 for the former and then 1 for the
1404 window_copy_in_set(wp
, px
, py
, separators
) == expected
) {
1405 /* Move down if we're past the end of the line. */
1409 window_copy_cursor_down(wp
, 0);
1412 py
= screen_hsize(base_s
) + data
->cy
- data
->oy
;
1413 xx
= window_copy_find_length(wp
, py
);
1417 expected
= !expected
;
1418 } while (expected
== 1);
1420 window_copy_update_cursor(wp
, px
, data
->cy
);
1421 if (window_copy_update_selection(wp
))
1422 window_copy_redraw_lines(wp
, data
->cy
, 1);
1426 window_copy_cursor_next_word_end(struct window_pane
*wp
, const char *separators
)
1428 struct window_copy_mode_data
*data
= wp
->modedata
;
1429 struct screen
*base_s
= &wp
->base
;
1430 u_int px
, py
, xx
, yy
;
1434 py
= screen_hsize(base_s
) + data
->cy
- data
->oy
;
1435 xx
= window_copy_find_length(wp
, py
);
1436 yy
= screen_hsize(base_s
) + screen_size_y(base_s
) - 1;
1439 * First skip past any word characters, then any nonword characters.
1441 * expected is initially set to 1 for the former and then 0 for the
1446 window_copy_in_set(wp
, px
, py
, separators
) == expected
) {
1447 /* Move down if we're past the end of the line. */
1451 window_copy_cursor_down(wp
, 0);
1454 py
= screen_hsize(base_s
) + data
->cy
- data
->oy
;
1455 xx
= window_copy_find_length(wp
, py
);
1459 expected
= !expected
;
1460 } while (expected
== 0);
1462 window_copy_update_cursor(wp
, px
, data
->cy
);
1463 if (window_copy_update_selection(wp
))
1464 window_copy_redraw_lines(wp
, data
->cy
, 1);
1467 /* Move to the previous place where a word begins. */
1469 window_copy_cursor_previous_word(struct window_pane
*wp
, const char *separators
)
1471 struct window_copy_mode_data
*data
= wp
->modedata
;
1475 py
= screen_hsize(&wp
->base
) + data
->cy
- data
->oy
;
1477 /* Move back to the previous word character. */
1481 if (!window_copy_in_set(wp
, px
, py
, separators
))
1484 if (data
->cy
== 0 &&
1485 (screen_hsize(&wp
->base
) == 0 ||
1486 data
->oy
>= screen_hsize(&wp
->base
) - 1))
1488 window_copy_cursor_up(wp
, 0);
1490 py
= screen_hsize(&wp
->base
) + data
->cy
- data
->oy
;
1491 px
= window_copy_find_length(wp
, py
);
1495 /* Move back to the beginning of this word. */
1496 while (px
> 0 && !window_copy_in_set(wp
, px
- 1, py
, separators
))
1500 window_copy_update_cursor(wp
, px
, data
->cy
);
1501 if (window_copy_update_selection(wp
))
1502 window_copy_redraw_lines(wp
, data
->cy
, 1);
1506 window_copy_scroll_up(struct window_pane
*wp
, u_int ny
)
1508 struct window_copy_mode_data
*data
= wp
->modedata
;
1509 struct screen
*s
= &data
->screen
;
1510 struct screen_write_ctx ctx
;
1518 screen_write_start(&ctx
, wp
, NULL
);
1519 screen_write_cursormove(&ctx
, 0, 0);
1520 screen_write_deleteline(&ctx
, ny
);
1521 window_copy_write_lines(wp
, &ctx
, screen_size_y(s
) - ny
, ny
);
1522 window_copy_write_line(wp
, &ctx
, 0);
1523 if (screen_size_y(s
) > 1)
1524 window_copy_write_line(wp
, &ctx
, 1);
1525 if (screen_size_y(s
) > 3)
1526 window_copy_write_line(wp
, &ctx
, screen_size_y(s
) - 2);
1527 if (s
->sel
.flag
&& screen_size_y(s
) > ny
) {
1528 window_copy_update_selection(wp
);
1529 window_copy_write_line(wp
, &ctx
, screen_size_y(s
) - ny
- 1);
1531 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1532 window_copy_update_selection(wp
);
1533 screen_write_stop(&ctx
);
1537 window_copy_scroll_down(struct window_pane
*wp
, u_int ny
)
1539 struct window_copy_mode_data
*data
= wp
->modedata
;
1540 struct screen
*s
= &data
->screen
;
1541 struct screen_write_ctx ctx
;
1543 if (ny
> screen_hsize(&wp
->base
))
1546 if (data
->oy
> screen_hsize(&wp
->base
) - ny
)
1547 ny
= screen_hsize(&wp
->base
) - data
->oy
;
1552 screen_write_start(&ctx
, wp
, NULL
);
1553 screen_write_cursormove(&ctx
, 0, 0);
1554 screen_write_insertline(&ctx
, ny
);
1555 window_copy_write_lines(wp
, &ctx
, 0, ny
);
1556 if (s
->sel
.flag
&& screen_size_y(s
) > ny
) {
1557 window_copy_update_selection(wp
);
1558 window_copy_write_line(wp
, &ctx
, ny
);
1559 } else if (ny
== 1) /* nuke position */
1560 window_copy_write_line(wp
, &ctx
, 1);
1561 screen_write_cursormove(&ctx
, data
->cx
, data
->cy
);
1562 window_copy_update_selection(wp
);
1563 screen_write_stop(&ctx
);
1567 window_copy_rectangle_toggle(struct window_pane
*wp
)
1569 struct window_copy_mode_data
*data
= wp
->modedata
;
1572 data
->rectflag
= !data
->rectflag
;
1574 py
= screen_hsize(&wp
->base
) + data
->cy
- data
->oy
;
1575 px
= window_copy_find_length(wp
, py
);
1577 window_copy_update_cursor(wp
, px
, data
->cy
);
1579 window_copy_update_selection(wp
);
1580 window_copy_redraw_screen(wp
);