1*eda6f593SDavid van Moolenbroek /* $Id: window-copy.c,v 1.2 2011/08/17 19:28:36 jmmv Exp $ */ 2*eda6f593SDavid van Moolenbroek 3*eda6f593SDavid van Moolenbroek /* 4*eda6f593SDavid van Moolenbroek * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> 5*eda6f593SDavid van Moolenbroek * 6*eda6f593SDavid van Moolenbroek * Permission to use, copy, modify, and distribute this software for any 7*eda6f593SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above 8*eda6f593SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies. 9*eda6f593SDavid van Moolenbroek * 10*eda6f593SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*eda6f593SDavid van Moolenbroek * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*eda6f593SDavid van Moolenbroek * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*eda6f593SDavid van Moolenbroek * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*eda6f593SDavid van Moolenbroek * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15*eda6f593SDavid van Moolenbroek * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16*eda6f593SDavid van Moolenbroek * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*eda6f593SDavid van Moolenbroek */ 18*eda6f593SDavid van Moolenbroek 19*eda6f593SDavid van Moolenbroek #include <sys/types.h> 20*eda6f593SDavid van Moolenbroek 21*eda6f593SDavid van Moolenbroek #include <stdlib.h> 22*eda6f593SDavid van Moolenbroek #include <string.h> 23*eda6f593SDavid van Moolenbroek 24*eda6f593SDavid van Moolenbroek #include "tmux.h" 25*eda6f593SDavid van Moolenbroek 26*eda6f593SDavid van Moolenbroek struct screen *window_copy_init(struct window_pane *); 27*eda6f593SDavid van Moolenbroek void window_copy_free(struct window_pane *); 28*eda6f593SDavid van Moolenbroek void window_copy_resize(struct window_pane *, u_int, u_int); 29*eda6f593SDavid van Moolenbroek void window_copy_key(struct window_pane *, struct session *, int); 30*eda6f593SDavid van Moolenbroek int window_copy_key_input(struct window_pane *, int); 31*eda6f593SDavid van Moolenbroek int window_copy_key_numeric_prefix(struct window_pane *, int); 32*eda6f593SDavid van Moolenbroek void window_copy_mouse( 33*eda6f593SDavid van Moolenbroek struct window_pane *, struct session *, struct mouse_event *); 34*eda6f593SDavid van Moolenbroek 35*eda6f593SDavid van Moolenbroek void window_copy_redraw_lines(struct window_pane *, u_int, u_int); 36*eda6f593SDavid van Moolenbroek void window_copy_redraw_screen(struct window_pane *); 37*eda6f593SDavid van Moolenbroek void window_copy_write_line( 38*eda6f593SDavid van Moolenbroek struct window_pane *, struct screen_write_ctx *, u_int); 39*eda6f593SDavid van Moolenbroek void window_copy_write_lines( 40*eda6f593SDavid van Moolenbroek struct window_pane *, struct screen_write_ctx *, u_int, u_int); 41*eda6f593SDavid van Moolenbroek 42*eda6f593SDavid van Moolenbroek void window_copy_scroll_to(struct window_pane *, u_int, u_int); 43*eda6f593SDavid van Moolenbroek int window_copy_search_compare( 44*eda6f593SDavid van Moolenbroek struct grid *, u_int, u_int, struct grid *, u_int); 45*eda6f593SDavid van Moolenbroek int window_copy_search_lr( 46*eda6f593SDavid van Moolenbroek struct grid *, struct grid *, u_int *, u_int, u_int, u_int); 47*eda6f593SDavid van Moolenbroek int window_copy_search_rl( 48*eda6f593SDavid van Moolenbroek struct grid *, struct grid *, u_int *, u_int, u_int, u_int); 49*eda6f593SDavid van Moolenbroek void window_copy_search_up(struct window_pane *, const char *); 50*eda6f593SDavid van Moolenbroek void window_copy_search_down(struct window_pane *, const char *); 51*eda6f593SDavid van Moolenbroek void window_copy_goto_line(struct window_pane *, const char *); 52*eda6f593SDavid van Moolenbroek void window_copy_update_cursor(struct window_pane *, u_int, u_int); 53*eda6f593SDavid van Moolenbroek void window_copy_start_selection(struct window_pane *); 54*eda6f593SDavid van Moolenbroek int window_copy_update_selection(struct window_pane *); 55*eda6f593SDavid van Moolenbroek void window_copy_copy_selection(struct window_pane *); 56*eda6f593SDavid van Moolenbroek void window_copy_clear_selection(struct window_pane *); 57*eda6f593SDavid van Moolenbroek void window_copy_copy_line( 58*eda6f593SDavid van Moolenbroek struct window_pane *, char **, size_t *, u_int, u_int, u_int); 59*eda6f593SDavid van Moolenbroek int window_copy_in_set(struct window_pane *, u_int, u_int, const char *); 60*eda6f593SDavid van Moolenbroek u_int window_copy_find_length(struct window_pane *, u_int); 61*eda6f593SDavid van Moolenbroek void window_copy_cursor_start_of_line(struct window_pane *); 62*eda6f593SDavid van Moolenbroek void window_copy_cursor_back_to_indentation(struct window_pane *); 63*eda6f593SDavid van Moolenbroek void window_copy_cursor_end_of_line(struct window_pane *); 64*eda6f593SDavid van Moolenbroek void window_copy_cursor_left(struct window_pane *); 65*eda6f593SDavid van Moolenbroek void window_copy_cursor_right(struct window_pane *); 66*eda6f593SDavid van Moolenbroek void window_copy_cursor_up(struct window_pane *, int); 67*eda6f593SDavid van Moolenbroek void window_copy_cursor_down(struct window_pane *, int); 68*eda6f593SDavid van Moolenbroek void window_copy_cursor_jump(struct window_pane *); 69*eda6f593SDavid van Moolenbroek void window_copy_cursor_jump_back(struct window_pane *); 70*eda6f593SDavid van Moolenbroek void window_copy_cursor_next_word(struct window_pane *, const char *); 71*eda6f593SDavid van Moolenbroek void window_copy_cursor_next_word_end(struct window_pane *, const char *); 72*eda6f593SDavid van Moolenbroek void window_copy_cursor_previous_word(struct window_pane *, const char *); 73*eda6f593SDavid van Moolenbroek void window_copy_scroll_up(struct window_pane *, u_int); 74*eda6f593SDavid van Moolenbroek void window_copy_scroll_down(struct window_pane *, u_int); 75*eda6f593SDavid van Moolenbroek void window_copy_rectangle_toggle(struct window_pane *); 76*eda6f593SDavid van Moolenbroek 77*eda6f593SDavid van Moolenbroek const struct window_mode window_copy_mode = { 78*eda6f593SDavid van Moolenbroek window_copy_init, 79*eda6f593SDavid van Moolenbroek window_copy_free, 80*eda6f593SDavid van Moolenbroek window_copy_resize, 81*eda6f593SDavid van Moolenbroek window_copy_key, 82*eda6f593SDavid van Moolenbroek window_copy_mouse, 83*eda6f593SDavid van Moolenbroek NULL, 84*eda6f593SDavid van Moolenbroek }; 85*eda6f593SDavid van Moolenbroek 86*eda6f593SDavid van Moolenbroek enum window_copy_input_type { 87*eda6f593SDavid van Moolenbroek WINDOW_COPY_OFF, 88*eda6f593SDavid van Moolenbroek WINDOW_COPY_NUMERICPREFIX, 89*eda6f593SDavid van Moolenbroek WINDOW_COPY_SEARCHUP, 90*eda6f593SDavid van Moolenbroek WINDOW_COPY_SEARCHDOWN, 91*eda6f593SDavid van Moolenbroek WINDOW_COPY_JUMPFORWARD, 92*eda6f593SDavid van Moolenbroek WINDOW_COPY_JUMPBACK, 93*eda6f593SDavid van Moolenbroek WINDOW_COPY_GOTOLINE, 94*eda6f593SDavid van Moolenbroek }; 95*eda6f593SDavid van Moolenbroek 96*eda6f593SDavid van Moolenbroek /* 97*eda6f593SDavid van Moolenbroek * Copy-mode's visible screen (the "screen" field) is filled from one of 98*eda6f593SDavid van Moolenbroek * two sources: the original contents of the pane (used when we 99*eda6f593SDavid van Moolenbroek * actually enter via the "copy-mode" command, to copy the contents of 100*eda6f593SDavid van Moolenbroek * the current pane), or else a series of lines containing the output 101*eda6f593SDavid van Moolenbroek * from an output-writing tmux command (such as any of the "show-*" or 102*eda6f593SDavid van Moolenbroek * "list-*" commands). 103*eda6f593SDavid van Moolenbroek * 104*eda6f593SDavid van Moolenbroek * In either case, the full content of the copy-mode grid is pointed at 105*eda6f593SDavid van Moolenbroek * by the "backing" field, and is copied into "screen" as needed (that 106*eda6f593SDavid van Moolenbroek * is, when scrolling occurs). When copy-mode is backed by a pane, 107*eda6f593SDavid van Moolenbroek * backing points directly at that pane's screen structure (&wp->base); 108*eda6f593SDavid van Moolenbroek * when backed by a list of output-lines from a command, it points at 109*eda6f593SDavid van Moolenbroek * a newly-allocated screen structure (which is deallocated when the 110*eda6f593SDavid van Moolenbroek * mode ends). 111*eda6f593SDavid van Moolenbroek */ 112*eda6f593SDavid van Moolenbroek struct window_copy_mode_data { 113*eda6f593SDavid van Moolenbroek struct screen screen; 114*eda6f593SDavid van Moolenbroek 115*eda6f593SDavid van Moolenbroek struct screen *backing; 116*eda6f593SDavid van Moolenbroek int backing_written; /* backing display has started */ 117*eda6f593SDavid van Moolenbroek 118*eda6f593SDavid van Moolenbroek struct mode_key_data mdata; 119*eda6f593SDavid van Moolenbroek 120*eda6f593SDavid van Moolenbroek u_int oy; 121*eda6f593SDavid van Moolenbroek 122*eda6f593SDavid van Moolenbroek u_int selx; 123*eda6f593SDavid van Moolenbroek u_int sely; 124*eda6f593SDavid van Moolenbroek 125*eda6f593SDavid van Moolenbroek u_int rectflag; /* are we in rectangle copy mode? */ 126*eda6f593SDavid van Moolenbroek 127*eda6f593SDavid van Moolenbroek u_int cx; 128*eda6f593SDavid van Moolenbroek u_int cy; 129*eda6f593SDavid van Moolenbroek 130*eda6f593SDavid van Moolenbroek u_int lastcx; /* position in last line with content */ 131*eda6f593SDavid van Moolenbroek u_int lastsx; /* size of last line with content */ 132*eda6f593SDavid van Moolenbroek 133*eda6f593SDavid van Moolenbroek enum window_copy_input_type inputtype; 134*eda6f593SDavid van Moolenbroek const char *inputprompt; 135*eda6f593SDavid van Moolenbroek char *inputstr; 136*eda6f593SDavid van Moolenbroek 137*eda6f593SDavid van Moolenbroek u_int numprefix; 138*eda6f593SDavid van Moolenbroek 139*eda6f593SDavid van Moolenbroek enum window_copy_input_type searchtype; 140*eda6f593SDavid van Moolenbroek char *searchstr; 141*eda6f593SDavid van Moolenbroek 142*eda6f593SDavid van Moolenbroek enum window_copy_input_type jumptype; 143*eda6f593SDavid van Moolenbroek char jumpchar; 144*eda6f593SDavid van Moolenbroek }; 145*eda6f593SDavid van Moolenbroek 146*eda6f593SDavid van Moolenbroek struct screen * 147*eda6f593SDavid van Moolenbroek window_copy_init(struct window_pane *wp) 148*eda6f593SDavid van Moolenbroek { 149*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data; 150*eda6f593SDavid van Moolenbroek struct screen *s; 151*eda6f593SDavid van Moolenbroek int keys; 152*eda6f593SDavid van Moolenbroek 153*eda6f593SDavid van Moolenbroek wp->modedata = data = xmalloc(sizeof *data); 154*eda6f593SDavid van Moolenbroek data->oy = 0; 155*eda6f593SDavid van Moolenbroek data->cx = 0; 156*eda6f593SDavid van Moolenbroek data->cy = 0; 157*eda6f593SDavid van Moolenbroek 158*eda6f593SDavid van Moolenbroek data->lastcx = 0; 159*eda6f593SDavid van Moolenbroek data->lastsx = 0; 160*eda6f593SDavid van Moolenbroek 161*eda6f593SDavid van Moolenbroek data->backing_written = 0; 162*eda6f593SDavid van Moolenbroek 163*eda6f593SDavid van Moolenbroek data->rectflag = 0; 164*eda6f593SDavid van Moolenbroek 165*eda6f593SDavid van Moolenbroek data->inputtype = WINDOW_COPY_OFF; 166*eda6f593SDavid van Moolenbroek data->inputprompt = NULL; 167*eda6f593SDavid van Moolenbroek data->inputstr = xstrdup(""); 168*eda6f593SDavid van Moolenbroek data->numprefix = 0; 169*eda6f593SDavid van Moolenbroek 170*eda6f593SDavid van Moolenbroek data->searchtype = WINDOW_COPY_OFF; 171*eda6f593SDavid van Moolenbroek data->searchstr = NULL; 172*eda6f593SDavid van Moolenbroek 173*eda6f593SDavid van Moolenbroek if (wp->fd != -1) 174*eda6f593SDavid van Moolenbroek bufferevent_disable(wp->event, EV_READ|EV_WRITE); 175*eda6f593SDavid van Moolenbroek 176*eda6f593SDavid van Moolenbroek data->jumptype = WINDOW_COPY_OFF; 177*eda6f593SDavid van Moolenbroek data->jumpchar = '\0'; 178*eda6f593SDavid van Moolenbroek 179*eda6f593SDavid van Moolenbroek s = &data->screen; 180*eda6f593SDavid van Moolenbroek screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); 181*eda6f593SDavid van Moolenbroek if (options_get_number(&wp->window->options, "mode-mouse")) 182*eda6f593SDavid van Moolenbroek s->mode |= MODE_MOUSE_STANDARD; 183*eda6f593SDavid van Moolenbroek 184*eda6f593SDavid van Moolenbroek keys = options_get_number(&wp->window->options, "mode-keys"); 185*eda6f593SDavid van Moolenbroek if (keys == MODEKEY_EMACS) 186*eda6f593SDavid van Moolenbroek mode_key_init(&data->mdata, &mode_key_tree_emacs_copy); 187*eda6f593SDavid van Moolenbroek else 188*eda6f593SDavid van Moolenbroek mode_key_init(&data->mdata, &mode_key_tree_vi_copy); 189*eda6f593SDavid van Moolenbroek 190*eda6f593SDavid van Moolenbroek data->backing = NULL; 191*eda6f593SDavid van Moolenbroek 192*eda6f593SDavid van Moolenbroek return (s); 193*eda6f593SDavid van Moolenbroek } 194*eda6f593SDavid van Moolenbroek 195*eda6f593SDavid van Moolenbroek void 196*eda6f593SDavid van Moolenbroek window_copy_init_from_pane(struct window_pane *wp) 197*eda6f593SDavid van Moolenbroek { 198*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 199*eda6f593SDavid van Moolenbroek struct screen *s = &data->screen; 200*eda6f593SDavid van Moolenbroek struct screen_write_ctx ctx; 201*eda6f593SDavid van Moolenbroek u_int i; 202*eda6f593SDavid van Moolenbroek 203*eda6f593SDavid van Moolenbroek if (wp->mode != &window_copy_mode) 204*eda6f593SDavid van Moolenbroek fatalx("not in copy mode"); 205*eda6f593SDavid van Moolenbroek 206*eda6f593SDavid van Moolenbroek data->backing = &wp->base; 207*eda6f593SDavid van Moolenbroek data->cx = data->backing->cx; 208*eda6f593SDavid van Moolenbroek data->cy = data->backing->cy; 209*eda6f593SDavid van Moolenbroek 210*eda6f593SDavid van Moolenbroek s->cx = data->cx; 211*eda6f593SDavid van Moolenbroek s->cy = data->cy; 212*eda6f593SDavid van Moolenbroek 213*eda6f593SDavid van Moolenbroek screen_write_start(&ctx, NULL, s); 214*eda6f593SDavid van Moolenbroek for (i = 0; i < screen_size_y(s); i++) 215*eda6f593SDavid van Moolenbroek window_copy_write_line(wp, &ctx, i); 216*eda6f593SDavid van Moolenbroek screen_write_cursormove(&ctx, data->cx, data->cy); 217*eda6f593SDavid van Moolenbroek screen_write_stop(&ctx); 218*eda6f593SDavid van Moolenbroek } 219*eda6f593SDavid van Moolenbroek 220*eda6f593SDavid van Moolenbroek void 221*eda6f593SDavid van Moolenbroek window_copy_init_for_output(struct window_pane *wp) 222*eda6f593SDavid van Moolenbroek { 223*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 224*eda6f593SDavid van Moolenbroek 225*eda6f593SDavid van Moolenbroek data->backing = xmalloc(sizeof *data->backing); 226*eda6f593SDavid van Moolenbroek screen_init(data->backing, screen_size_x(&wp->base), 227*eda6f593SDavid van Moolenbroek screen_size_y(&wp->base), UINT_MAX); 228*eda6f593SDavid van Moolenbroek data->backing->mode &= ~MODE_WRAP; 229*eda6f593SDavid van Moolenbroek } 230*eda6f593SDavid van Moolenbroek 231*eda6f593SDavid van Moolenbroek void 232*eda6f593SDavid van Moolenbroek window_copy_free(struct window_pane *wp) 233*eda6f593SDavid van Moolenbroek { 234*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 235*eda6f593SDavid van Moolenbroek 236*eda6f593SDavid van Moolenbroek if (wp->fd != -1) 237*eda6f593SDavid van Moolenbroek bufferevent_enable(wp->event, EV_READ|EV_WRITE); 238*eda6f593SDavid van Moolenbroek 239*eda6f593SDavid van Moolenbroek if (data->searchstr != NULL) 240*eda6f593SDavid van Moolenbroek xfree(data->searchstr); 241*eda6f593SDavid van Moolenbroek xfree(data->inputstr); 242*eda6f593SDavid van Moolenbroek 243*eda6f593SDavid van Moolenbroek if (data->backing != &wp->base) { 244*eda6f593SDavid van Moolenbroek screen_free(data->backing); 245*eda6f593SDavid van Moolenbroek xfree(data->backing); 246*eda6f593SDavid van Moolenbroek } 247*eda6f593SDavid van Moolenbroek screen_free(&data->screen); 248*eda6f593SDavid van Moolenbroek 249*eda6f593SDavid van Moolenbroek xfree(data); 250*eda6f593SDavid van Moolenbroek } 251*eda6f593SDavid van Moolenbroek 252*eda6f593SDavid van Moolenbroek void 253*eda6f593SDavid van Moolenbroek window_copy_add(struct window_pane *wp, const char *fmt, ...) 254*eda6f593SDavid van Moolenbroek { 255*eda6f593SDavid van Moolenbroek va_list ap; 256*eda6f593SDavid van Moolenbroek 257*eda6f593SDavid van Moolenbroek va_start(ap, fmt); 258*eda6f593SDavid van Moolenbroek window_copy_vadd(wp, fmt, ap); 259*eda6f593SDavid van Moolenbroek va_end(ap); 260*eda6f593SDavid van Moolenbroek } 261*eda6f593SDavid van Moolenbroek 262*eda6f593SDavid van Moolenbroek void 263*eda6f593SDavid van Moolenbroek window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap) 264*eda6f593SDavid van Moolenbroek { 265*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 266*eda6f593SDavid van Moolenbroek struct screen *backing = data->backing; 267*eda6f593SDavid van Moolenbroek struct screen_write_ctx back_ctx, ctx; 268*eda6f593SDavid van Moolenbroek struct grid_cell gc; 269*eda6f593SDavid van Moolenbroek int utf8flag; 270*eda6f593SDavid van Moolenbroek u_int old_hsize; 271*eda6f593SDavid van Moolenbroek 272*eda6f593SDavid van Moolenbroek if (backing == &wp->base) 273*eda6f593SDavid van Moolenbroek return; 274*eda6f593SDavid van Moolenbroek 275*eda6f593SDavid van Moolenbroek utf8flag = options_get_number(&wp->window->options, "utf8"); 276*eda6f593SDavid van Moolenbroek memcpy(&gc, &grid_default_cell, sizeof gc); 277*eda6f593SDavid van Moolenbroek 278*eda6f593SDavid van Moolenbroek old_hsize = screen_hsize(data->backing); 279*eda6f593SDavid van Moolenbroek screen_write_start(&back_ctx, NULL, backing); 280*eda6f593SDavid van Moolenbroek if (data->backing_written) { 281*eda6f593SDavid van Moolenbroek /* 282*eda6f593SDavid van Moolenbroek * On the second or later line, do a CRLF before writing 283*eda6f593SDavid van Moolenbroek * (so it's on a new line). 284*eda6f593SDavid van Moolenbroek */ 285*eda6f593SDavid van Moolenbroek screen_write_carriagereturn(&back_ctx); 286*eda6f593SDavid van Moolenbroek screen_write_linefeed(&back_ctx, 0); 287*eda6f593SDavid van Moolenbroek } else 288*eda6f593SDavid van Moolenbroek data->backing_written = 1; 289*eda6f593SDavid van Moolenbroek screen_write_vnputs(&back_ctx, 0, &gc, utf8flag, fmt, ap); 290*eda6f593SDavid van Moolenbroek screen_write_stop(&back_ctx); 291*eda6f593SDavid van Moolenbroek 292*eda6f593SDavid van Moolenbroek data->oy += screen_hsize(data->backing) - old_hsize; 293*eda6f593SDavid van Moolenbroek 294*eda6f593SDavid van Moolenbroek screen_write_start(&ctx, wp, &data->screen); 295*eda6f593SDavid van Moolenbroek 296*eda6f593SDavid van Moolenbroek /* 297*eda6f593SDavid van Moolenbroek * If the history has changed, draw the top line. 298*eda6f593SDavid van Moolenbroek * (If there's any history at all, it has changed.) 299*eda6f593SDavid van Moolenbroek */ 300*eda6f593SDavid van Moolenbroek if (screen_hsize(data->backing)) 301*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, 0, 1); 302*eda6f593SDavid van Moolenbroek 303*eda6f593SDavid van Moolenbroek /* Write the line, if it's visible. */ 304*eda6f593SDavid van Moolenbroek if (backing->cy + data->oy < screen_size_y(backing)) 305*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, backing->cy, 1); 306*eda6f593SDavid van Moolenbroek 307*eda6f593SDavid van Moolenbroek screen_write_stop(&ctx); 308*eda6f593SDavid van Moolenbroek } 309*eda6f593SDavid van Moolenbroek 310*eda6f593SDavid van Moolenbroek void 311*eda6f593SDavid van Moolenbroek window_copy_pageup(struct window_pane *wp) 312*eda6f593SDavid van Moolenbroek { 313*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 314*eda6f593SDavid van Moolenbroek struct screen *s = &data->screen; 315*eda6f593SDavid van Moolenbroek u_int n; 316*eda6f593SDavid van Moolenbroek 317*eda6f593SDavid van Moolenbroek n = 1; 318*eda6f593SDavid van Moolenbroek if (screen_size_y(s) > 2) 319*eda6f593SDavid van Moolenbroek n = screen_size_y(s) - 2; 320*eda6f593SDavid van Moolenbroek if (data->oy + n > screen_hsize(data->backing)) 321*eda6f593SDavid van Moolenbroek data->oy = screen_hsize(data->backing); 322*eda6f593SDavid van Moolenbroek else 323*eda6f593SDavid van Moolenbroek data->oy += n; 324*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 325*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 326*eda6f593SDavid van Moolenbroek } 327*eda6f593SDavid van Moolenbroek 328*eda6f593SDavid van Moolenbroek void 329*eda6f593SDavid van Moolenbroek window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) 330*eda6f593SDavid van Moolenbroek { 331*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 332*eda6f593SDavid van Moolenbroek struct screen *s = &data->screen; 333*eda6f593SDavid van Moolenbroek struct screen_write_ctx ctx; 334*eda6f593SDavid van Moolenbroek 335*eda6f593SDavid van Moolenbroek screen_resize(s, sx, sy); 336*eda6f593SDavid van Moolenbroek if (data->backing != &wp->base) 337*eda6f593SDavid van Moolenbroek screen_resize(data->backing, sx, sy); 338*eda6f593SDavid van Moolenbroek 339*eda6f593SDavid van Moolenbroek if (data->cy > sy - 1) 340*eda6f593SDavid van Moolenbroek data->cy = sy - 1; 341*eda6f593SDavid van Moolenbroek if (data->cx > sx) 342*eda6f593SDavid van Moolenbroek data->cx = sx; 343*eda6f593SDavid van Moolenbroek if (data->oy > screen_hsize(data->backing)) 344*eda6f593SDavid van Moolenbroek data->oy = screen_hsize(data->backing); 345*eda6f593SDavid van Moolenbroek 346*eda6f593SDavid van Moolenbroek window_copy_clear_selection(wp); 347*eda6f593SDavid van Moolenbroek 348*eda6f593SDavid van Moolenbroek screen_write_start(&ctx, NULL, s); 349*eda6f593SDavid van Moolenbroek window_copy_write_lines(wp, &ctx, 0, screen_size_y(s) - 1); 350*eda6f593SDavid van Moolenbroek screen_write_stop(&ctx); 351*eda6f593SDavid van Moolenbroek 352*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 353*eda6f593SDavid van Moolenbroek } 354*eda6f593SDavid van Moolenbroek 355*eda6f593SDavid van Moolenbroek void 356*eda6f593SDavid van Moolenbroek window_copy_key(struct window_pane *wp, struct session *sess, int key) 357*eda6f593SDavid van Moolenbroek { 358*eda6f593SDavid van Moolenbroek const char *word_separators; 359*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 360*eda6f593SDavid van Moolenbroek struct screen *s = &data->screen; 361*eda6f593SDavid van Moolenbroek u_int n, np; 362*eda6f593SDavid van Moolenbroek int keys; 363*eda6f593SDavid van Moolenbroek enum mode_key_cmd cmd; 364*eda6f593SDavid van Moolenbroek 365*eda6f593SDavid van Moolenbroek np = data->numprefix; 366*eda6f593SDavid van Moolenbroek if (np == 0) 367*eda6f593SDavid van Moolenbroek np = 1; 368*eda6f593SDavid van Moolenbroek 369*eda6f593SDavid van Moolenbroek if (data->inputtype == WINDOW_COPY_JUMPFORWARD || 370*eda6f593SDavid van Moolenbroek data->inputtype == WINDOW_COPY_JUMPBACK) { 371*eda6f593SDavid van Moolenbroek /* Ignore keys with modifiers. */ 372*eda6f593SDavid van Moolenbroek if ((key & KEYC_MASK_MOD) == 0) { 373*eda6f593SDavid van Moolenbroek data->jumpchar = key; 374*eda6f593SDavid van Moolenbroek if (data->inputtype == WINDOW_COPY_JUMPFORWARD) { 375*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 376*eda6f593SDavid van Moolenbroek window_copy_cursor_jump(wp); 377*eda6f593SDavid van Moolenbroek } else { 378*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 379*eda6f593SDavid van Moolenbroek window_copy_cursor_jump_back(wp); 380*eda6f593SDavid van Moolenbroek } 381*eda6f593SDavid van Moolenbroek } 382*eda6f593SDavid van Moolenbroek data->jumptype = data->inputtype; 383*eda6f593SDavid van Moolenbroek data->inputtype = WINDOW_COPY_OFF; 384*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); 385*eda6f593SDavid van Moolenbroek return; 386*eda6f593SDavid van Moolenbroek } else if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) { 387*eda6f593SDavid van Moolenbroek if (window_copy_key_numeric_prefix(wp, key) == 0) 388*eda6f593SDavid van Moolenbroek return; 389*eda6f593SDavid van Moolenbroek data->inputtype = WINDOW_COPY_OFF; 390*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); 391*eda6f593SDavid van Moolenbroek } else if (data->inputtype != WINDOW_COPY_OFF) { 392*eda6f593SDavid van Moolenbroek if (window_copy_key_input(wp, key) != 0) 393*eda6f593SDavid van Moolenbroek goto input_off; 394*eda6f593SDavid van Moolenbroek return; 395*eda6f593SDavid van Moolenbroek } 396*eda6f593SDavid van Moolenbroek 397*eda6f593SDavid van Moolenbroek cmd = mode_key_lookup(&data->mdata, key); 398*eda6f593SDavid van Moolenbroek switch (cmd) { 399*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_CANCEL: 400*eda6f593SDavid van Moolenbroek window_pane_reset_mode(wp); 401*eda6f593SDavid van Moolenbroek return; 402*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_LEFT: 403*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 404*eda6f593SDavid van Moolenbroek window_copy_cursor_left(wp); 405*eda6f593SDavid van Moolenbroek break; 406*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_RIGHT: 407*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 408*eda6f593SDavid van Moolenbroek window_copy_cursor_right(wp); 409*eda6f593SDavid van Moolenbroek break; 410*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_UP: 411*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 412*eda6f593SDavid van Moolenbroek window_copy_cursor_up(wp, 0); 413*eda6f593SDavid van Moolenbroek break; 414*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_DOWN: 415*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 416*eda6f593SDavid van Moolenbroek window_copy_cursor_down(wp, 0); 417*eda6f593SDavid van Moolenbroek break; 418*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_SCROLLUP: 419*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 420*eda6f593SDavid van Moolenbroek window_copy_cursor_up(wp, 1); 421*eda6f593SDavid van Moolenbroek break; 422*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_SCROLLDOWN: 423*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 424*eda6f593SDavid van Moolenbroek window_copy_cursor_down(wp, 1); 425*eda6f593SDavid van Moolenbroek break; 426*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_PREVIOUSPAGE: 427*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 428*eda6f593SDavid van Moolenbroek window_copy_pageup(wp); 429*eda6f593SDavid van Moolenbroek break; 430*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_NEXTPAGE: 431*eda6f593SDavid van Moolenbroek n = 1; 432*eda6f593SDavid van Moolenbroek if (screen_size_y(s) > 2) 433*eda6f593SDavid van Moolenbroek n = screen_size_y(s) - 2; 434*eda6f593SDavid van Moolenbroek for (; np != 0; np--) { 435*eda6f593SDavid van Moolenbroek if (data->oy < n) 436*eda6f593SDavid van Moolenbroek data->oy = 0; 437*eda6f593SDavid van Moolenbroek else 438*eda6f593SDavid van Moolenbroek data->oy -= n; 439*eda6f593SDavid van Moolenbroek } 440*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 441*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 442*eda6f593SDavid van Moolenbroek break; 443*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_HALFPAGEUP: 444*eda6f593SDavid van Moolenbroek n = screen_size_y(s) / 2; 445*eda6f593SDavid van Moolenbroek for (; np != 0; np--) { 446*eda6f593SDavid van Moolenbroek if (data->oy + n > screen_hsize(data->backing)) 447*eda6f593SDavid van Moolenbroek data->oy = screen_hsize(data->backing); 448*eda6f593SDavid van Moolenbroek else 449*eda6f593SDavid van Moolenbroek data->oy += n; 450*eda6f593SDavid van Moolenbroek } 451*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 452*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 453*eda6f593SDavid van Moolenbroek break; 454*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_HALFPAGEDOWN: 455*eda6f593SDavid van Moolenbroek n = screen_size_y(s) / 2; 456*eda6f593SDavid van Moolenbroek for (; np != 0; np--) { 457*eda6f593SDavid van Moolenbroek if (data->oy < n) 458*eda6f593SDavid van Moolenbroek data->oy = 0; 459*eda6f593SDavid van Moolenbroek else 460*eda6f593SDavid van Moolenbroek data->oy -= n; 461*eda6f593SDavid van Moolenbroek } 462*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 463*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 464*eda6f593SDavid van Moolenbroek break; 465*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_TOPLINE: 466*eda6f593SDavid van Moolenbroek data->cx = 0; 467*eda6f593SDavid van Moolenbroek data->cy = 0; 468*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 469*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 470*eda6f593SDavid van Moolenbroek break; 471*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_MIDDLELINE: 472*eda6f593SDavid van Moolenbroek data->cx = 0; 473*eda6f593SDavid van Moolenbroek data->cy = (screen_size_y(s) - 1) / 2; 474*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 475*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 476*eda6f593SDavid van Moolenbroek break; 477*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_BOTTOMLINE: 478*eda6f593SDavid van Moolenbroek data->cx = 0; 479*eda6f593SDavid van Moolenbroek data->cy = screen_size_y(s) - 1; 480*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 481*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 482*eda6f593SDavid van Moolenbroek break; 483*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_HISTORYTOP: 484*eda6f593SDavid van Moolenbroek data->cx = 0; 485*eda6f593SDavid van Moolenbroek data->cy = 0; 486*eda6f593SDavid van Moolenbroek data->oy = screen_hsize(data->backing); 487*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 488*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 489*eda6f593SDavid van Moolenbroek break; 490*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_HISTORYBOTTOM: 491*eda6f593SDavid van Moolenbroek data->cx = 0; 492*eda6f593SDavid van Moolenbroek data->cy = screen_size_y(s) - 1; 493*eda6f593SDavid van Moolenbroek data->oy = 0; 494*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 495*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 496*eda6f593SDavid van Moolenbroek break; 497*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_STARTSELECTION: 498*eda6f593SDavid van Moolenbroek window_copy_start_selection(wp); 499*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 500*eda6f593SDavid van Moolenbroek break; 501*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_COPYLINE: 502*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_SELECTLINE: 503*eda6f593SDavid van Moolenbroek window_copy_cursor_start_of_line(wp); 504*eda6f593SDavid van Moolenbroek /* FALLTHROUGH */ 505*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_COPYENDOFLINE: 506*eda6f593SDavid van Moolenbroek window_copy_start_selection(wp); 507*eda6f593SDavid van Moolenbroek for (; np > 1; np--) 508*eda6f593SDavid van Moolenbroek window_copy_cursor_down(wp, 0); 509*eda6f593SDavid van Moolenbroek window_copy_cursor_end_of_line(wp); 510*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 511*eda6f593SDavid van Moolenbroek 512*eda6f593SDavid van Moolenbroek /* If a copy command then copy the selection and exit. */ 513*eda6f593SDavid van Moolenbroek if (sess != NULL && 514*eda6f593SDavid van Moolenbroek (cmd == MODEKEYCOPY_COPYLINE || 515*eda6f593SDavid van Moolenbroek cmd == MODEKEYCOPY_COPYENDOFLINE)) { 516*eda6f593SDavid van Moolenbroek window_copy_copy_selection(wp); 517*eda6f593SDavid van Moolenbroek window_pane_reset_mode(wp); 518*eda6f593SDavid van Moolenbroek return; 519*eda6f593SDavid van Moolenbroek } 520*eda6f593SDavid van Moolenbroek break; 521*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_CLEARSELECTION: 522*eda6f593SDavid van Moolenbroek window_copy_clear_selection(wp); 523*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 524*eda6f593SDavid van Moolenbroek break; 525*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_COPYSELECTION: 526*eda6f593SDavid van Moolenbroek if (sess != NULL) { 527*eda6f593SDavid van Moolenbroek window_copy_copy_selection(wp); 528*eda6f593SDavid van Moolenbroek window_pane_reset_mode(wp); 529*eda6f593SDavid van Moolenbroek return; 530*eda6f593SDavid van Moolenbroek } 531*eda6f593SDavid van Moolenbroek break; 532*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_STARTOFLINE: 533*eda6f593SDavid van Moolenbroek window_copy_cursor_start_of_line(wp); 534*eda6f593SDavid van Moolenbroek break; 535*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_BACKTOINDENTATION: 536*eda6f593SDavid van Moolenbroek window_copy_cursor_back_to_indentation(wp); 537*eda6f593SDavid van Moolenbroek break; 538*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_ENDOFLINE: 539*eda6f593SDavid van Moolenbroek window_copy_cursor_end_of_line(wp); 540*eda6f593SDavid van Moolenbroek break; 541*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_NEXTSPACE: 542*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 543*eda6f593SDavid van Moolenbroek window_copy_cursor_next_word(wp, " "); 544*eda6f593SDavid van Moolenbroek break; 545*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_NEXTSPACEEND: 546*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 547*eda6f593SDavid van Moolenbroek window_copy_cursor_next_word_end(wp, " "); 548*eda6f593SDavid van Moolenbroek break; 549*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_NEXTWORD: 550*eda6f593SDavid van Moolenbroek word_separators = 551*eda6f593SDavid van Moolenbroek options_get_string(&wp->window->options, "word-separators"); 552*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 553*eda6f593SDavid van Moolenbroek window_copy_cursor_next_word(wp, word_separators); 554*eda6f593SDavid van Moolenbroek break; 555*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_NEXTWORDEND: 556*eda6f593SDavid van Moolenbroek word_separators = 557*eda6f593SDavid van Moolenbroek options_get_string(&wp->window->options, "word-separators"); 558*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 559*eda6f593SDavid van Moolenbroek window_copy_cursor_next_word_end(wp, word_separators); 560*eda6f593SDavid van Moolenbroek break; 561*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_PREVIOUSSPACE: 562*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 563*eda6f593SDavid van Moolenbroek window_copy_cursor_previous_word(wp, " "); 564*eda6f593SDavid van Moolenbroek break; 565*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_PREVIOUSWORD: 566*eda6f593SDavid van Moolenbroek word_separators = 567*eda6f593SDavid van Moolenbroek options_get_string(&wp->window->options, "word-separators"); 568*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 569*eda6f593SDavid van Moolenbroek window_copy_cursor_previous_word(wp, word_separators); 570*eda6f593SDavid van Moolenbroek break; 571*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_JUMP: 572*eda6f593SDavid van Moolenbroek data->inputtype = WINDOW_COPY_JUMPFORWARD; 573*eda6f593SDavid van Moolenbroek data->inputprompt = "Jump Forward"; 574*eda6f593SDavid van Moolenbroek *data->inputstr = '\0'; 575*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); 576*eda6f593SDavid van Moolenbroek return; /* skip numprefix reset */ 577*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_JUMPAGAIN: 578*eda6f593SDavid van Moolenbroek if (data->jumptype == WINDOW_COPY_JUMPFORWARD) { 579*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 580*eda6f593SDavid van Moolenbroek window_copy_cursor_jump(wp); 581*eda6f593SDavid van Moolenbroek } else if (data->jumptype == WINDOW_COPY_JUMPBACK) { 582*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 583*eda6f593SDavid van Moolenbroek window_copy_cursor_jump_back(wp); 584*eda6f593SDavid van Moolenbroek } 585*eda6f593SDavid van Moolenbroek break; 586*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_JUMPREVERSE: 587*eda6f593SDavid van Moolenbroek if (data->jumptype == WINDOW_COPY_JUMPFORWARD) { 588*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 589*eda6f593SDavid van Moolenbroek window_copy_cursor_jump_back(wp); 590*eda6f593SDavid van Moolenbroek } else if (data->jumptype == WINDOW_COPY_JUMPBACK) { 591*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 592*eda6f593SDavid van Moolenbroek window_copy_cursor_jump(wp); 593*eda6f593SDavid van Moolenbroek } 594*eda6f593SDavid van Moolenbroek break; 595*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_JUMPBACK: 596*eda6f593SDavid van Moolenbroek data->inputtype = WINDOW_COPY_JUMPBACK; 597*eda6f593SDavid van Moolenbroek data->inputprompt = "Jump Back"; 598*eda6f593SDavid van Moolenbroek *data->inputstr = '\0'; 599*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); 600*eda6f593SDavid van Moolenbroek return; /* skip numprefix reset */ 601*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_SEARCHUP: 602*eda6f593SDavid van Moolenbroek data->inputtype = WINDOW_COPY_SEARCHUP; 603*eda6f593SDavid van Moolenbroek data->inputprompt = "Search Up"; 604*eda6f593SDavid van Moolenbroek goto input_on; 605*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_SEARCHDOWN: 606*eda6f593SDavid van Moolenbroek data->inputtype = WINDOW_COPY_SEARCHDOWN; 607*eda6f593SDavid van Moolenbroek data->inputprompt = "Search Down"; 608*eda6f593SDavid van Moolenbroek goto input_on; 609*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_SEARCHAGAIN: 610*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_SEARCHREVERSE: 611*eda6f593SDavid van Moolenbroek switch (data->searchtype) { 612*eda6f593SDavid van Moolenbroek case WINDOW_COPY_OFF: 613*eda6f593SDavid van Moolenbroek case WINDOW_COPY_GOTOLINE: 614*eda6f593SDavid van Moolenbroek case WINDOW_COPY_JUMPFORWARD: 615*eda6f593SDavid van Moolenbroek case WINDOW_COPY_JUMPBACK: 616*eda6f593SDavid van Moolenbroek case WINDOW_COPY_NUMERICPREFIX: 617*eda6f593SDavid van Moolenbroek break; 618*eda6f593SDavid van Moolenbroek case WINDOW_COPY_SEARCHUP: 619*eda6f593SDavid van Moolenbroek if (cmd == MODEKEYCOPY_SEARCHAGAIN) { 620*eda6f593SDavid van Moolenbroek for (; np != 0; np--) { 621*eda6f593SDavid van Moolenbroek window_copy_search_up( 622*eda6f593SDavid van Moolenbroek wp, data->searchstr); 623*eda6f593SDavid van Moolenbroek } 624*eda6f593SDavid van Moolenbroek } else { 625*eda6f593SDavid van Moolenbroek for (; np != 0; np--) { 626*eda6f593SDavid van Moolenbroek window_copy_search_down( 627*eda6f593SDavid van Moolenbroek wp, data->searchstr); 628*eda6f593SDavid van Moolenbroek } 629*eda6f593SDavid van Moolenbroek } 630*eda6f593SDavid van Moolenbroek break; 631*eda6f593SDavid van Moolenbroek case WINDOW_COPY_SEARCHDOWN: 632*eda6f593SDavid van Moolenbroek if (cmd == MODEKEYCOPY_SEARCHAGAIN) { 633*eda6f593SDavid van Moolenbroek for (; np != 0; np--) { 634*eda6f593SDavid van Moolenbroek window_copy_search_down( 635*eda6f593SDavid van Moolenbroek wp, data->searchstr); 636*eda6f593SDavid van Moolenbroek } 637*eda6f593SDavid van Moolenbroek } else { 638*eda6f593SDavid van Moolenbroek for (; np != 0; np--) { 639*eda6f593SDavid van Moolenbroek window_copy_search_up( 640*eda6f593SDavid van Moolenbroek wp, data->searchstr); 641*eda6f593SDavid van Moolenbroek } 642*eda6f593SDavid van Moolenbroek } 643*eda6f593SDavid van Moolenbroek break; 644*eda6f593SDavid van Moolenbroek } 645*eda6f593SDavid van Moolenbroek break; 646*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_GOTOLINE: 647*eda6f593SDavid van Moolenbroek data->inputtype = WINDOW_COPY_GOTOLINE; 648*eda6f593SDavid van Moolenbroek data->inputprompt = "Goto Line"; 649*eda6f593SDavid van Moolenbroek *data->inputstr = '\0'; 650*eda6f593SDavid van Moolenbroek goto input_on; 651*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_STARTNUMBERPREFIX: 652*eda6f593SDavid van Moolenbroek key &= KEYC_MASK_KEY; 653*eda6f593SDavid van Moolenbroek if (key >= '0' && key <= '9') { 654*eda6f593SDavid van Moolenbroek data->inputtype = WINDOW_COPY_NUMERICPREFIX; 655*eda6f593SDavid van Moolenbroek data->numprefix = 0; 656*eda6f593SDavid van Moolenbroek window_copy_key_numeric_prefix(wp, key); 657*eda6f593SDavid van Moolenbroek return; 658*eda6f593SDavid van Moolenbroek } 659*eda6f593SDavid van Moolenbroek break; 660*eda6f593SDavid van Moolenbroek case MODEKEYCOPY_RECTANGLETOGGLE: 661*eda6f593SDavid van Moolenbroek window_copy_rectangle_toggle(wp); 662*eda6f593SDavid van Moolenbroek break; 663*eda6f593SDavid van Moolenbroek default: 664*eda6f593SDavid van Moolenbroek break; 665*eda6f593SDavid van Moolenbroek } 666*eda6f593SDavid van Moolenbroek 667*eda6f593SDavid van Moolenbroek data->numprefix = 0; 668*eda6f593SDavid van Moolenbroek return; 669*eda6f593SDavid van Moolenbroek 670*eda6f593SDavid van Moolenbroek input_on: 671*eda6f593SDavid van Moolenbroek keys = options_get_number(&wp->window->options, "mode-keys"); 672*eda6f593SDavid van Moolenbroek if (keys == MODEKEY_EMACS) 673*eda6f593SDavid van Moolenbroek mode_key_init(&data->mdata, &mode_key_tree_emacs_edit); 674*eda6f593SDavid van Moolenbroek else 675*eda6f593SDavid van Moolenbroek mode_key_init(&data->mdata, &mode_key_tree_vi_edit); 676*eda6f593SDavid van Moolenbroek 677*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); 678*eda6f593SDavid van Moolenbroek return; 679*eda6f593SDavid van Moolenbroek 680*eda6f593SDavid van Moolenbroek input_off: 681*eda6f593SDavid van Moolenbroek keys = options_get_number(&wp->window->options, "mode-keys"); 682*eda6f593SDavid van Moolenbroek if (keys == MODEKEY_EMACS) 683*eda6f593SDavid van Moolenbroek mode_key_init(&data->mdata, &mode_key_tree_emacs_copy); 684*eda6f593SDavid van Moolenbroek else 685*eda6f593SDavid van Moolenbroek mode_key_init(&data->mdata, &mode_key_tree_vi_copy); 686*eda6f593SDavid van Moolenbroek 687*eda6f593SDavid van Moolenbroek data->inputtype = WINDOW_COPY_OFF; 688*eda6f593SDavid van Moolenbroek data->inputprompt = NULL; 689*eda6f593SDavid van Moolenbroek 690*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); 691*eda6f593SDavid van Moolenbroek } 692*eda6f593SDavid van Moolenbroek 693*eda6f593SDavid van Moolenbroek int 694*eda6f593SDavid van Moolenbroek window_copy_key_input(struct window_pane *wp, int key) 695*eda6f593SDavid van Moolenbroek { 696*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 697*eda6f593SDavid van Moolenbroek struct screen *s = &data->screen; 698*eda6f593SDavid van Moolenbroek size_t inputlen; 699*eda6f593SDavid van Moolenbroek u_int np; 700*eda6f593SDavid van Moolenbroek 701*eda6f593SDavid van Moolenbroek switch (mode_key_lookup(&data->mdata, key)) { 702*eda6f593SDavid van Moolenbroek case MODEKEYEDIT_CANCEL: 703*eda6f593SDavid van Moolenbroek data->numprefix = 0; 704*eda6f593SDavid van Moolenbroek return (-1); 705*eda6f593SDavid van Moolenbroek case MODEKEYEDIT_BACKSPACE: 706*eda6f593SDavid van Moolenbroek inputlen = strlen(data->inputstr); 707*eda6f593SDavid van Moolenbroek if (inputlen > 0) 708*eda6f593SDavid van Moolenbroek data->inputstr[inputlen - 1] = '\0'; 709*eda6f593SDavid van Moolenbroek break; 710*eda6f593SDavid van Moolenbroek case MODEKEYEDIT_DELETELINE: 711*eda6f593SDavid van Moolenbroek *data->inputstr = '\0'; 712*eda6f593SDavid van Moolenbroek break; 713*eda6f593SDavid van Moolenbroek case MODEKEYEDIT_ENTER: 714*eda6f593SDavid van Moolenbroek np = data->numprefix; 715*eda6f593SDavid van Moolenbroek if (np == 0) 716*eda6f593SDavid van Moolenbroek np = 1; 717*eda6f593SDavid van Moolenbroek 718*eda6f593SDavid van Moolenbroek switch (data->inputtype) { 719*eda6f593SDavid van Moolenbroek case WINDOW_COPY_OFF: 720*eda6f593SDavid van Moolenbroek case WINDOW_COPY_JUMPFORWARD: 721*eda6f593SDavid van Moolenbroek case WINDOW_COPY_JUMPBACK: 722*eda6f593SDavid van Moolenbroek case WINDOW_COPY_NUMERICPREFIX: 723*eda6f593SDavid van Moolenbroek break; 724*eda6f593SDavid van Moolenbroek case WINDOW_COPY_SEARCHUP: 725*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 726*eda6f593SDavid van Moolenbroek window_copy_search_up(wp, data->inputstr); 727*eda6f593SDavid van Moolenbroek data->searchtype = data->inputtype; 728*eda6f593SDavid van Moolenbroek data->searchstr = xstrdup(data->inputstr); 729*eda6f593SDavid van Moolenbroek break; 730*eda6f593SDavid van Moolenbroek case WINDOW_COPY_SEARCHDOWN: 731*eda6f593SDavid van Moolenbroek for (; np != 0; np--) 732*eda6f593SDavid van Moolenbroek window_copy_search_down(wp, data->inputstr); 733*eda6f593SDavid van Moolenbroek data->searchtype = data->inputtype; 734*eda6f593SDavid van Moolenbroek data->searchstr = xstrdup(data->inputstr); 735*eda6f593SDavid van Moolenbroek break; 736*eda6f593SDavid van Moolenbroek case WINDOW_COPY_GOTOLINE: 737*eda6f593SDavid van Moolenbroek window_copy_goto_line(wp, data->inputstr); 738*eda6f593SDavid van Moolenbroek *data->inputstr = '\0'; 739*eda6f593SDavid van Moolenbroek break; 740*eda6f593SDavid van Moolenbroek } 741*eda6f593SDavid van Moolenbroek data->numprefix = 0; 742*eda6f593SDavid van Moolenbroek return (1); 743*eda6f593SDavid van Moolenbroek case MODEKEY_OTHER: 744*eda6f593SDavid van Moolenbroek if (key < 32 || key > 126) 745*eda6f593SDavid van Moolenbroek break; 746*eda6f593SDavid van Moolenbroek inputlen = strlen(data->inputstr) + 2; 747*eda6f593SDavid van Moolenbroek 748*eda6f593SDavid van Moolenbroek data->inputstr = xrealloc(data->inputstr, 1, inputlen); 749*eda6f593SDavid van Moolenbroek data->inputstr[inputlen - 2] = key; 750*eda6f593SDavid van Moolenbroek data->inputstr[inputlen - 1] = '\0'; 751*eda6f593SDavid van Moolenbroek break; 752*eda6f593SDavid van Moolenbroek default: 753*eda6f593SDavid van Moolenbroek break; 754*eda6f593SDavid van Moolenbroek } 755*eda6f593SDavid van Moolenbroek 756*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); 757*eda6f593SDavid van Moolenbroek return (0); 758*eda6f593SDavid van Moolenbroek } 759*eda6f593SDavid van Moolenbroek 760*eda6f593SDavid van Moolenbroek int 761*eda6f593SDavid van Moolenbroek window_copy_key_numeric_prefix(struct window_pane *wp, int key) 762*eda6f593SDavid van Moolenbroek { 763*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 764*eda6f593SDavid van Moolenbroek struct screen *s = &data->screen; 765*eda6f593SDavid van Moolenbroek 766*eda6f593SDavid van Moolenbroek key &= KEYC_MASK_KEY; 767*eda6f593SDavid van Moolenbroek if (key < '0' || key > '9') 768*eda6f593SDavid van Moolenbroek return 1; 769*eda6f593SDavid van Moolenbroek 770*eda6f593SDavid van Moolenbroek if (data->numprefix >= 100) /* no more than three digits */ 771*eda6f593SDavid van Moolenbroek return 0; 772*eda6f593SDavid van Moolenbroek data->numprefix = data->numprefix * 10 + key - '0'; 773*eda6f593SDavid van Moolenbroek 774*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); 775*eda6f593SDavid van Moolenbroek return 0; 776*eda6f593SDavid van Moolenbroek } 777*eda6f593SDavid van Moolenbroek 778*eda6f593SDavid van Moolenbroek /* ARGSUSED */ 779*eda6f593SDavid van Moolenbroek void 780*eda6f593SDavid van Moolenbroek window_copy_mouse( 781*eda6f593SDavid van Moolenbroek struct window_pane *wp, struct session *sess, struct mouse_event *m) 782*eda6f593SDavid van Moolenbroek { 783*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 784*eda6f593SDavid van Moolenbroek struct screen *s = &data->screen; 785*eda6f593SDavid van Moolenbroek u_int i, old_cy; 786*eda6f593SDavid van Moolenbroek 787*eda6f593SDavid van Moolenbroek if (m->x >= screen_size_x(s)) 788*eda6f593SDavid van Moolenbroek return; 789*eda6f593SDavid van Moolenbroek if (m->y >= screen_size_y(s)) 790*eda6f593SDavid van Moolenbroek return; 791*eda6f593SDavid van Moolenbroek 792*eda6f593SDavid van Moolenbroek /* If mouse wheel (buttons 4 and 5), scroll. */ 793*eda6f593SDavid van Moolenbroek if ((m->b & MOUSE_45)) { 794*eda6f593SDavid van Moolenbroek if ((m->b & MOUSE_BUTTON) == MOUSE_1) { 795*eda6f593SDavid van Moolenbroek for (i = 0; i < 5; i++) 796*eda6f593SDavid van Moolenbroek window_copy_cursor_up(wp, 0); 797*eda6f593SDavid van Moolenbroek } else if ((m->b & MOUSE_BUTTON) == MOUSE_2) { 798*eda6f593SDavid van Moolenbroek old_cy = data->cy; 799*eda6f593SDavid van Moolenbroek for (i = 0; i < 5; i++) 800*eda6f593SDavid van Moolenbroek window_copy_cursor_down(wp, 0); 801*eda6f593SDavid van Moolenbroek if (old_cy == data->cy) 802*eda6f593SDavid van Moolenbroek goto reset_mode; 803*eda6f593SDavid van Moolenbroek } 804*eda6f593SDavid van Moolenbroek return; 805*eda6f593SDavid van Moolenbroek } 806*eda6f593SDavid van Moolenbroek 807*eda6f593SDavid van Moolenbroek /* 808*eda6f593SDavid van Moolenbroek * If already reading motion, move the cursor while buttons are still 809*eda6f593SDavid van Moolenbroek * pressed, or stop the selection on their release. 810*eda6f593SDavid van Moolenbroek */ 811*eda6f593SDavid van Moolenbroek if (s->mode & MODE_MOUSE_BUTTON) { 812*eda6f593SDavid van Moolenbroek if ((m->b & MOUSE_BUTTON) != MOUSE_UP) { 813*eda6f593SDavid van Moolenbroek window_copy_update_cursor(wp, m->x, m->y); 814*eda6f593SDavid van Moolenbroek if (window_copy_update_selection(wp)) 815*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 816*eda6f593SDavid van Moolenbroek return; 817*eda6f593SDavid van Moolenbroek } 818*eda6f593SDavid van Moolenbroek goto reset_mode; 819*eda6f593SDavid van Moolenbroek } 820*eda6f593SDavid van Moolenbroek 821*eda6f593SDavid van Moolenbroek /* Otherwise if other buttons pressed, start selection and motion. */ 822*eda6f593SDavid van Moolenbroek if ((m->b & MOUSE_BUTTON) != MOUSE_UP) { 823*eda6f593SDavid van Moolenbroek s->mode &= ~MODE_MOUSE_STANDARD; 824*eda6f593SDavid van Moolenbroek s->mode |= MODE_MOUSE_BUTTON; 825*eda6f593SDavid van Moolenbroek 826*eda6f593SDavid van Moolenbroek window_copy_update_cursor(wp, m->x, m->y); 827*eda6f593SDavid van Moolenbroek window_copy_start_selection(wp); 828*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 829*eda6f593SDavid van Moolenbroek } 830*eda6f593SDavid van Moolenbroek 831*eda6f593SDavid van Moolenbroek return; 832*eda6f593SDavid van Moolenbroek 833*eda6f593SDavid van Moolenbroek reset_mode: 834*eda6f593SDavid van Moolenbroek s->mode &= ~MODE_MOUSE_BUTTON; 835*eda6f593SDavid van Moolenbroek s->mode |= MODE_MOUSE_STANDARD; 836*eda6f593SDavid van Moolenbroek if (sess != NULL) { 837*eda6f593SDavid van Moolenbroek window_copy_copy_selection(wp); 838*eda6f593SDavid van Moolenbroek window_pane_reset_mode(wp); 839*eda6f593SDavid van Moolenbroek } 840*eda6f593SDavid van Moolenbroek } 841*eda6f593SDavid van Moolenbroek 842*eda6f593SDavid van Moolenbroek void 843*eda6f593SDavid van Moolenbroek window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py) 844*eda6f593SDavid van Moolenbroek { 845*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 846*eda6f593SDavid van Moolenbroek struct grid *gd = data->backing->grid; 847*eda6f593SDavid van Moolenbroek u_int offset, gap; 848*eda6f593SDavid van Moolenbroek 849*eda6f593SDavid van Moolenbroek data->cx = px; 850*eda6f593SDavid van Moolenbroek 851*eda6f593SDavid van Moolenbroek gap = gd->sy / 4; 852*eda6f593SDavid van Moolenbroek if (py < gd->sy) { 853*eda6f593SDavid van Moolenbroek offset = 0; 854*eda6f593SDavid van Moolenbroek data->cy = py; 855*eda6f593SDavid van Moolenbroek } else if (py > gd->hsize + gd->sy - gap) { 856*eda6f593SDavid van Moolenbroek offset = gd->hsize; 857*eda6f593SDavid van Moolenbroek data->cy = py - gd->hsize; 858*eda6f593SDavid van Moolenbroek } else { 859*eda6f593SDavid van Moolenbroek offset = py + gap - gd->sy; 860*eda6f593SDavid van Moolenbroek data->cy = py - offset; 861*eda6f593SDavid van Moolenbroek } 862*eda6f593SDavid van Moolenbroek data->oy = gd->hsize - offset; 863*eda6f593SDavid van Moolenbroek 864*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 865*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 866*eda6f593SDavid van Moolenbroek } 867*eda6f593SDavid van Moolenbroek 868*eda6f593SDavid van Moolenbroek int 869*eda6f593SDavid van Moolenbroek window_copy_search_compare( 870*eda6f593SDavid van Moolenbroek struct grid *gd, u_int px, u_int py, struct grid *sgd, u_int spx) 871*eda6f593SDavid van Moolenbroek { 872*eda6f593SDavid van Moolenbroek const struct grid_cell *gc, *sgc; 873*eda6f593SDavid van Moolenbroek const struct grid_utf8 *gu, *sgu; 874*eda6f593SDavid van Moolenbroek 875*eda6f593SDavid van Moolenbroek gc = grid_peek_cell(gd, px, py); 876*eda6f593SDavid van Moolenbroek sgc = grid_peek_cell(sgd, spx, 0); 877*eda6f593SDavid van Moolenbroek 878*eda6f593SDavid van Moolenbroek if ((gc->flags & GRID_FLAG_UTF8) != (sgc->flags & GRID_FLAG_UTF8)) 879*eda6f593SDavid van Moolenbroek return (0); 880*eda6f593SDavid van Moolenbroek 881*eda6f593SDavid van Moolenbroek if (gc->flags & GRID_FLAG_UTF8) { 882*eda6f593SDavid van Moolenbroek gu = grid_peek_utf8(gd, px, py); 883*eda6f593SDavid van Moolenbroek sgu = grid_peek_utf8(sgd, spx, 0); 884*eda6f593SDavid van Moolenbroek if (grid_utf8_compare(gu, sgu)) 885*eda6f593SDavid van Moolenbroek return (1); 886*eda6f593SDavid van Moolenbroek } else { 887*eda6f593SDavid van Moolenbroek if (gc->data == sgc->data) 888*eda6f593SDavid van Moolenbroek return (1); 889*eda6f593SDavid van Moolenbroek } 890*eda6f593SDavid van Moolenbroek return (0); 891*eda6f593SDavid van Moolenbroek } 892*eda6f593SDavid van Moolenbroek 893*eda6f593SDavid van Moolenbroek int 894*eda6f593SDavid van Moolenbroek window_copy_search_lr(struct grid *gd, 895*eda6f593SDavid van Moolenbroek struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last) 896*eda6f593SDavid van Moolenbroek { 897*eda6f593SDavid van Moolenbroek u_int ax, bx, px; 898*eda6f593SDavid van Moolenbroek 899*eda6f593SDavid van Moolenbroek for (ax = first; ax < last; ax++) { 900*eda6f593SDavid van Moolenbroek if (ax + sgd->sx >= gd->sx) 901*eda6f593SDavid van Moolenbroek break; 902*eda6f593SDavid van Moolenbroek for (bx = 0; bx < sgd->sx; bx++) { 903*eda6f593SDavid van Moolenbroek px = ax + bx; 904*eda6f593SDavid van Moolenbroek if (!window_copy_search_compare(gd, px, py, sgd, bx)) 905*eda6f593SDavid van Moolenbroek break; 906*eda6f593SDavid van Moolenbroek } 907*eda6f593SDavid van Moolenbroek if (bx == sgd->sx) { 908*eda6f593SDavid van Moolenbroek *ppx = ax; 909*eda6f593SDavid van Moolenbroek return (1); 910*eda6f593SDavid van Moolenbroek } 911*eda6f593SDavid van Moolenbroek } 912*eda6f593SDavid van Moolenbroek return (0); 913*eda6f593SDavid van Moolenbroek } 914*eda6f593SDavid van Moolenbroek 915*eda6f593SDavid van Moolenbroek int 916*eda6f593SDavid van Moolenbroek window_copy_search_rl(struct grid *gd, 917*eda6f593SDavid van Moolenbroek struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last) 918*eda6f593SDavid van Moolenbroek { 919*eda6f593SDavid van Moolenbroek u_int ax, bx, px; 920*eda6f593SDavid van Moolenbroek 921*eda6f593SDavid van Moolenbroek for (ax = last + 1; ax > first; ax--) { 922*eda6f593SDavid van Moolenbroek if (gd->sx - (ax - 1) < sgd->sx) 923*eda6f593SDavid van Moolenbroek continue; 924*eda6f593SDavid van Moolenbroek for (bx = 0; bx < sgd->sx; bx++) { 925*eda6f593SDavid van Moolenbroek px = ax - 1 + bx; 926*eda6f593SDavid van Moolenbroek if (!window_copy_search_compare(gd, px, py, sgd, bx)) 927*eda6f593SDavid van Moolenbroek break; 928*eda6f593SDavid van Moolenbroek } 929*eda6f593SDavid van Moolenbroek if (bx == sgd->sx) { 930*eda6f593SDavid van Moolenbroek *ppx = ax - 1; 931*eda6f593SDavid van Moolenbroek return (1); 932*eda6f593SDavid van Moolenbroek } 933*eda6f593SDavid van Moolenbroek } 934*eda6f593SDavid van Moolenbroek return (0); 935*eda6f593SDavid van Moolenbroek } 936*eda6f593SDavid van Moolenbroek 937*eda6f593SDavid van Moolenbroek void 938*eda6f593SDavid van Moolenbroek window_copy_search_up(struct window_pane *wp, const char *searchstr) 939*eda6f593SDavid van Moolenbroek { 940*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 941*eda6f593SDavid van Moolenbroek struct screen *s = data->backing, ss; 942*eda6f593SDavid van Moolenbroek struct screen_write_ctx ctx; 943*eda6f593SDavid van Moolenbroek struct grid *gd = s->grid, *sgd; 944*eda6f593SDavid van Moolenbroek struct grid_cell gc; 945*eda6f593SDavid van Moolenbroek size_t searchlen; 946*eda6f593SDavid van Moolenbroek u_int i, last, fx, fy, px; 947*eda6f593SDavid van Moolenbroek int utf8flag, n, wrapped; 948*eda6f593SDavid van Moolenbroek 949*eda6f593SDavid van Moolenbroek if (*searchstr == '\0') 950*eda6f593SDavid van Moolenbroek return; 951*eda6f593SDavid van Moolenbroek utf8flag = options_get_number(&wp->window->options, "utf8"); 952*eda6f593SDavid van Moolenbroek searchlen = screen_write_strlen(utf8flag, "%s", searchstr); 953*eda6f593SDavid van Moolenbroek 954*eda6f593SDavid van Moolenbroek screen_init(&ss, searchlen, 1, 0); 955*eda6f593SDavid van Moolenbroek screen_write_start(&ctx, NULL, &ss); 956*eda6f593SDavid van Moolenbroek memcpy(&gc, &grid_default_cell, sizeof gc); 957*eda6f593SDavid van Moolenbroek screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr); 958*eda6f593SDavid van Moolenbroek screen_write_stop(&ctx); 959*eda6f593SDavid van Moolenbroek 960*eda6f593SDavid van Moolenbroek fx = data->cx; 961*eda6f593SDavid van Moolenbroek fy = gd->hsize - data->oy + data->cy; 962*eda6f593SDavid van Moolenbroek 963*eda6f593SDavid van Moolenbroek if (fx == 0) { 964*eda6f593SDavid van Moolenbroek if (fy == 0) 965*eda6f593SDavid van Moolenbroek return; 966*eda6f593SDavid van Moolenbroek fx = gd->sx - 1; 967*eda6f593SDavid van Moolenbroek fy--; 968*eda6f593SDavid van Moolenbroek } else 969*eda6f593SDavid van Moolenbroek fx--; 970*eda6f593SDavid van Moolenbroek n = wrapped = 0; 971*eda6f593SDavid van Moolenbroek 972*eda6f593SDavid van Moolenbroek retry: 973*eda6f593SDavid van Moolenbroek sgd = ss.grid; 974*eda6f593SDavid van Moolenbroek for (i = fy + 1; i > 0; i--) { 975*eda6f593SDavid van Moolenbroek last = screen_size_x(s); 976*eda6f593SDavid van Moolenbroek if (i == fy + 1) 977*eda6f593SDavid van Moolenbroek last = fx; 978*eda6f593SDavid van Moolenbroek n = window_copy_search_rl(gd, sgd, &px, i - 1, 0, last); 979*eda6f593SDavid van Moolenbroek if (n) { 980*eda6f593SDavid van Moolenbroek window_copy_scroll_to(wp, px, i - 1); 981*eda6f593SDavid van Moolenbroek break; 982*eda6f593SDavid van Moolenbroek } 983*eda6f593SDavid van Moolenbroek } 984*eda6f593SDavid van Moolenbroek if (!n && !wrapped) { 985*eda6f593SDavid van Moolenbroek fx = gd->sx - 1; 986*eda6f593SDavid van Moolenbroek fy = gd->hsize + gd->sy - 1; 987*eda6f593SDavid van Moolenbroek wrapped = 1; 988*eda6f593SDavid van Moolenbroek goto retry; 989*eda6f593SDavid van Moolenbroek } 990*eda6f593SDavid van Moolenbroek 991*eda6f593SDavid van Moolenbroek screen_free(&ss); 992*eda6f593SDavid van Moolenbroek } 993*eda6f593SDavid van Moolenbroek 994*eda6f593SDavid van Moolenbroek void 995*eda6f593SDavid van Moolenbroek window_copy_search_down(struct window_pane *wp, const char *searchstr) 996*eda6f593SDavid van Moolenbroek { 997*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 998*eda6f593SDavid van Moolenbroek struct screen *s = data->backing, ss; 999*eda6f593SDavid van Moolenbroek struct screen_write_ctx ctx; 1000*eda6f593SDavid van Moolenbroek struct grid *gd = s->grid, *sgd; 1001*eda6f593SDavid van Moolenbroek struct grid_cell gc; 1002*eda6f593SDavid van Moolenbroek size_t searchlen; 1003*eda6f593SDavid van Moolenbroek u_int i, first, fx, fy, px; 1004*eda6f593SDavid van Moolenbroek int utf8flag, n, wrapped; 1005*eda6f593SDavid van Moolenbroek 1006*eda6f593SDavid van Moolenbroek if (*searchstr == '\0') 1007*eda6f593SDavid van Moolenbroek return; 1008*eda6f593SDavid van Moolenbroek utf8flag = options_get_number(&wp->window->options, "utf8"); 1009*eda6f593SDavid van Moolenbroek searchlen = screen_write_strlen(utf8flag, "%s", searchstr); 1010*eda6f593SDavid van Moolenbroek 1011*eda6f593SDavid van Moolenbroek screen_init(&ss, searchlen, 1, 0); 1012*eda6f593SDavid van Moolenbroek screen_write_start(&ctx, NULL, &ss); 1013*eda6f593SDavid van Moolenbroek memcpy(&gc, &grid_default_cell, sizeof gc); 1014*eda6f593SDavid van Moolenbroek screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr); 1015*eda6f593SDavid van Moolenbroek screen_write_stop(&ctx); 1016*eda6f593SDavid van Moolenbroek 1017*eda6f593SDavid van Moolenbroek fx = data->cx; 1018*eda6f593SDavid van Moolenbroek fy = gd->hsize - data->oy + data->cy; 1019*eda6f593SDavid van Moolenbroek 1020*eda6f593SDavid van Moolenbroek if (fx == gd->sx - 1) { 1021*eda6f593SDavid van Moolenbroek if (fy == gd->hsize + gd->sy) 1022*eda6f593SDavid van Moolenbroek return; 1023*eda6f593SDavid van Moolenbroek fx = 0; 1024*eda6f593SDavid van Moolenbroek fy++; 1025*eda6f593SDavid van Moolenbroek } else 1026*eda6f593SDavid van Moolenbroek fx++; 1027*eda6f593SDavid van Moolenbroek n = wrapped = 0; 1028*eda6f593SDavid van Moolenbroek 1029*eda6f593SDavid van Moolenbroek retry: 1030*eda6f593SDavid van Moolenbroek sgd = ss.grid; 1031*eda6f593SDavid van Moolenbroek for (i = fy + 1; i < gd->hsize + gd->sy; i++) { 1032*eda6f593SDavid van Moolenbroek first = 0; 1033*eda6f593SDavid van Moolenbroek if (i == fy + 1) 1034*eda6f593SDavid van Moolenbroek first = fx; 1035*eda6f593SDavid van Moolenbroek n = window_copy_search_lr(gd, sgd, &px, i - 1, first, gd->sx); 1036*eda6f593SDavid van Moolenbroek if (n) { 1037*eda6f593SDavid van Moolenbroek window_copy_scroll_to(wp, px, i - 1); 1038*eda6f593SDavid van Moolenbroek break; 1039*eda6f593SDavid van Moolenbroek } 1040*eda6f593SDavid van Moolenbroek } 1041*eda6f593SDavid van Moolenbroek if (!n && !wrapped) { 1042*eda6f593SDavid van Moolenbroek fx = 0; 1043*eda6f593SDavid van Moolenbroek fy = 0; 1044*eda6f593SDavid van Moolenbroek wrapped = 1; 1045*eda6f593SDavid van Moolenbroek goto retry; 1046*eda6f593SDavid van Moolenbroek } 1047*eda6f593SDavid van Moolenbroek 1048*eda6f593SDavid van Moolenbroek screen_free(&ss); 1049*eda6f593SDavid van Moolenbroek } 1050*eda6f593SDavid van Moolenbroek 1051*eda6f593SDavid van Moolenbroek void 1052*eda6f593SDavid van Moolenbroek window_copy_goto_line(struct window_pane *wp, const char *linestr) 1053*eda6f593SDavid van Moolenbroek { 1054*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1055*eda6f593SDavid van Moolenbroek const char *errstr; 1056*eda6f593SDavid van Moolenbroek u_int lineno; 1057*eda6f593SDavid van Moolenbroek 1058*eda6f593SDavid van Moolenbroek lineno = strtonum(linestr, 0, screen_hsize(data->backing), &errstr); 1059*eda6f593SDavid van Moolenbroek if (errstr != NULL) 1060*eda6f593SDavid van Moolenbroek return; 1061*eda6f593SDavid van Moolenbroek 1062*eda6f593SDavid van Moolenbroek data->oy = lineno; 1063*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 1064*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 1065*eda6f593SDavid van Moolenbroek } 1066*eda6f593SDavid van Moolenbroek 1067*eda6f593SDavid van Moolenbroek void 1068*eda6f593SDavid van Moolenbroek window_copy_write_line( 1069*eda6f593SDavid van Moolenbroek struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) 1070*eda6f593SDavid van Moolenbroek { 1071*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1072*eda6f593SDavid van Moolenbroek struct screen *s = &data->screen; 1073*eda6f593SDavid van Moolenbroek struct options *oo = &wp->window->options; 1074*eda6f593SDavid van Moolenbroek struct grid_cell gc; 1075*eda6f593SDavid van Moolenbroek char hdr[32]; 1076*eda6f593SDavid van Moolenbroek size_t last, xoff = 0, size = 0; 1077*eda6f593SDavid van Moolenbroek 1078*eda6f593SDavid van Moolenbroek memcpy(&gc, &grid_default_cell, sizeof gc); 1079*eda6f593SDavid van Moolenbroek colour_set_fg(&gc, options_get_number(oo, "mode-fg")); 1080*eda6f593SDavid van Moolenbroek colour_set_bg(&gc, options_get_number(oo, "mode-bg")); 1081*eda6f593SDavid van Moolenbroek gc.attr |= options_get_number(oo, "mode-attr"); 1082*eda6f593SDavid van Moolenbroek 1083*eda6f593SDavid van Moolenbroek last = screen_size_y(s) - 1; 1084*eda6f593SDavid van Moolenbroek if (py == 0) { 1085*eda6f593SDavid van Moolenbroek size = xsnprintf(hdr, sizeof hdr, 1086*eda6f593SDavid van Moolenbroek "[%u/%u]", data->oy, screen_hsize(data->backing)); 1087*eda6f593SDavid van Moolenbroek if (size > screen_size_x(s)) 1088*eda6f593SDavid van Moolenbroek size = screen_size_x(s); 1089*eda6f593SDavid van Moolenbroek screen_write_cursormove(ctx, screen_size_x(s) - size, 0); 1090*eda6f593SDavid van Moolenbroek screen_write_puts(ctx, &gc, "%s", hdr); 1091*eda6f593SDavid van Moolenbroek } else if (py == last && data->inputtype != WINDOW_COPY_OFF) { 1092*eda6f593SDavid van Moolenbroek if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) { 1093*eda6f593SDavid van Moolenbroek xoff = size = xsnprintf(hdr, sizeof hdr, 1094*eda6f593SDavid van Moolenbroek "Repeat: %u", data->numprefix); 1095*eda6f593SDavid van Moolenbroek } else { 1096*eda6f593SDavid van Moolenbroek xoff = size = xsnprintf(hdr, sizeof hdr, 1097*eda6f593SDavid van Moolenbroek "%s: %s", data->inputprompt, data->inputstr); 1098*eda6f593SDavid van Moolenbroek } 1099*eda6f593SDavid van Moolenbroek screen_write_cursormove(ctx, 0, last); 1100*eda6f593SDavid van Moolenbroek screen_write_puts(ctx, &gc, "%s", hdr); 1101*eda6f593SDavid van Moolenbroek } else 1102*eda6f593SDavid van Moolenbroek size = 0; 1103*eda6f593SDavid van Moolenbroek 1104*eda6f593SDavid van Moolenbroek screen_write_cursormove(ctx, xoff, py); 1105*eda6f593SDavid van Moolenbroek screen_write_copy(ctx, data->backing, xoff, 1106*eda6f593SDavid van Moolenbroek (screen_hsize(data->backing) - data->oy) + py, 1107*eda6f593SDavid van Moolenbroek screen_size_x(s) - size, 1); 1108*eda6f593SDavid van Moolenbroek 1109*eda6f593SDavid van Moolenbroek if (py == data->cy && data->cx == screen_size_x(s)) { 1110*eda6f593SDavid van Moolenbroek memcpy(&gc, &grid_default_cell, sizeof gc); 1111*eda6f593SDavid van Moolenbroek screen_write_cursormove(ctx, screen_size_x(s) - 1, py); 1112*eda6f593SDavid van Moolenbroek screen_write_putc(ctx, &gc, '$'); 1113*eda6f593SDavid van Moolenbroek } 1114*eda6f593SDavid van Moolenbroek } 1115*eda6f593SDavid van Moolenbroek 1116*eda6f593SDavid van Moolenbroek void 1117*eda6f593SDavid van Moolenbroek window_copy_write_lines( 1118*eda6f593SDavid van Moolenbroek struct window_pane *wp, struct screen_write_ctx *ctx, u_int py, u_int ny) 1119*eda6f593SDavid van Moolenbroek { 1120*eda6f593SDavid van Moolenbroek u_int yy; 1121*eda6f593SDavid van Moolenbroek 1122*eda6f593SDavid van Moolenbroek for (yy = py; yy < py + ny; yy++) 1123*eda6f593SDavid van Moolenbroek window_copy_write_line(wp, ctx, py); 1124*eda6f593SDavid van Moolenbroek } 1125*eda6f593SDavid van Moolenbroek 1126*eda6f593SDavid van Moolenbroek void 1127*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(struct window_pane *wp, u_int py, u_int ny) 1128*eda6f593SDavid van Moolenbroek { 1129*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1130*eda6f593SDavid van Moolenbroek struct screen_write_ctx ctx; 1131*eda6f593SDavid van Moolenbroek u_int i; 1132*eda6f593SDavid van Moolenbroek 1133*eda6f593SDavid van Moolenbroek screen_write_start(&ctx, wp, NULL); 1134*eda6f593SDavid van Moolenbroek for (i = py; i < py + ny; i++) 1135*eda6f593SDavid van Moolenbroek window_copy_write_line(wp, &ctx, i); 1136*eda6f593SDavid van Moolenbroek screen_write_cursormove(&ctx, data->cx, data->cy); 1137*eda6f593SDavid van Moolenbroek screen_write_stop(&ctx); 1138*eda6f593SDavid van Moolenbroek } 1139*eda6f593SDavid van Moolenbroek 1140*eda6f593SDavid van Moolenbroek void 1141*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(struct window_pane *wp) 1142*eda6f593SDavid van Moolenbroek { 1143*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1144*eda6f593SDavid van Moolenbroek 1145*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, 0, screen_size_y(&data->screen)); 1146*eda6f593SDavid van Moolenbroek } 1147*eda6f593SDavid van Moolenbroek 1148*eda6f593SDavid van Moolenbroek void 1149*eda6f593SDavid van Moolenbroek window_copy_update_cursor(struct window_pane *wp, u_int cx, u_int cy) 1150*eda6f593SDavid van Moolenbroek { 1151*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1152*eda6f593SDavid van Moolenbroek struct screen *s = &data->screen; 1153*eda6f593SDavid van Moolenbroek struct screen_write_ctx ctx; 1154*eda6f593SDavid van Moolenbroek u_int old_cx, old_cy; 1155*eda6f593SDavid van Moolenbroek 1156*eda6f593SDavid van Moolenbroek old_cx = data->cx; old_cy = data->cy; 1157*eda6f593SDavid van Moolenbroek data->cx = cx; data->cy = cy; 1158*eda6f593SDavid van Moolenbroek if (old_cx == screen_size_x(s)) 1159*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, old_cy, 1); 1160*eda6f593SDavid van Moolenbroek if (data->cx == screen_size_x(s)) 1161*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy, 1); 1162*eda6f593SDavid van Moolenbroek else { 1163*eda6f593SDavid van Moolenbroek screen_write_start(&ctx, wp, NULL); 1164*eda6f593SDavid van Moolenbroek screen_write_cursormove(&ctx, data->cx, data->cy); 1165*eda6f593SDavid van Moolenbroek screen_write_stop(&ctx); 1166*eda6f593SDavid van Moolenbroek } 1167*eda6f593SDavid van Moolenbroek } 1168*eda6f593SDavid van Moolenbroek 1169*eda6f593SDavid van Moolenbroek void 1170*eda6f593SDavid van Moolenbroek window_copy_start_selection(struct window_pane *wp) 1171*eda6f593SDavid van Moolenbroek { 1172*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1173*eda6f593SDavid van Moolenbroek struct screen *s = &data->screen; 1174*eda6f593SDavid van Moolenbroek 1175*eda6f593SDavid van Moolenbroek data->selx = data->cx; 1176*eda6f593SDavid van Moolenbroek data->sely = screen_hsize(data->backing) + data->cy - data->oy; 1177*eda6f593SDavid van Moolenbroek 1178*eda6f593SDavid van Moolenbroek s->sel.flag = 1; 1179*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 1180*eda6f593SDavid van Moolenbroek } 1181*eda6f593SDavid van Moolenbroek 1182*eda6f593SDavid van Moolenbroek int 1183*eda6f593SDavid van Moolenbroek window_copy_update_selection(struct window_pane *wp) 1184*eda6f593SDavid van Moolenbroek { 1185*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1186*eda6f593SDavid van Moolenbroek struct screen *s = &data->screen; 1187*eda6f593SDavid van Moolenbroek struct options *oo = &wp->window->options; 1188*eda6f593SDavid van Moolenbroek struct grid_cell gc; 1189*eda6f593SDavid van Moolenbroek u_int sx, sy, ty, cy; 1190*eda6f593SDavid van Moolenbroek 1191*eda6f593SDavid van Moolenbroek if (!s->sel.flag) 1192*eda6f593SDavid van Moolenbroek return (0); 1193*eda6f593SDavid van Moolenbroek 1194*eda6f593SDavid van Moolenbroek /* Set colours. */ 1195*eda6f593SDavid van Moolenbroek memcpy(&gc, &grid_default_cell, sizeof gc); 1196*eda6f593SDavid van Moolenbroek colour_set_fg(&gc, options_get_number(oo, "mode-fg")); 1197*eda6f593SDavid van Moolenbroek colour_set_bg(&gc, options_get_number(oo, "mode-bg")); 1198*eda6f593SDavid van Moolenbroek gc.attr |= options_get_number(oo, "mode-attr"); 1199*eda6f593SDavid van Moolenbroek 1200*eda6f593SDavid van Moolenbroek /* Find top of screen. */ 1201*eda6f593SDavid van Moolenbroek ty = screen_hsize(data->backing) - data->oy; 1202*eda6f593SDavid van Moolenbroek 1203*eda6f593SDavid van Moolenbroek /* Adjust the selection. */ 1204*eda6f593SDavid van Moolenbroek sx = data->selx; 1205*eda6f593SDavid van Moolenbroek sy = data->sely; 1206*eda6f593SDavid van Moolenbroek if (sy < ty) { /* above screen */ 1207*eda6f593SDavid van Moolenbroek if (!data->rectflag) 1208*eda6f593SDavid van Moolenbroek sx = 0; 1209*eda6f593SDavid van Moolenbroek sy = 0; 1210*eda6f593SDavid van Moolenbroek } else if (sy > ty + screen_size_y(s) - 1) { /* below screen */ 1211*eda6f593SDavid van Moolenbroek if (!data->rectflag) 1212*eda6f593SDavid van Moolenbroek sx = screen_size_x(s) - 1; 1213*eda6f593SDavid van Moolenbroek sy = screen_size_y(s) - 1; 1214*eda6f593SDavid van Moolenbroek } else 1215*eda6f593SDavid van Moolenbroek sy -= ty; 1216*eda6f593SDavid van Moolenbroek sy = screen_hsize(s) + sy; 1217*eda6f593SDavid van Moolenbroek 1218*eda6f593SDavid van Moolenbroek screen_set_selection(s, 1219*eda6f593SDavid van Moolenbroek sx, sy, data->cx, screen_hsize(s) + data->cy, data->rectflag, &gc); 1220*eda6f593SDavid van Moolenbroek 1221*eda6f593SDavid van Moolenbroek if (data->rectflag) { 1222*eda6f593SDavid van Moolenbroek /* 1223*eda6f593SDavid van Moolenbroek * Can't rely on the caller to redraw the right lines for 1224*eda6f593SDavid van Moolenbroek * rectangle selection - find the highest line and the number 1225*eda6f593SDavid van Moolenbroek * of lines, and redraw just past that in both directions 1226*eda6f593SDavid van Moolenbroek */ 1227*eda6f593SDavid van Moolenbroek cy = data->cy; 1228*eda6f593SDavid van Moolenbroek if (sy < cy) 1229*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, sy, cy - sy + 1); 1230*eda6f593SDavid van Moolenbroek else 1231*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, cy, sy - cy + 1); 1232*eda6f593SDavid van Moolenbroek } 1233*eda6f593SDavid van Moolenbroek 1234*eda6f593SDavid van Moolenbroek return (1); 1235*eda6f593SDavid van Moolenbroek } 1236*eda6f593SDavid van Moolenbroek 1237*eda6f593SDavid van Moolenbroek void 1238*eda6f593SDavid van Moolenbroek window_copy_copy_selection(struct window_pane *wp) 1239*eda6f593SDavid van Moolenbroek { 1240*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1241*eda6f593SDavid van Moolenbroek struct screen *s = &data->screen; 1242*eda6f593SDavid van Moolenbroek char *buf; 1243*eda6f593SDavid van Moolenbroek size_t off; 1244*eda6f593SDavid van Moolenbroek u_int i, xx, yy, sx, sy, ex, ey, limit; 1245*eda6f593SDavid van Moolenbroek u_int firstsx, lastex, restex, restsx; 1246*eda6f593SDavid van Moolenbroek int keys; 1247*eda6f593SDavid van Moolenbroek 1248*eda6f593SDavid van Moolenbroek if (!s->sel.flag) 1249*eda6f593SDavid van Moolenbroek return; 1250*eda6f593SDavid van Moolenbroek 1251*eda6f593SDavid van Moolenbroek buf = xmalloc(1); 1252*eda6f593SDavid van Moolenbroek off = 0; 1253*eda6f593SDavid van Moolenbroek 1254*eda6f593SDavid van Moolenbroek *buf = '\0'; 1255*eda6f593SDavid van Moolenbroek 1256*eda6f593SDavid van Moolenbroek /* 1257*eda6f593SDavid van Moolenbroek * The selection extends from selx,sely to (adjusted) cx,cy on 1258*eda6f593SDavid van Moolenbroek * the base screen. 1259*eda6f593SDavid van Moolenbroek */ 1260*eda6f593SDavid van Moolenbroek 1261*eda6f593SDavid van Moolenbroek /* Find start and end. */ 1262*eda6f593SDavid van Moolenbroek xx = data->cx; 1263*eda6f593SDavid van Moolenbroek yy = screen_hsize(data->backing) + data->cy - data->oy; 1264*eda6f593SDavid van Moolenbroek if (yy < data->sely || (yy == data->sely && xx < data->selx)) { 1265*eda6f593SDavid van Moolenbroek sx = xx; sy = yy; 1266*eda6f593SDavid van Moolenbroek ex = data->selx; ey = data->sely; 1267*eda6f593SDavid van Moolenbroek } else { 1268*eda6f593SDavid van Moolenbroek sx = data->selx; sy = data->sely; 1269*eda6f593SDavid van Moolenbroek ex = xx; ey = yy; 1270*eda6f593SDavid van Moolenbroek } 1271*eda6f593SDavid van Moolenbroek 1272*eda6f593SDavid van Moolenbroek /* Trim ex to end of line. */ 1273*eda6f593SDavid van Moolenbroek xx = window_copy_find_length(wp, ey); 1274*eda6f593SDavid van Moolenbroek if (ex > xx) 1275*eda6f593SDavid van Moolenbroek ex = xx; 1276*eda6f593SDavid van Moolenbroek 1277*eda6f593SDavid van Moolenbroek /* 1278*eda6f593SDavid van Moolenbroek * Deal with rectangle-copy if necessary; four situations: start of 1279*eda6f593SDavid van Moolenbroek * first line (firstsx), end of last line (lastex), start (restsx) and 1280*eda6f593SDavid van Moolenbroek * end (restex) of all other lines. 1281*eda6f593SDavid van Moolenbroek */ 1282*eda6f593SDavid van Moolenbroek xx = screen_size_x(s); 1283*eda6f593SDavid van Moolenbroek 1284*eda6f593SDavid van Moolenbroek /* 1285*eda6f593SDavid van Moolenbroek * Behave according to mode-keys. If it is emacs, copy like emacs, 1286*eda6f593SDavid van Moolenbroek * keeping the top-left-most character, and dropping the 1287*eda6f593SDavid van Moolenbroek * bottom-right-most, regardless of copy direction. If it is vi, also 1288*eda6f593SDavid van Moolenbroek * keep bottom-right-most character. 1289*eda6f593SDavid van Moolenbroek */ 1290*eda6f593SDavid van Moolenbroek keys = options_get_number(&wp->window->options, "mode-keys"); 1291*eda6f593SDavid van Moolenbroek if (data->rectflag) { 1292*eda6f593SDavid van Moolenbroek /* 1293*eda6f593SDavid van Moolenbroek * Need to ignore the column with the cursor in it, which for 1294*eda6f593SDavid van Moolenbroek * rectangular copy means knowing which side the cursor is on. 1295*eda6f593SDavid van Moolenbroek */ 1296*eda6f593SDavid van Moolenbroek if (data->selx < data->cx) { 1297*eda6f593SDavid van Moolenbroek /* Selection start is on the left. */ 1298*eda6f593SDavid van Moolenbroek if (keys == MODEKEY_EMACS) { 1299*eda6f593SDavid van Moolenbroek lastex = data->cx; 1300*eda6f593SDavid van Moolenbroek restex = data->cx; 1301*eda6f593SDavid van Moolenbroek } 1302*eda6f593SDavid van Moolenbroek else { 1303*eda6f593SDavid van Moolenbroek lastex = data->cx + 1; 1304*eda6f593SDavid van Moolenbroek restex = data->cx + 1; 1305*eda6f593SDavid van Moolenbroek } 1306*eda6f593SDavid van Moolenbroek firstsx = data->selx; 1307*eda6f593SDavid van Moolenbroek restsx = data->selx; 1308*eda6f593SDavid van Moolenbroek } else { 1309*eda6f593SDavid van Moolenbroek /* Cursor is on the left. */ 1310*eda6f593SDavid van Moolenbroek lastex = data->selx + 1; 1311*eda6f593SDavid van Moolenbroek restex = data->selx + 1; 1312*eda6f593SDavid van Moolenbroek firstsx = data->cx; 1313*eda6f593SDavid van Moolenbroek restsx = data->cx; 1314*eda6f593SDavid van Moolenbroek } 1315*eda6f593SDavid van Moolenbroek } else { 1316*eda6f593SDavid van Moolenbroek if (keys == MODEKEY_EMACS) 1317*eda6f593SDavid van Moolenbroek lastex = ex; 1318*eda6f593SDavid van Moolenbroek else 1319*eda6f593SDavid van Moolenbroek lastex = ex + 1; 1320*eda6f593SDavid van Moolenbroek restex = xx; 1321*eda6f593SDavid van Moolenbroek firstsx = sx; 1322*eda6f593SDavid van Moolenbroek restsx = 0; 1323*eda6f593SDavid van Moolenbroek } 1324*eda6f593SDavid van Moolenbroek 1325*eda6f593SDavid van Moolenbroek /* Copy the lines. */ 1326*eda6f593SDavid van Moolenbroek if (sy == ey) 1327*eda6f593SDavid van Moolenbroek window_copy_copy_line(wp, &buf, &off, sy, firstsx, lastex); 1328*eda6f593SDavid van Moolenbroek else { 1329*eda6f593SDavid van Moolenbroek window_copy_copy_line(wp, &buf, &off, sy, firstsx, restex); 1330*eda6f593SDavid van Moolenbroek if (ey - sy > 1) { 1331*eda6f593SDavid van Moolenbroek for (i = sy + 1; i < ey; i++) { 1332*eda6f593SDavid van Moolenbroek window_copy_copy_line( 1333*eda6f593SDavid van Moolenbroek wp, &buf, &off, i, restsx, restex); 1334*eda6f593SDavid van Moolenbroek } 1335*eda6f593SDavid van Moolenbroek } 1336*eda6f593SDavid van Moolenbroek window_copy_copy_line(wp, &buf, &off, ey, restsx, lastex); 1337*eda6f593SDavid van Moolenbroek } 1338*eda6f593SDavid van Moolenbroek 1339*eda6f593SDavid van Moolenbroek /* Don't bother if no data. */ 1340*eda6f593SDavid van Moolenbroek if (off == 0) { 1341*eda6f593SDavid van Moolenbroek xfree(buf); 1342*eda6f593SDavid van Moolenbroek return; 1343*eda6f593SDavid van Moolenbroek } 1344*eda6f593SDavid van Moolenbroek off--; /* remove final \n */ 1345*eda6f593SDavid van Moolenbroek 1346*eda6f593SDavid van Moolenbroek if (options_get_number(&global_options, "set-clipboard")) 1347*eda6f593SDavid van Moolenbroek screen_write_setselection(&wp->ictx.ctx, (u_char *)buf, off); 1348*eda6f593SDavid van Moolenbroek 1349*eda6f593SDavid van Moolenbroek /* Add the buffer to the stack. */ 1350*eda6f593SDavid van Moolenbroek limit = options_get_number(&global_options, "buffer-limit"); 1351*eda6f593SDavid van Moolenbroek paste_add(&global_buffers, buf, off, limit); 1352*eda6f593SDavid van Moolenbroek } 1353*eda6f593SDavid van Moolenbroek 1354*eda6f593SDavid van Moolenbroek void 1355*eda6f593SDavid van Moolenbroek window_copy_copy_line(struct window_pane *wp, 1356*eda6f593SDavid van Moolenbroek char **buf, size_t *off, u_int sy, u_int sx, u_int ex) 1357*eda6f593SDavid van Moolenbroek { 1358*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1359*eda6f593SDavid van Moolenbroek struct grid *gd = data->backing->grid; 1360*eda6f593SDavid van Moolenbroek const struct grid_cell *gc; 1361*eda6f593SDavid van Moolenbroek const struct grid_utf8 *gu; 1362*eda6f593SDavid van Moolenbroek struct grid_line *gl; 1363*eda6f593SDavid van Moolenbroek u_int i, xx, wrapped = 0; 1364*eda6f593SDavid van Moolenbroek size_t size; 1365*eda6f593SDavid van Moolenbroek 1366*eda6f593SDavid van Moolenbroek if (sx > ex) 1367*eda6f593SDavid van Moolenbroek return; 1368*eda6f593SDavid van Moolenbroek 1369*eda6f593SDavid van Moolenbroek /* 1370*eda6f593SDavid van Moolenbroek * Work out if the line was wrapped at the screen edge and all of it is 1371*eda6f593SDavid van Moolenbroek * on screen. 1372*eda6f593SDavid van Moolenbroek */ 1373*eda6f593SDavid van Moolenbroek gl = &gd->linedata[sy]; 1374*eda6f593SDavid van Moolenbroek if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx) 1375*eda6f593SDavid van Moolenbroek wrapped = 1; 1376*eda6f593SDavid van Moolenbroek 1377*eda6f593SDavid van Moolenbroek /* If the line was wrapped, don't strip spaces (use the full length). */ 1378*eda6f593SDavid van Moolenbroek if (wrapped) 1379*eda6f593SDavid van Moolenbroek xx = gl->cellsize; 1380*eda6f593SDavid van Moolenbroek else 1381*eda6f593SDavid van Moolenbroek xx = window_copy_find_length(wp, sy); 1382*eda6f593SDavid van Moolenbroek if (ex > xx) 1383*eda6f593SDavid van Moolenbroek ex = xx; 1384*eda6f593SDavid van Moolenbroek if (sx > xx) 1385*eda6f593SDavid van Moolenbroek sx = xx; 1386*eda6f593SDavid van Moolenbroek 1387*eda6f593SDavid van Moolenbroek if (sx < ex) { 1388*eda6f593SDavid van Moolenbroek for (i = sx; i < ex; i++) { 1389*eda6f593SDavid van Moolenbroek gc = grid_peek_cell(gd, i, sy); 1390*eda6f593SDavid van Moolenbroek if (gc->flags & GRID_FLAG_PADDING) 1391*eda6f593SDavid van Moolenbroek continue; 1392*eda6f593SDavid van Moolenbroek if (!(gc->flags & GRID_FLAG_UTF8)) { 1393*eda6f593SDavid van Moolenbroek *buf = xrealloc(*buf, 1, (*off) + 1); 1394*eda6f593SDavid van Moolenbroek (*buf)[(*off)++] = gc->data; 1395*eda6f593SDavid van Moolenbroek } else { 1396*eda6f593SDavid van Moolenbroek gu = grid_peek_utf8(gd, i, sy); 1397*eda6f593SDavid van Moolenbroek size = grid_utf8_size(gu); 1398*eda6f593SDavid van Moolenbroek *buf = xrealloc(*buf, 1, (*off) + size); 1399*eda6f593SDavid van Moolenbroek *off += grid_utf8_copy(gu, *buf + *off, size); 1400*eda6f593SDavid van Moolenbroek } 1401*eda6f593SDavid van Moolenbroek } 1402*eda6f593SDavid van Moolenbroek } 1403*eda6f593SDavid van Moolenbroek 1404*eda6f593SDavid van Moolenbroek /* Only add a newline if the line wasn't wrapped. */ 1405*eda6f593SDavid van Moolenbroek if (!wrapped || ex != xx) { 1406*eda6f593SDavid van Moolenbroek *buf = xrealloc(*buf, 1, (*off) + 1); 1407*eda6f593SDavid van Moolenbroek (*buf)[(*off)++] = '\n'; 1408*eda6f593SDavid van Moolenbroek } 1409*eda6f593SDavid van Moolenbroek } 1410*eda6f593SDavid van Moolenbroek 1411*eda6f593SDavid van Moolenbroek void 1412*eda6f593SDavid van Moolenbroek window_copy_clear_selection(struct window_pane *wp) 1413*eda6f593SDavid van Moolenbroek { 1414*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1415*eda6f593SDavid van Moolenbroek u_int px, py; 1416*eda6f593SDavid van Moolenbroek 1417*eda6f593SDavid van Moolenbroek screen_clear_selection(&data->screen); 1418*eda6f593SDavid van Moolenbroek 1419*eda6f593SDavid van Moolenbroek py = screen_hsize(data->backing) + data->cy - data->oy; 1420*eda6f593SDavid van Moolenbroek px = window_copy_find_length(wp, py); 1421*eda6f593SDavid van Moolenbroek if (data->cx > px) 1422*eda6f593SDavid van Moolenbroek window_copy_update_cursor(wp, px, data->cy); 1423*eda6f593SDavid van Moolenbroek } 1424*eda6f593SDavid van Moolenbroek 1425*eda6f593SDavid van Moolenbroek int 1426*eda6f593SDavid van Moolenbroek window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set) 1427*eda6f593SDavid van Moolenbroek { 1428*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1429*eda6f593SDavid van Moolenbroek const struct grid_cell *gc; 1430*eda6f593SDavid van Moolenbroek 1431*eda6f593SDavid van Moolenbroek gc = grid_peek_cell(data->backing->grid, px, py); 1432*eda6f593SDavid van Moolenbroek if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) 1433*eda6f593SDavid van Moolenbroek return (0); 1434*eda6f593SDavid van Moolenbroek if (gc->data == 0x00 || gc->data == 0x7f) 1435*eda6f593SDavid van Moolenbroek return (0); 1436*eda6f593SDavid van Moolenbroek return (strchr(set, gc->data) != NULL); 1437*eda6f593SDavid van Moolenbroek } 1438*eda6f593SDavid van Moolenbroek 1439*eda6f593SDavid van Moolenbroek u_int 1440*eda6f593SDavid van Moolenbroek window_copy_find_length(struct window_pane *wp, u_int py) 1441*eda6f593SDavid van Moolenbroek { 1442*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1443*eda6f593SDavid van Moolenbroek struct screen *s = data->backing; 1444*eda6f593SDavid van Moolenbroek const struct grid_cell *gc; 1445*eda6f593SDavid van Moolenbroek u_int px; 1446*eda6f593SDavid van Moolenbroek 1447*eda6f593SDavid van Moolenbroek /* 1448*eda6f593SDavid van Moolenbroek * If the pane has been resized, its grid can contain old overlong 1449*eda6f593SDavid van Moolenbroek * lines. grid_peek_cell does not allow accessing cells beyond the 1450*eda6f593SDavid van Moolenbroek * width of the grid, and screen_write_copy treats them as spaces, so 1451*eda6f593SDavid van Moolenbroek * ignore them here too. 1452*eda6f593SDavid van Moolenbroek */ 1453*eda6f593SDavid van Moolenbroek px = s->grid->linedata[py].cellsize; 1454*eda6f593SDavid van Moolenbroek if (px > screen_size_x(s)) 1455*eda6f593SDavid van Moolenbroek px = screen_size_x(s); 1456*eda6f593SDavid van Moolenbroek while (px > 0) { 1457*eda6f593SDavid van Moolenbroek gc = grid_peek_cell(s->grid, px - 1, py); 1458*eda6f593SDavid van Moolenbroek if (gc->flags & GRID_FLAG_UTF8) 1459*eda6f593SDavid van Moolenbroek break; 1460*eda6f593SDavid van Moolenbroek if (gc->data != ' ') 1461*eda6f593SDavid van Moolenbroek break; 1462*eda6f593SDavid van Moolenbroek px--; 1463*eda6f593SDavid van Moolenbroek } 1464*eda6f593SDavid van Moolenbroek return (px); 1465*eda6f593SDavid van Moolenbroek } 1466*eda6f593SDavid van Moolenbroek 1467*eda6f593SDavid van Moolenbroek void 1468*eda6f593SDavid van Moolenbroek window_copy_cursor_start_of_line(struct window_pane *wp) 1469*eda6f593SDavid van Moolenbroek { 1470*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1471*eda6f593SDavid van Moolenbroek struct screen *back_s = data->backing; 1472*eda6f593SDavid van Moolenbroek struct grid *gd = back_s->grid; 1473*eda6f593SDavid van Moolenbroek u_int py; 1474*eda6f593SDavid van Moolenbroek 1475*eda6f593SDavid van Moolenbroek if (data->cx == 0) { 1476*eda6f593SDavid van Moolenbroek py = screen_hsize(back_s) + data->cy - data->oy; 1477*eda6f593SDavid van Moolenbroek while (py > 0 && gd->linedata[py-1].flags & GRID_LINE_WRAPPED) { 1478*eda6f593SDavid van Moolenbroek window_copy_cursor_up(wp, 0); 1479*eda6f593SDavid van Moolenbroek py = screen_hsize(back_s) + data->cy - data->oy; 1480*eda6f593SDavid van Moolenbroek } 1481*eda6f593SDavid van Moolenbroek } 1482*eda6f593SDavid van Moolenbroek window_copy_update_cursor(wp, 0, data->cy); 1483*eda6f593SDavid van Moolenbroek if (window_copy_update_selection(wp)) 1484*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy, 1); 1485*eda6f593SDavid van Moolenbroek } 1486*eda6f593SDavid van Moolenbroek 1487*eda6f593SDavid van Moolenbroek void 1488*eda6f593SDavid van Moolenbroek window_copy_cursor_back_to_indentation(struct window_pane *wp) 1489*eda6f593SDavid van Moolenbroek { 1490*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1491*eda6f593SDavid van Moolenbroek u_int px, py, xx; 1492*eda6f593SDavid van Moolenbroek const struct grid_cell *gc; 1493*eda6f593SDavid van Moolenbroek 1494*eda6f593SDavid van Moolenbroek px = 0; 1495*eda6f593SDavid van Moolenbroek py = screen_hsize(data->backing) + data->cy - data->oy; 1496*eda6f593SDavid van Moolenbroek xx = window_copy_find_length(wp, py); 1497*eda6f593SDavid van Moolenbroek 1498*eda6f593SDavid van Moolenbroek while (px < xx) { 1499*eda6f593SDavid van Moolenbroek gc = grid_peek_cell(data->backing->grid, px, py); 1500*eda6f593SDavid van Moolenbroek if (gc->flags & GRID_FLAG_UTF8) 1501*eda6f593SDavid van Moolenbroek break; 1502*eda6f593SDavid van Moolenbroek if (gc->data != ' ') 1503*eda6f593SDavid van Moolenbroek break; 1504*eda6f593SDavid van Moolenbroek px++; 1505*eda6f593SDavid van Moolenbroek } 1506*eda6f593SDavid van Moolenbroek 1507*eda6f593SDavid van Moolenbroek window_copy_update_cursor(wp, px, data->cy); 1508*eda6f593SDavid van Moolenbroek if (window_copy_update_selection(wp)) 1509*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy, 1); 1510*eda6f593SDavid van Moolenbroek } 1511*eda6f593SDavid van Moolenbroek 1512*eda6f593SDavid van Moolenbroek void 1513*eda6f593SDavid van Moolenbroek window_copy_cursor_end_of_line(struct window_pane *wp) 1514*eda6f593SDavid van Moolenbroek { 1515*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1516*eda6f593SDavid van Moolenbroek struct screen *back_s = data->backing; 1517*eda6f593SDavid van Moolenbroek struct grid *gd = back_s->grid; 1518*eda6f593SDavid van Moolenbroek u_int px, py; 1519*eda6f593SDavid van Moolenbroek 1520*eda6f593SDavid van Moolenbroek py = screen_hsize(back_s) + data->cy - data->oy; 1521*eda6f593SDavid van Moolenbroek px = window_copy_find_length(wp, py); 1522*eda6f593SDavid van Moolenbroek 1523*eda6f593SDavid van Moolenbroek if (data->cx == px) { 1524*eda6f593SDavid van Moolenbroek if (data->screen.sel.flag && data->rectflag) 1525*eda6f593SDavid van Moolenbroek px = screen_size_x(back_s); 1526*eda6f593SDavid van Moolenbroek if (gd->linedata[py].flags & GRID_LINE_WRAPPED) { 1527*eda6f593SDavid van Moolenbroek while (py < gd->sy + gd->hsize && 1528*eda6f593SDavid van Moolenbroek gd->linedata[py].flags & GRID_LINE_WRAPPED) { 1529*eda6f593SDavid van Moolenbroek window_copy_cursor_down(wp, 0); 1530*eda6f593SDavid van Moolenbroek py = screen_hsize(back_s) 1531*eda6f593SDavid van Moolenbroek + data->cy - data->oy; 1532*eda6f593SDavid van Moolenbroek } 1533*eda6f593SDavid van Moolenbroek px = window_copy_find_length(wp, py); 1534*eda6f593SDavid van Moolenbroek } 1535*eda6f593SDavid van Moolenbroek } 1536*eda6f593SDavid van Moolenbroek window_copy_update_cursor(wp, px, data->cy); 1537*eda6f593SDavid van Moolenbroek 1538*eda6f593SDavid van Moolenbroek if (window_copy_update_selection(wp)) 1539*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy, 1); 1540*eda6f593SDavid van Moolenbroek } 1541*eda6f593SDavid van Moolenbroek 1542*eda6f593SDavid van Moolenbroek void 1543*eda6f593SDavid van Moolenbroek window_copy_cursor_left(struct window_pane *wp) 1544*eda6f593SDavid van Moolenbroek { 1545*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1546*eda6f593SDavid van Moolenbroek 1547*eda6f593SDavid van Moolenbroek if (data->cx == 0) { 1548*eda6f593SDavid van Moolenbroek window_copy_cursor_up(wp, 0); 1549*eda6f593SDavid van Moolenbroek window_copy_cursor_end_of_line(wp); 1550*eda6f593SDavid van Moolenbroek } else { 1551*eda6f593SDavid van Moolenbroek window_copy_update_cursor(wp, data->cx - 1, data->cy); 1552*eda6f593SDavid van Moolenbroek if (window_copy_update_selection(wp)) 1553*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy, 1); 1554*eda6f593SDavid van Moolenbroek } 1555*eda6f593SDavid van Moolenbroek } 1556*eda6f593SDavid van Moolenbroek 1557*eda6f593SDavid van Moolenbroek void 1558*eda6f593SDavid van Moolenbroek window_copy_cursor_right(struct window_pane *wp) 1559*eda6f593SDavid van Moolenbroek { 1560*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1561*eda6f593SDavid van Moolenbroek u_int px, py; 1562*eda6f593SDavid van Moolenbroek 1563*eda6f593SDavid van Moolenbroek if (data->screen.sel.flag && data->rectflag) 1564*eda6f593SDavid van Moolenbroek px = screen_size_x(&data->screen); 1565*eda6f593SDavid van Moolenbroek else { 1566*eda6f593SDavid van Moolenbroek py = screen_hsize(data->backing) + data->cy - data->oy; 1567*eda6f593SDavid van Moolenbroek px = window_copy_find_length(wp, py); 1568*eda6f593SDavid van Moolenbroek } 1569*eda6f593SDavid van Moolenbroek 1570*eda6f593SDavid van Moolenbroek if (data->cx >= px) { 1571*eda6f593SDavid van Moolenbroek window_copy_cursor_start_of_line(wp); 1572*eda6f593SDavid van Moolenbroek window_copy_cursor_down(wp, 0); 1573*eda6f593SDavid van Moolenbroek } else { 1574*eda6f593SDavid van Moolenbroek window_copy_update_cursor(wp, data->cx + 1, data->cy); 1575*eda6f593SDavid van Moolenbroek if (window_copy_update_selection(wp)) 1576*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy, 1); 1577*eda6f593SDavid van Moolenbroek } 1578*eda6f593SDavid van Moolenbroek } 1579*eda6f593SDavid van Moolenbroek 1580*eda6f593SDavid van Moolenbroek void 1581*eda6f593SDavid van Moolenbroek window_copy_cursor_up(struct window_pane *wp, int scroll_only) 1582*eda6f593SDavid van Moolenbroek { 1583*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1584*eda6f593SDavid van Moolenbroek struct screen *s = &data->screen; 1585*eda6f593SDavid van Moolenbroek u_int ox, oy, px, py; 1586*eda6f593SDavid van Moolenbroek 1587*eda6f593SDavid van Moolenbroek oy = screen_hsize(data->backing) + data->cy - data->oy; 1588*eda6f593SDavid van Moolenbroek ox = window_copy_find_length(wp, oy); 1589*eda6f593SDavid van Moolenbroek if (ox != 0) { 1590*eda6f593SDavid van Moolenbroek data->lastcx = data->cx; 1591*eda6f593SDavid van Moolenbroek data->lastsx = ox; 1592*eda6f593SDavid van Moolenbroek } 1593*eda6f593SDavid van Moolenbroek 1594*eda6f593SDavid van Moolenbroek data->cx = data->lastcx; 1595*eda6f593SDavid van Moolenbroek if (scroll_only || data->cy == 0) { 1596*eda6f593SDavid van Moolenbroek window_copy_scroll_down(wp, 1); 1597*eda6f593SDavid van Moolenbroek if (scroll_only) { 1598*eda6f593SDavid van Moolenbroek if (data->cy == screen_size_y(s) - 1) 1599*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy, 1); 1600*eda6f593SDavid van Moolenbroek else 1601*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy, 2); 1602*eda6f593SDavid van Moolenbroek } 1603*eda6f593SDavid van Moolenbroek } else { 1604*eda6f593SDavid van Moolenbroek window_copy_update_cursor(wp, data->cx, data->cy - 1); 1605*eda6f593SDavid van Moolenbroek if (window_copy_update_selection(wp)) { 1606*eda6f593SDavid van Moolenbroek if (data->cy == screen_size_y(s) - 1) 1607*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy, 1); 1608*eda6f593SDavid van Moolenbroek else 1609*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy, 2); 1610*eda6f593SDavid van Moolenbroek } 1611*eda6f593SDavid van Moolenbroek } 1612*eda6f593SDavid van Moolenbroek 1613*eda6f593SDavid van Moolenbroek if (!data->screen.sel.flag || !data->rectflag) { 1614*eda6f593SDavid van Moolenbroek py = screen_hsize(data->backing) + data->cy - data->oy; 1615*eda6f593SDavid van Moolenbroek px = window_copy_find_length(wp, py); 1616*eda6f593SDavid van Moolenbroek if ((data->cx >= data->lastsx && data->cx != px) || 1617*eda6f593SDavid van Moolenbroek data->cx > px) 1618*eda6f593SDavid van Moolenbroek window_copy_cursor_end_of_line(wp); 1619*eda6f593SDavid van Moolenbroek } 1620*eda6f593SDavid van Moolenbroek } 1621*eda6f593SDavid van Moolenbroek 1622*eda6f593SDavid van Moolenbroek void 1623*eda6f593SDavid van Moolenbroek window_copy_cursor_down(struct window_pane *wp, int scroll_only) 1624*eda6f593SDavid van Moolenbroek { 1625*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1626*eda6f593SDavid van Moolenbroek struct screen *s = &data->screen; 1627*eda6f593SDavid van Moolenbroek u_int ox, oy, px, py; 1628*eda6f593SDavid van Moolenbroek 1629*eda6f593SDavid van Moolenbroek oy = screen_hsize(data->backing) + data->cy - data->oy; 1630*eda6f593SDavid van Moolenbroek ox = window_copy_find_length(wp, oy); 1631*eda6f593SDavid van Moolenbroek if (ox != 0) { 1632*eda6f593SDavid van Moolenbroek data->lastcx = data->cx; 1633*eda6f593SDavid van Moolenbroek data->lastsx = ox; 1634*eda6f593SDavid van Moolenbroek } 1635*eda6f593SDavid van Moolenbroek 1636*eda6f593SDavid van Moolenbroek data->cx = data->lastcx; 1637*eda6f593SDavid van Moolenbroek if (scroll_only || data->cy == screen_size_y(s) - 1) { 1638*eda6f593SDavid van Moolenbroek window_copy_scroll_up(wp, 1); 1639*eda6f593SDavid van Moolenbroek if (scroll_only && data->cy > 0) 1640*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy - 1, 2); 1641*eda6f593SDavid van Moolenbroek } else { 1642*eda6f593SDavid van Moolenbroek window_copy_update_cursor(wp, data->cx, data->cy + 1); 1643*eda6f593SDavid van Moolenbroek if (window_copy_update_selection(wp)) 1644*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy - 1, 2); 1645*eda6f593SDavid van Moolenbroek } 1646*eda6f593SDavid van Moolenbroek 1647*eda6f593SDavid van Moolenbroek if (!data->screen.sel.flag || !data->rectflag) { 1648*eda6f593SDavid van Moolenbroek py = screen_hsize(data->backing) + data->cy - data->oy; 1649*eda6f593SDavid van Moolenbroek px = window_copy_find_length(wp, py); 1650*eda6f593SDavid van Moolenbroek if ((data->cx >= data->lastsx && data->cx != px) || 1651*eda6f593SDavid van Moolenbroek data->cx > px) 1652*eda6f593SDavid van Moolenbroek window_copy_cursor_end_of_line(wp); 1653*eda6f593SDavid van Moolenbroek } 1654*eda6f593SDavid van Moolenbroek } 1655*eda6f593SDavid van Moolenbroek 1656*eda6f593SDavid van Moolenbroek void 1657*eda6f593SDavid van Moolenbroek window_copy_cursor_jump(struct window_pane *wp) 1658*eda6f593SDavid van Moolenbroek { 1659*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1660*eda6f593SDavid van Moolenbroek struct screen *back_s = data->backing; 1661*eda6f593SDavid van Moolenbroek const struct grid_cell *gc; 1662*eda6f593SDavid van Moolenbroek u_int px, py, xx; 1663*eda6f593SDavid van Moolenbroek 1664*eda6f593SDavid van Moolenbroek px = data->cx + 1; 1665*eda6f593SDavid van Moolenbroek py = screen_hsize(back_s) + data->cy - data->oy; 1666*eda6f593SDavid van Moolenbroek xx = window_copy_find_length(wp, py); 1667*eda6f593SDavid van Moolenbroek 1668*eda6f593SDavid van Moolenbroek while (px < xx) { 1669*eda6f593SDavid van Moolenbroek gc = grid_peek_cell(back_s->grid, px, py); 1670*eda6f593SDavid van Moolenbroek if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0 1671*eda6f593SDavid van Moolenbroek && gc->data == data->jumpchar) { 1672*eda6f593SDavid van Moolenbroek 1673*eda6f593SDavid van Moolenbroek window_copy_update_cursor(wp, px, data->cy); 1674*eda6f593SDavid van Moolenbroek if (window_copy_update_selection(wp)) 1675*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy, 1); 1676*eda6f593SDavid van Moolenbroek return; 1677*eda6f593SDavid van Moolenbroek } 1678*eda6f593SDavid van Moolenbroek px++; 1679*eda6f593SDavid van Moolenbroek } 1680*eda6f593SDavid van Moolenbroek } 1681*eda6f593SDavid van Moolenbroek 1682*eda6f593SDavid van Moolenbroek void 1683*eda6f593SDavid van Moolenbroek window_copy_cursor_jump_back(struct window_pane *wp) 1684*eda6f593SDavid van Moolenbroek { 1685*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1686*eda6f593SDavid van Moolenbroek struct screen *back_s = data->backing; 1687*eda6f593SDavid van Moolenbroek const struct grid_cell *gc; 1688*eda6f593SDavid van Moolenbroek u_int px, py; 1689*eda6f593SDavid van Moolenbroek 1690*eda6f593SDavid van Moolenbroek px = data->cx; 1691*eda6f593SDavid van Moolenbroek py = screen_hsize(back_s) + data->cy - data->oy; 1692*eda6f593SDavid van Moolenbroek 1693*eda6f593SDavid van Moolenbroek if (px > 0) 1694*eda6f593SDavid van Moolenbroek px--; 1695*eda6f593SDavid van Moolenbroek 1696*eda6f593SDavid van Moolenbroek for (;;) { 1697*eda6f593SDavid van Moolenbroek gc = grid_peek_cell(back_s->grid, px, py); 1698*eda6f593SDavid van Moolenbroek if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0 1699*eda6f593SDavid van Moolenbroek && gc->data == data->jumpchar) { 1700*eda6f593SDavid van Moolenbroek 1701*eda6f593SDavid van Moolenbroek window_copy_update_cursor(wp, px, data->cy); 1702*eda6f593SDavid van Moolenbroek if (window_copy_update_selection(wp)) 1703*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy, 1); 1704*eda6f593SDavid van Moolenbroek return; 1705*eda6f593SDavid van Moolenbroek } 1706*eda6f593SDavid van Moolenbroek if (px == 0) 1707*eda6f593SDavid van Moolenbroek break; 1708*eda6f593SDavid van Moolenbroek px--; 1709*eda6f593SDavid van Moolenbroek } 1710*eda6f593SDavid van Moolenbroek } 1711*eda6f593SDavid van Moolenbroek 1712*eda6f593SDavid van Moolenbroek void 1713*eda6f593SDavid van Moolenbroek window_copy_cursor_next_word(struct window_pane *wp, const char *separators) 1714*eda6f593SDavid van Moolenbroek { 1715*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1716*eda6f593SDavid van Moolenbroek struct screen *back_s = data->backing; 1717*eda6f593SDavid van Moolenbroek u_int px, py, xx, yy; 1718*eda6f593SDavid van Moolenbroek int expected = 0; 1719*eda6f593SDavid van Moolenbroek 1720*eda6f593SDavid van Moolenbroek px = data->cx; 1721*eda6f593SDavid van Moolenbroek py = screen_hsize(back_s) + data->cy - data->oy; 1722*eda6f593SDavid van Moolenbroek xx = window_copy_find_length(wp, py); 1723*eda6f593SDavid van Moolenbroek yy = screen_hsize(back_s) + screen_size_y(back_s) - 1; 1724*eda6f593SDavid van Moolenbroek 1725*eda6f593SDavid van Moolenbroek /* 1726*eda6f593SDavid van Moolenbroek * First skip past any nonword characters and then any word characters. 1727*eda6f593SDavid van Moolenbroek * 1728*eda6f593SDavid van Moolenbroek * expected is initially set to 0 for the former and then 1 for the 1729*eda6f593SDavid van Moolenbroek * latter. 1730*eda6f593SDavid van Moolenbroek */ 1731*eda6f593SDavid van Moolenbroek do { 1732*eda6f593SDavid van Moolenbroek while (px > xx || 1733*eda6f593SDavid van Moolenbroek window_copy_in_set(wp, px, py, separators) == expected) { 1734*eda6f593SDavid van Moolenbroek /* Move down if we're past the end of the line. */ 1735*eda6f593SDavid van Moolenbroek if (px > xx) { 1736*eda6f593SDavid van Moolenbroek if (py == yy) 1737*eda6f593SDavid van Moolenbroek return; 1738*eda6f593SDavid van Moolenbroek window_copy_cursor_down(wp, 0); 1739*eda6f593SDavid van Moolenbroek px = 0; 1740*eda6f593SDavid van Moolenbroek 1741*eda6f593SDavid van Moolenbroek py = screen_hsize(back_s) + data->cy - data->oy; 1742*eda6f593SDavid van Moolenbroek xx = window_copy_find_length(wp, py); 1743*eda6f593SDavid van Moolenbroek } else 1744*eda6f593SDavid van Moolenbroek px++; 1745*eda6f593SDavid van Moolenbroek } 1746*eda6f593SDavid van Moolenbroek expected = !expected; 1747*eda6f593SDavid van Moolenbroek } while (expected == 1); 1748*eda6f593SDavid van Moolenbroek 1749*eda6f593SDavid van Moolenbroek window_copy_update_cursor(wp, px, data->cy); 1750*eda6f593SDavid van Moolenbroek if (window_copy_update_selection(wp)) 1751*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy, 1); 1752*eda6f593SDavid van Moolenbroek } 1753*eda6f593SDavid van Moolenbroek 1754*eda6f593SDavid van Moolenbroek void 1755*eda6f593SDavid van Moolenbroek window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators) 1756*eda6f593SDavid van Moolenbroek { 1757*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1758*eda6f593SDavid van Moolenbroek struct screen *back_s = data->backing; 1759*eda6f593SDavid van Moolenbroek u_int px, py, xx, yy; 1760*eda6f593SDavid van Moolenbroek int expected = 1; 1761*eda6f593SDavid van Moolenbroek 1762*eda6f593SDavid van Moolenbroek px = data->cx; 1763*eda6f593SDavid van Moolenbroek py = screen_hsize(back_s) + data->cy - data->oy; 1764*eda6f593SDavid van Moolenbroek xx = window_copy_find_length(wp, py); 1765*eda6f593SDavid van Moolenbroek yy = screen_hsize(back_s) + screen_size_y(back_s) - 1; 1766*eda6f593SDavid van Moolenbroek 1767*eda6f593SDavid van Moolenbroek /* 1768*eda6f593SDavid van Moolenbroek * First skip past any word characters, then any nonword characters. 1769*eda6f593SDavid van Moolenbroek * 1770*eda6f593SDavid van Moolenbroek * expected is initially set to 1 for the former and then 0 for the 1771*eda6f593SDavid van Moolenbroek * latter. 1772*eda6f593SDavid van Moolenbroek */ 1773*eda6f593SDavid van Moolenbroek do { 1774*eda6f593SDavid van Moolenbroek while (px > xx || 1775*eda6f593SDavid van Moolenbroek window_copy_in_set(wp, px, py, separators) == expected) { 1776*eda6f593SDavid van Moolenbroek /* Move down if we're past the end of the line. */ 1777*eda6f593SDavid van Moolenbroek if (px > xx) { 1778*eda6f593SDavid van Moolenbroek if (py == yy) 1779*eda6f593SDavid van Moolenbroek return; 1780*eda6f593SDavid van Moolenbroek window_copy_cursor_down(wp, 0); 1781*eda6f593SDavid van Moolenbroek px = 0; 1782*eda6f593SDavid van Moolenbroek 1783*eda6f593SDavid van Moolenbroek py = screen_hsize(back_s) + data->cy - data->oy; 1784*eda6f593SDavid van Moolenbroek xx = window_copy_find_length(wp, py); 1785*eda6f593SDavid van Moolenbroek } else 1786*eda6f593SDavid van Moolenbroek px++; 1787*eda6f593SDavid van Moolenbroek } 1788*eda6f593SDavid van Moolenbroek expected = !expected; 1789*eda6f593SDavid van Moolenbroek } while (expected == 0); 1790*eda6f593SDavid van Moolenbroek 1791*eda6f593SDavid van Moolenbroek window_copy_update_cursor(wp, px, data->cy); 1792*eda6f593SDavid van Moolenbroek if (window_copy_update_selection(wp)) 1793*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy, 1); 1794*eda6f593SDavid van Moolenbroek } 1795*eda6f593SDavid van Moolenbroek 1796*eda6f593SDavid van Moolenbroek /* Move to the previous place where a word begins. */ 1797*eda6f593SDavid van Moolenbroek void 1798*eda6f593SDavid van Moolenbroek window_copy_cursor_previous_word(struct window_pane *wp, const char *separators) 1799*eda6f593SDavid van Moolenbroek { 1800*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1801*eda6f593SDavid van Moolenbroek u_int px, py; 1802*eda6f593SDavid van Moolenbroek 1803*eda6f593SDavid van Moolenbroek px = data->cx; 1804*eda6f593SDavid van Moolenbroek py = screen_hsize(data->backing) + data->cy - data->oy; 1805*eda6f593SDavid van Moolenbroek 1806*eda6f593SDavid van Moolenbroek /* Move back to the previous word character. */ 1807*eda6f593SDavid van Moolenbroek for (;;) { 1808*eda6f593SDavid van Moolenbroek if (px > 0) { 1809*eda6f593SDavid van Moolenbroek px--; 1810*eda6f593SDavid van Moolenbroek if (!window_copy_in_set(wp, px, py, separators)) 1811*eda6f593SDavid van Moolenbroek break; 1812*eda6f593SDavid van Moolenbroek } else { 1813*eda6f593SDavid van Moolenbroek if (data->cy == 0 && 1814*eda6f593SDavid van Moolenbroek (screen_hsize(data->backing) == 0 || 1815*eda6f593SDavid van Moolenbroek data->oy >= screen_hsize(data->backing) - 1)) 1816*eda6f593SDavid van Moolenbroek goto out; 1817*eda6f593SDavid van Moolenbroek window_copy_cursor_up(wp, 0); 1818*eda6f593SDavid van Moolenbroek 1819*eda6f593SDavid van Moolenbroek py = screen_hsize(data->backing) + data->cy - data->oy; 1820*eda6f593SDavid van Moolenbroek px = window_copy_find_length(wp, py); 1821*eda6f593SDavid van Moolenbroek } 1822*eda6f593SDavid van Moolenbroek } 1823*eda6f593SDavid van Moolenbroek 1824*eda6f593SDavid van Moolenbroek /* Move back to the beginning of this word. */ 1825*eda6f593SDavid van Moolenbroek while (px > 0 && !window_copy_in_set(wp, px - 1, py, separators)) 1826*eda6f593SDavid van Moolenbroek px--; 1827*eda6f593SDavid van Moolenbroek 1828*eda6f593SDavid van Moolenbroek out: 1829*eda6f593SDavid van Moolenbroek window_copy_update_cursor(wp, px, data->cy); 1830*eda6f593SDavid van Moolenbroek if (window_copy_update_selection(wp)) 1831*eda6f593SDavid van Moolenbroek window_copy_redraw_lines(wp, data->cy, 1); 1832*eda6f593SDavid van Moolenbroek } 1833*eda6f593SDavid van Moolenbroek 1834*eda6f593SDavid van Moolenbroek void 1835*eda6f593SDavid van Moolenbroek window_copy_scroll_up(struct window_pane *wp, u_int ny) 1836*eda6f593SDavid van Moolenbroek { 1837*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1838*eda6f593SDavid van Moolenbroek struct screen *s = &data->screen; 1839*eda6f593SDavid van Moolenbroek struct screen_write_ctx ctx; 1840*eda6f593SDavid van Moolenbroek 1841*eda6f593SDavid van Moolenbroek if (data->oy < ny) 1842*eda6f593SDavid van Moolenbroek ny = data->oy; 1843*eda6f593SDavid van Moolenbroek if (ny == 0) 1844*eda6f593SDavid van Moolenbroek return; 1845*eda6f593SDavid van Moolenbroek data->oy -= ny; 1846*eda6f593SDavid van Moolenbroek 1847*eda6f593SDavid van Moolenbroek screen_write_start(&ctx, wp, NULL); 1848*eda6f593SDavid van Moolenbroek screen_write_cursormove(&ctx, 0, 0); 1849*eda6f593SDavid van Moolenbroek screen_write_deleteline(&ctx, ny); 1850*eda6f593SDavid van Moolenbroek window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, ny); 1851*eda6f593SDavid van Moolenbroek window_copy_write_line(wp, &ctx, 0); 1852*eda6f593SDavid van Moolenbroek if (screen_size_y(s) > 1) 1853*eda6f593SDavid van Moolenbroek window_copy_write_line(wp, &ctx, 1); 1854*eda6f593SDavid van Moolenbroek if (screen_size_y(s) > 3) 1855*eda6f593SDavid van Moolenbroek window_copy_write_line(wp, &ctx, screen_size_y(s) - 2); 1856*eda6f593SDavid van Moolenbroek if (s->sel.flag && screen_size_y(s) > ny) { 1857*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 1858*eda6f593SDavid van Moolenbroek window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1); 1859*eda6f593SDavid van Moolenbroek } 1860*eda6f593SDavid van Moolenbroek screen_write_cursormove(&ctx, data->cx, data->cy); 1861*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 1862*eda6f593SDavid van Moolenbroek screen_write_stop(&ctx); 1863*eda6f593SDavid van Moolenbroek } 1864*eda6f593SDavid van Moolenbroek 1865*eda6f593SDavid van Moolenbroek void 1866*eda6f593SDavid van Moolenbroek window_copy_scroll_down(struct window_pane *wp, u_int ny) 1867*eda6f593SDavid van Moolenbroek { 1868*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1869*eda6f593SDavid van Moolenbroek struct screen *s = &data->screen; 1870*eda6f593SDavid van Moolenbroek struct screen_write_ctx ctx; 1871*eda6f593SDavid van Moolenbroek 1872*eda6f593SDavid van Moolenbroek if (ny > screen_hsize(data->backing)) 1873*eda6f593SDavid van Moolenbroek return; 1874*eda6f593SDavid van Moolenbroek 1875*eda6f593SDavid van Moolenbroek if (data->oy > screen_hsize(data->backing) - ny) 1876*eda6f593SDavid van Moolenbroek ny = screen_hsize(data->backing) - data->oy; 1877*eda6f593SDavid van Moolenbroek if (ny == 0) 1878*eda6f593SDavid van Moolenbroek return; 1879*eda6f593SDavid van Moolenbroek data->oy += ny; 1880*eda6f593SDavid van Moolenbroek 1881*eda6f593SDavid van Moolenbroek screen_write_start(&ctx, wp, NULL); 1882*eda6f593SDavid van Moolenbroek screen_write_cursormove(&ctx, 0, 0); 1883*eda6f593SDavid van Moolenbroek screen_write_insertline(&ctx, ny); 1884*eda6f593SDavid van Moolenbroek window_copy_write_lines(wp, &ctx, 0, ny); 1885*eda6f593SDavid van Moolenbroek if (s->sel.flag && screen_size_y(s) > ny) { 1886*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 1887*eda6f593SDavid van Moolenbroek window_copy_write_line(wp, &ctx, ny); 1888*eda6f593SDavid van Moolenbroek } else if (ny == 1) /* nuke position */ 1889*eda6f593SDavid van Moolenbroek window_copy_write_line(wp, &ctx, 1); 1890*eda6f593SDavid van Moolenbroek screen_write_cursormove(&ctx, data->cx, data->cy); 1891*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 1892*eda6f593SDavid van Moolenbroek screen_write_stop(&ctx); 1893*eda6f593SDavid van Moolenbroek } 1894*eda6f593SDavid van Moolenbroek 1895*eda6f593SDavid van Moolenbroek void 1896*eda6f593SDavid van Moolenbroek window_copy_rectangle_toggle(struct window_pane *wp) 1897*eda6f593SDavid van Moolenbroek { 1898*eda6f593SDavid van Moolenbroek struct window_copy_mode_data *data = wp->modedata; 1899*eda6f593SDavid van Moolenbroek u_int px, py; 1900*eda6f593SDavid van Moolenbroek 1901*eda6f593SDavid van Moolenbroek data->rectflag = !data->rectflag; 1902*eda6f593SDavid van Moolenbroek 1903*eda6f593SDavid van Moolenbroek py = screen_hsize(data->backing) + data->cy - data->oy; 1904*eda6f593SDavid van Moolenbroek px = window_copy_find_length(wp, py); 1905*eda6f593SDavid van Moolenbroek if (data->cx > px) 1906*eda6f593SDavid van Moolenbroek window_copy_update_cursor(wp, px, data->cy); 1907*eda6f593SDavid van Moolenbroek 1908*eda6f593SDavid van Moolenbroek window_copy_update_selection(wp); 1909*eda6f593SDavid van Moolenbroek window_copy_redraw_screen(wp); 1910*eda6f593SDavid van Moolenbroek } 1911