[BACK]Return to window-copy.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Annotation of src/usr.bin/tmux/window-copy.c, Revision 1.138

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