[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.215

1.215   ! nicm        1: /* $OpenBSD: window-copy.c,v 1.214 2019/03/27 13:25:11 nicm Exp $ */
1.1       nicm        2:
                      3: /*
1.144     nicm        4:  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
1.1       nicm        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:
1.208     nicm       27: static const char *window_copy_key_table(struct window_mode_entry *);
                     28: static void    window_copy_command(struct window_mode_entry *, struct client *,
1.205     nicm       29:                    struct session *, struct winlink *, struct args *,
                     30:                    struct mouse_event *);
1.208     nicm       31: static struct screen *window_copy_init(struct window_mode_entry *,
1.177     nicm       32:                    struct cmd_find_state *, struct args *);
1.210     nicm       33: static struct screen *window_copy_view_init(struct window_mode_entry *,
                     34:                    struct cmd_find_state *, struct args *);
1.208     nicm       35: static void    window_copy_free(struct window_mode_entry *);
                     36: static void    window_copy_resize(struct window_mode_entry *, u_int, u_int);
                     37: static void    window_copy_formats(struct window_mode_entry *,
                     38:                    struct format_tree *);
                     39: static void    window_copy_pageup1(struct window_mode_entry *, int);
                     40: static int     window_copy_pagedown(struct window_mode_entry *, int, int);
                     41: static void    window_copy_next_paragraph(struct window_mode_entry *);
                     42: static void    window_copy_previous_paragraph(struct window_mode_entry *);
                     43:
                     44: static void    window_copy_redraw_selection(struct window_mode_entry *, u_int);
                     45: static void    window_copy_redraw_lines(struct window_mode_entry *, u_int,
                     46:                    u_int);
                     47: static void    window_copy_redraw_screen(struct window_mode_entry *);
                     48: static void    window_copy_write_line(struct window_mode_entry *,
1.157     nicm       49:                    struct screen_write_ctx *, u_int);
1.208     nicm       50: static void    window_copy_write_lines(struct window_mode_entry *,
1.157     nicm       51:                    struct screen_write_ctx *, u_int, u_int);
                     52:
1.208     nicm       53: static void    window_copy_scroll_to(struct window_mode_entry *, u_int, u_int);
1.157     nicm       54: static int     window_copy_search_compare(struct grid *, u_int, u_int,
                     55:                    struct grid *, u_int, int);
                     56: static int     window_copy_search_lr(struct grid *, struct grid *, u_int *,
                     57:                    u_int, u_int, u_int, int);
                     58: static int     window_copy_search_rl(struct grid *, struct grid *, u_int *,
                     59:                    u_int, u_int, u_int, int);
1.208     nicm       60: static int     window_copy_search_marks(struct window_mode_entry *,
                     61:                    struct screen *);
                     62: static void    window_copy_clear_marks(struct window_mode_entry *);
1.157     nicm       63: static void    window_copy_move_left(struct screen *, u_int *, u_int *);
                     64: static void    window_copy_move_right(struct screen *, u_int *, u_int *);
                     65: static int     window_copy_is_lowercase(const char *);
1.208     nicm       66: static int     window_copy_search_jump(struct window_mode_entry *,
                     67:                    struct grid *, struct grid *, u_int, u_int, u_int, int, int,
                     68:                    int);
                     69: static int     window_copy_search(struct window_mode_entry *, int);
                     70: static int     window_copy_search_up(struct window_mode_entry *);
                     71: static int     window_copy_search_down(struct window_mode_entry *);
                     72: static void    window_copy_goto_line(struct window_mode_entry *, const char *);
                     73: static void    window_copy_update_cursor(struct window_mode_entry *, u_int,
                     74:                    u_int);
                     75: static void    window_copy_start_selection(struct window_mode_entry *);
                     76: static int     window_copy_adjust_selection(struct window_mode_entry *,
                     77:                    u_int *, u_int *);
                     78: static int     window_copy_set_selection(struct window_mode_entry *, int);
                     79: static int     window_copy_update_selection(struct window_mode_entry *, int);
                     80: static void    window_copy_synchronize_cursor(struct window_mode_entry *);
                     81: static void    *window_copy_get_selection(struct window_mode_entry *, size_t *);
1.215   ! nicm       82: static void    window_copy_copy_buffer(struct window_mode_entry *,
        !            83:                    const char *, void *, size_t);
1.208     nicm       84: static void    window_copy_copy_pipe(struct window_mode_entry *,
1.215   ! nicm       85:                    struct session *, const char *, const char *);
        !            86: static void    window_copy_copy_selection(struct window_mode_entry *,
        !            87:                    const char *);
1.208     nicm       88: static void    window_copy_append_selection(struct window_mode_entry *);
                     89: static void    window_copy_clear_selection(struct window_mode_entry *);
                     90: static void    window_copy_copy_line(struct window_mode_entry *, char **,
                     91:                    size_t *, u_int, u_int, u_int);
                     92: static int     window_copy_in_set(struct window_mode_entry *, u_int, u_int,
1.157     nicm       93:                    const char *);
1.208     nicm       94: static u_int   window_copy_find_length(struct window_mode_entry *, u_int);
                     95: static void    window_copy_cursor_start_of_line(struct window_mode_entry *);
                     96: static void    window_copy_cursor_back_to_indentation(
                     97:                    struct window_mode_entry *);
                     98: static void    window_copy_cursor_end_of_line(struct window_mode_entry *);
                     99: static void    window_copy_other_end(struct window_mode_entry *);
                    100: static void    window_copy_cursor_left(struct window_mode_entry *);
                    101: static void    window_copy_cursor_right(struct window_mode_entry *);
                    102: static void    window_copy_cursor_up(struct window_mode_entry *, int);
                    103: static void    window_copy_cursor_down(struct window_mode_entry *, int);
                    104: static void    window_copy_cursor_jump(struct window_mode_entry *);
                    105: static void    window_copy_cursor_jump_back(struct window_mode_entry *);
                    106: static void    window_copy_cursor_jump_to(struct window_mode_entry *);
                    107: static void    window_copy_cursor_jump_to_back(struct window_mode_entry *);
                    108: static void    window_copy_cursor_next_word(struct window_mode_entry *,
1.157     nicm      109:                    const char *);
1.208     nicm      110: static void    window_copy_cursor_next_word_end(struct window_mode_entry *,
1.157     nicm      111:                    const char *);
1.208     nicm      112: static void    window_copy_cursor_previous_word(struct window_mode_entry *,
1.157     nicm      113:                    const char *);
1.208     nicm      114: static void    window_copy_scroll_up(struct window_mode_entry *, u_int);
                    115: static void    window_copy_scroll_down(struct window_mode_entry *, u_int);
                    116: static void    window_copy_rectangle_toggle(struct window_mode_entry *);
1.157     nicm      117: static void    window_copy_move_mouse(struct mouse_event *);
                    118: static void    window_copy_drag_update(struct client *, struct mouse_event *);
1.1       nicm      119:
                    120: const struct window_mode window_copy_mode = {
1.173     nicm      121:        .name = "copy-mode",
                    122:
1.155     nicm      123:        .init = window_copy_init,
                    124:        .free = window_copy_free,
                    125:        .resize = window_copy_resize,
                    126:        .key_table = window_copy_key_table,
                    127:        .command = window_copy_command,
1.206     nicm      128:        .formats = window_copy_formats,
1.1       nicm      129: };
                    130:
1.210     nicm      131: const struct window_mode window_view_mode = {
                    132:        .name = "view-mode",
                    133:
                    134:        .init = window_copy_view_init,
                    135:        .free = window_copy_free,
                    136:        .resize = window_copy_resize,
                    137:        .key_table = window_copy_key_table,
                    138:        .command = window_copy_command,
                    139:        .formats = window_copy_formats,
                    140: };
                    141:
1.155     nicm      142: enum {
1.21      nicm      143:        WINDOW_COPY_OFF,
                    144:        WINDOW_COPY_SEARCHUP,
                    145:        WINDOW_COPY_SEARCHDOWN,
1.52      nicm      146:        WINDOW_COPY_JUMPFORWARD,
1.155     nicm      147:        WINDOW_COPY_JUMPBACKWARD,
1.76      nicm      148:        WINDOW_COPY_JUMPTOFORWARD,
1.155     nicm      149:        WINDOW_COPY_JUMPTOBACKWARD,
1.21      nicm      150: };
                    151:
1.161     nicm      152: enum {
                    153:        WINDOW_COPY_REL_POS_ABOVE,
                    154:        WINDOW_COPY_REL_POS_ON_SCREEN,
                    155:        WINDOW_COPY_REL_POS_BELOW,
                    156: };
                    157:
1.213     nicm      158: enum window_copy_cmd_action {
                    159:        WINDOW_COPY_CMD_NOTHING,
                    160:        WINDOW_COPY_CMD_REDRAW,
                    161:        WINDOW_COPY_CMD_CANCEL,
                    162: };
                    163:
                    164: struct window_copy_cmd_state {
                    165:        struct window_mode_entry        *wme;
                    166:        struct args                     *args;
                    167:        struct mouse_event              *m;
1.215   ! nicm      168:
1.213     nicm      169:        struct client                   *c;
                    170:        struct session                  *s;
1.215   ! nicm      171:        struct winlink                  *wl;
1.213     nicm      172: };
                    173:
1.54      nicm      174: /*
1.161     nicm      175:  * Copy mode's visible screen (the "screen" field) is filled from one of two
                    176:  * sources: the original contents of the pane (used when we actually enter via
                    177:  * the "copy-mode" command, to copy the contents of the current pane), or else
                    178:  * a series of lines containing the output from an output-writing tmux command
                    179:  * (such as any of the "show-*" or "list-*" commands).
1.54      nicm      180:  *
1.161     nicm      181:  * In either case, the full content of the copy-mode grid is pointed at by the
                    182:  * "backing" field, and is copied into "screen" as needed (that is, when
                    183:  * scrolling occurs). When copy-mode is backed by a pane, backing points
                    184:  * directly at that pane's screen structure (&wp->base); when backed by a list
                    185:  * of output-lines from a command, it points at a newly-allocated screen
                    186:  * structure (which is deallocated when the mode ends).
1.54      nicm      187:  */
1.1       nicm      188: struct window_copy_mode_data {
1.155     nicm      189:        struct screen    screen;
1.1       nicm      190:
1.155     nicm      191:        struct screen   *backing;
                    192:        int              backing_written; /* backing display started */
1.54      nicm      193:
1.192     nicm      194:        u_int            oy;            /* number of lines scrolled up */
1.21      nicm      195:
1.192     nicm      196:        u_int            selx;          /* beginning of selection */
1.155     nicm      197:        u_int            sely;
1.21      nicm      198:
1.192     nicm      199:        u_int            endselx;       /* end of selection */
1.161     nicm      200:        u_int            endsely;
                    201:
                    202:        enum {
                    203:                CURSORDRAG_NONE,        /* selection is independent of cursor */
                    204:                CURSORDRAG_ENDSEL,      /* end is synchronized with cursor */
                    205:                CURSORDRAG_SEL,         /* start is synchronized with cursor */
                    206:        } cursordrag;
                    207:
1.192     nicm      208:        int              modekeys;
                    209:        enum {
                    210:                LINE_SEL_NONE,
                    211:                LINE_SEL_LEFT_RIGHT,
                    212:                LINE_SEL_RIGHT_LEFT,
                    213:        } lineflag;                     /* line selection mode */
1.155     nicm      214:        int              rectflag;      /* in rectangle copy mode? */
                    215:        int              scroll_exit;   /* exit on scroll to end? */
1.1       nicm      216:
1.155     nicm      217:        u_int            cx;
                    218:        u_int            cy;
1.42      nicm      219:
1.192     nicm      220:        u_int            lastcx;        /* position in last line w/ content */
                    221:        u_int            lastsx;        /* size of last line w/ content */
1.1       nicm      222:
1.155     nicm      223:        int              searchtype;
                    224:        char            *searchstr;
1.162     nicm      225:        bitstr_t        *searchmark;
1.170     nicm      226:        u_int            searchcount;
                    227:        int              searchthis;
1.163     nicm      228:        int              searchx;
                    229:        int              searchy;
                    230:        int              searcho;
1.25      nicm      231:
1.155     nicm      232:        int              jumptype;
                    233:        char             jumpchar;
1.1       nicm      234: };
                    235:
1.210     nicm      236: static struct window_copy_mode_data *
                    237: window_copy_common_init(struct window_mode_entry *wme)
1.1       nicm      238: {
1.208     nicm      239:        struct window_pane              *wp = wme->wp;
1.1       nicm      240:        struct window_copy_mode_data    *data;
1.210     nicm      241:        struct screen                   *base = &wp->base;
1.1       nicm      242:
1.208     nicm      243:        wme->data = data = xcalloc(1, sizeof *data);
1.1       nicm      244:
1.161     nicm      245:        data->cursordrag = CURSORDRAG_NONE;
1.193     nicm      246:        data->lineflag = LINE_SEL_NONE;
1.42      nicm      247:
1.174     nicm      248:        if (wp->searchstr != NULL) {
                    249:                data->searchtype = WINDOW_COPY_SEARCHUP;
                    250:                data->searchstr = xstrdup(wp->searchstr);
                    251:        } else {
                    252:                data->searchtype = WINDOW_COPY_OFF;
                    253:                data->searchstr = NULL;
                    254:        }
1.162     nicm      255:        data->searchmark = NULL;
1.163     nicm      256:        data->searchx = data->searchy = data->searcho = -1;
1.21      nicm      257:
1.52      nicm      258:        data->jumptype = WINDOW_COPY_OFF;
                    259:        data->jumpchar = '\0';
                    260:
1.210     nicm      261:        screen_init(&data->screen, screen_size_x(base), screen_size_y(base), 0);
1.192     nicm      262:        data->modekeys = options_get_number(wp->window->options, "mode-keys");
1.1       nicm      263:
1.210     nicm      264:        return (data);
1.54      nicm      265: }
                    266:
1.210     nicm      267: static struct screen *
                    268: window_copy_init(struct window_mode_entry *wme,
                    269:     __unused struct cmd_find_state *fs, struct args *args)
1.54      nicm      270: {
1.210     nicm      271:        struct window_pane              *wp = wme->wp;
                    272:        struct window_copy_mode_data    *data;
                    273:        struct screen_write_ctx          ctx;
1.54      nicm      274:        u_int                            i;
                    275:
1.210     nicm      276:        data = window_copy_common_init(wme);
                    277:
1.211     nicm      278:        if (wp->fd != -1 && wp->disabled++ == 0)
1.210     nicm      279:                bufferevent_disable(wp->event, EV_READ|EV_WRITE);
1.54      nicm      280:
                    281:        data->backing = &wp->base;
                    282:        data->cx = data->backing->cx;
                    283:        data->cy = data->backing->cy;
                    284:
1.210     nicm      285:        data->scroll_exit = args_has(args, 'e');
1.1       nicm      286:
1.210     nicm      287:        data->screen.cx = data->cx;
                    288:        data->screen.cy = data->cy;
                    289:
                    290:        screen_write_start(&ctx, NULL, &data->screen);
                    291:        for (i = 0; i < screen_size_y(&data->screen); i++)
1.208     nicm      292:                window_copy_write_line(wme, &ctx, i);
1.212     nicm      293:        screen_write_cursormove(&ctx, data->cx, data->cy, 0);
1.1       nicm      294:        screen_write_stop(&ctx);
1.210     nicm      295:
                    296:        return (&data->screen);
1.54      nicm      297: }
1.1       nicm      298:
1.210     nicm      299: static struct screen *
                    300: window_copy_view_init(struct window_mode_entry *wme,
                    301:     __unused struct cmd_find_state *fs, __unused struct args *args)
1.54      nicm      302: {
1.210     nicm      303:        struct window_pane              *wp = wme->wp;
1.208     nicm      304:        struct window_copy_mode_data    *data;
1.210     nicm      305:        struct screen                   *base = &wp->base;
                    306:        struct screen                   *s;
1.54      nicm      307:
1.210     nicm      308:        data = window_copy_common_init(wme);
1.208     nicm      309:
1.210     nicm      310:        data->backing = s = xmalloc(sizeof *data->backing);
                    311:        screen_init(s, screen_size_x(base), screen_size_y(base), UINT_MAX);
1.207     nicm      312:
1.210     nicm      313:        return (&data->screen);
1.1       nicm      314: }
                    315:
1.157     nicm      316: static void
1.208     nicm      317: window_copy_free(struct window_mode_entry *wme)
1.1       nicm      318: {
1.208     nicm      319:        struct window_pane              *wp = wme->wp;
                    320:        struct window_copy_mode_data    *data = wme->data;
1.46      nicm      321:
1.211     nicm      322:        if (wp->fd != -1 && --wp->disabled == 0)
1.61      nicm      323:                bufferevent_enable(wp->event, EV_READ|EV_WRITE);
1.1       nicm      324:
1.162     nicm      325:        free(data->searchmark);
1.81      nicm      326:        free(data->searchstr);
1.21      nicm      327:
1.54      nicm      328:        if (data->backing != &wp->base) {
                    329:                screen_free(data->backing);
1.81      nicm      330:                free(data->backing);
1.54      nicm      331:        }
1.1       nicm      332:        screen_free(&data->screen);
1.21      nicm      333:
1.81      nicm      334:        free(data);
1.1       nicm      335: }
                    336:
                    337: void
1.54      nicm      338: window_copy_add(struct window_pane *wp, const char *fmt, ...)
                    339: {
                    340:        va_list ap;
                    341:
                    342:        va_start(ap, fmt);
                    343:        window_copy_vadd(wp, fmt, ap);
                    344:        va_end(ap);
                    345: }
                    346:
                    347: void
                    348: window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap)
                    349: {
1.211     nicm      350:        struct window_mode_entry        *wme = TAILQ_FIRST(&wp->modes);
1.208     nicm      351:        struct window_copy_mode_data    *data = wme->data;
1.54      nicm      352:        struct screen                   *backing = data->backing;
                    353:        struct screen_write_ctx          back_ctx, ctx;
                    354:        struct grid_cell                 gc;
1.119     nicm      355:        u_int                            old_hsize, old_cy;
1.54      nicm      356:
                    357:        if (backing == &wp->base)
                    358:                return;
                    359:
                    360:        memcpy(&gc, &grid_default_cell, sizeof gc);
                    361:
                    362:        old_hsize = screen_hsize(data->backing);
                    363:        screen_write_start(&back_ctx, NULL, backing);
                    364:        if (data->backing_written) {
                    365:                /*
                    366:                 * On the second or later line, do a CRLF before writing
                    367:                 * (so it's on a new line).
                    368:                 */
                    369:                screen_write_carriagereturn(&back_ctx);
1.175     nicm      370:                screen_write_linefeed(&back_ctx, 0, 8);
1.54      nicm      371:        } else
                    372:                data->backing_written = 1;
1.119     nicm      373:        old_cy = backing->cy;
1.139     nicm      374:        screen_write_vnputs(&back_ctx, 0, &gc, fmt, ap);
1.54      nicm      375:        screen_write_stop(&back_ctx);
                    376:
                    377:        data->oy += screen_hsize(data->backing) - old_hsize;
                    378:
                    379:        screen_write_start(&ctx, wp, &data->screen);
                    380:
                    381:        /*
                    382:         * If the history has changed, draw the top line.
                    383:         * (If there's any history at all, it has changed.)
                    384:         */
                    385:        if (screen_hsize(data->backing))
1.208     nicm      386:                window_copy_redraw_lines(wme, 0, 1);
1.54      nicm      387:
1.119     nicm      388:        /* Write the new lines. */
1.208     nicm      389:        window_copy_redraw_lines(wme, old_cy, backing->cy - old_cy + 1);
1.54      nicm      390:
                    391:        screen_write_stop(&ctx);
                    392: }
                    393:
                    394: void
1.149     nicm      395: window_copy_pageup(struct window_pane *wp, int half_page)
1.1       nicm      396: {
1.211     nicm      397:        window_copy_pageup1(TAILQ_FIRST(&wp->modes), half_page);
1.208     nicm      398: }
                    399:
                    400: static void
                    401: window_copy_pageup1(struct window_mode_entry *wme, int half_page)
                    402: {
                    403:        struct window_copy_mode_data    *data = wme->data;
1.1       nicm      404:        struct screen                   *s = &data->screen;
1.162     nicm      405:        u_int                            n, ox, oy, px, py;
1.147     nicm      406:
                    407:        oy = screen_hsize(data->backing) + data->cy - data->oy;
1.208     nicm      408:        ox = window_copy_find_length(wme, oy);
1.147     nicm      409:
                    410:        if (data->cx != ox) {
                    411:                data->lastcx = data->cx;
                    412:                data->lastsx = ox;
                    413:        }
                    414:        data->cx = data->lastcx;
1.1       nicm      415:
1.19      nicm      416:        n = 1;
1.149     nicm      417:        if (screen_size_y(s) > 2) {
                    418:                if (half_page)
                    419:                        n = screen_size_y(s) / 2;
                    420:                else
                    421:                        n = screen_size_y(s) - 2;
                    422:        }
1.147     nicm      423:
1.195     nicm      424:        if (data->oy + n > screen_hsize(data->backing)) {
1.54      nicm      425:                data->oy = screen_hsize(data->backing);
1.195     nicm      426:                if (data->cy < n)
                    427:                        data->cy = 0;
                    428:                else
                    429:                        data->cy -= n;
                    430:        } else
1.19      nicm      431:                data->oy += n;
1.147     nicm      432:
1.192     nicm      433:        if (data->screen.sel == NULL || !data->rectflag) {
1.162     nicm      434:                py = screen_hsize(data->backing) + data->cy - data->oy;
1.208     nicm      435:                px = window_copy_find_length(wme, py);
1.162     nicm      436:                if ((data->cx >= data->lastsx && data->cx != px) ||
                    437:                    data->cx > px)
1.208     nicm      438:                        window_copy_cursor_end_of_line(wme);
1.147     nicm      439:        }
                    440:
1.208     nicm      441:        window_copy_update_selection(wme, 1);
                    442:        window_copy_redraw_screen(wme);
1.147     nicm      443: }
                    444:
1.166     nicm      445: static int
1.208     nicm      446: window_copy_pagedown(struct window_mode_entry *wme, int half_page,
                    447:     int scroll_exit)
1.147     nicm      448: {
1.208     nicm      449:        struct window_copy_mode_data    *data = wme->data;
1.147     nicm      450:        struct screen                   *s = &data->screen;
1.161     nicm      451:        u_int                            n, ox, oy, px, py;
1.147     nicm      452:
                    453:        oy = screen_hsize(data->backing) + data->cy - data->oy;
1.208     nicm      454:        ox = window_copy_find_length(wme, oy);
1.147     nicm      455:
                    456:        if (data->cx != ox) {
                    457:                data->lastcx = data->cx;
                    458:                data->lastsx = ox;
                    459:        }
                    460:        data->cx = data->lastcx;
                    461:
                    462:        n = 1;
1.149     nicm      463:        if (screen_size_y(s) > 2) {
                    464:                if (half_page)
                    465:                        n = screen_size_y(s) / 2;
                    466:                else
                    467:                        n = screen_size_y(s) - 2;
                    468:        }
1.147     nicm      469:
1.195     nicm      470:        if (data->oy < n) {
1.147     nicm      471:                data->oy = 0;
1.195     nicm      472:                if (data->cy + (n - data->oy) >= screen_size_y(data->backing))
                    473:                        data->cy = screen_size_y(data->backing) - 1;
                    474:                else
                    475:                        data->cy += n - data->oy;
                    476:        } else
1.147     nicm      477:                data->oy -= n;
                    478:
1.192     nicm      479:        if (data->screen.sel == NULL || !data->rectflag) {
1.161     nicm      480:                py = screen_hsize(data->backing) + data->cy - data->oy;
1.208     nicm      481:                px = window_copy_find_length(wme, py);
1.161     nicm      482:                if ((data->cx >= data->lastsx && data->cx != px) ||
                    483:                    data->cx > px)
1.208     nicm      484:                        window_copy_cursor_end_of_line(wme);
1.147     nicm      485:        }
                    486:
1.186     nicm      487:        if (scroll_exit && data->oy == 0)
1.166     nicm      488:                return (1);
1.208     nicm      489:        window_copy_update_selection(wme, 1);
                    490:        window_copy_redraw_screen(wme);
1.166     nicm      491:        return (0);
1.1       nicm      492: }
                    493:
1.157     nicm      494: static void
1.208     nicm      495: window_copy_previous_paragraph(struct window_mode_entry *wme)
1.148     nicm      496: {
1.208     nicm      497:        struct window_copy_mode_data    *data = wme->data;
1.151     nicm      498:        u_int                            oy;
1.148     nicm      499:
                    500:        oy = screen_hsize(data->backing) + data->cy - data->oy;
                    501:
1.208     nicm      502:        while (oy > 0 && window_copy_find_length(wme, oy) == 0)
1.148     nicm      503:                oy--;
                    504:
1.208     nicm      505:        while (oy > 0 && window_copy_find_length(wme, oy) > 0)
1.148     nicm      506:                oy--;
                    507:
1.208     nicm      508:        window_copy_scroll_to(wme, 0, oy);
1.148     nicm      509: }
                    510:
1.157     nicm      511: static void
1.208     nicm      512: window_copy_next_paragraph(struct window_mode_entry *wme)
1.148     nicm      513: {
1.208     nicm      514:        struct window_copy_mode_data    *data = wme->data;
1.148     nicm      515:        struct screen                   *s = &data->screen;
                    516:        u_int                            maxy, ox, oy;
                    517:
                    518:        oy = screen_hsize(data->backing) + data->cy - data->oy;
                    519:        maxy = screen_hsize(data->backing) + screen_size_y(s) - 1;
                    520:
1.208     nicm      521:        while (oy < maxy && window_copy_find_length(wme, oy) == 0)
1.148     nicm      522:                oy++;
                    523:
1.208     nicm      524:        while (oy < maxy && window_copy_find_length(wme, oy) > 0)
1.148     nicm      525:                oy++;
                    526:
1.208     nicm      527:        ox = window_copy_find_length(wme, oy);
                    528:        window_copy_scroll_to(wme, ox, oy);
1.148     nicm      529: }
                    530:
1.157     nicm      531: static void
1.208     nicm      532: window_copy_formats(struct window_mode_entry *wme, struct format_tree *ft)
1.206     nicm      533: {
1.208     nicm      534:        struct window_copy_mode_data    *data = wme->data;
1.206     nicm      535:
                    536:        format_add(ft, "selection_present", "%d", data->screen.sel != NULL);
                    537:        format_add(ft, "scroll_position", "%d", data->oy);
                    538:        format_add(ft, "rectangle_toggle", "%d", data->rectflag);
                    539: }
                    540:
                    541: static void
1.208     nicm      542: window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
1.1       nicm      543: {
1.208     nicm      544:        struct window_pane              *wp = wme->wp;
                    545:        struct window_copy_mode_data    *data = wme->data;
1.1       nicm      546:        struct screen                   *s = &data->screen;
                    547:        struct screen_write_ctx          ctx;
                    548:
1.119     nicm      549:        screen_resize(s, sx, sy, 1);
1.54      nicm      550:        if (data->backing != &wp->base)
1.119     nicm      551:                screen_resize(data->backing, sx, sy, 1);
1.35      nicm      552:
1.18      nicm      553:        if (data->cy > sy - 1)
                    554:                data->cy = sy - 1;
                    555:        if (data->cx > sx)
                    556:                data->cx = sx;
1.63      nicm      557:        if (data->oy > screen_hsize(data->backing))
                    558:                data->oy = screen_hsize(data->backing);
1.18      nicm      559:
1.208     nicm      560:        window_copy_clear_selection(wme);
1.18      nicm      561:
1.1       nicm      562:        screen_write_start(&ctx, NULL, s);
1.208     nicm      563:        window_copy_write_lines(wme, &ctx, 0, screen_size_y(s) - 1);
1.1       nicm      564:        screen_write_stop(&ctx);
1.18      nicm      565:
1.162     nicm      566:        if (data->searchmark != NULL)
1.208     nicm      567:                window_copy_search_marks(wme, NULL);
1.163     nicm      568:        data->searchx = data->cx;
                    569:        data->searchy = data->cy;
                    570:        data->searcho = data->oy;
1.162     nicm      571:
1.208     nicm      572:        window_copy_redraw_screen(wme);
1.1       nicm      573: }
                    574:
1.157     nicm      575: static const char *
1.208     nicm      576: window_copy_key_table(struct window_mode_entry *wme)
1.155     nicm      577: {
1.208     nicm      578:        struct window_pane      *wp = wme->wp;
                    579:
1.155     nicm      580:        if (options_get_number(wp->window->options, "mode-keys") == MODEKEY_VI)
                    581:                return ("copy-mode-vi");
                    582:        return ("copy-mode");
                    583: }
                    584:
1.213     nicm      585: static enum window_copy_cmd_action
                    586: window_copy_cmd_append_selection(struct window_copy_cmd_state *cs)
                    587: {
                    588:        struct window_mode_entry        *wme = cs->wme;
                    589:        struct session                  *s = cs->s;
                    590:
                    591:        if (s != NULL)
                    592:                window_copy_append_selection(wme);
                    593:        window_copy_clear_selection(wme);
                    594:        return (WINDOW_COPY_CMD_REDRAW);
                    595: }
                    596:
                    597: static enum window_copy_cmd_action
                    598: window_copy_cmd_append_selection_and_cancel(struct window_copy_cmd_state *cs)
                    599: {
                    600:        struct window_mode_entry        *wme = cs->wme;
                    601:        struct session                  *s = cs->s;
                    602:
                    603:        if (s != NULL)
                    604:                window_copy_append_selection(wme);
                    605:        window_copy_clear_selection(wme);
                    606:        return (WINDOW_COPY_CMD_CANCEL);
                    607: }
                    608:
                    609: static enum window_copy_cmd_action
                    610: window_copy_cmd_back_to_indentation(struct window_copy_cmd_state *cs)
                    611: {
                    612:        struct window_mode_entry        *wme = cs->wme;
                    613:
                    614:        window_copy_cursor_back_to_indentation(wme);
                    615:        return (WINDOW_COPY_CMD_NOTHING);
                    616: }
                    617:
                    618: static enum window_copy_cmd_action
                    619: window_copy_cmd_begin_selection(struct window_copy_cmd_state *cs)
                    620: {
                    621:        struct window_mode_entry        *wme = cs->wme;
                    622:        struct client                   *c = cs->c;
                    623:        struct mouse_event              *m = cs->m;
                    624:        struct window_copy_mode_data    *data = wme->data;
                    625:
                    626:        if (m != NULL) {
                    627:                window_copy_start_drag(c, m);
                    628:                return (WINDOW_COPY_CMD_NOTHING);
                    629:        }
                    630:
                    631:        data->lineflag = LINE_SEL_NONE;
                    632:        window_copy_start_selection(wme);
                    633:        return (WINDOW_COPY_CMD_REDRAW);
                    634: }
                    635:
                    636: static enum window_copy_cmd_action
                    637: window_copy_cmd_stop_selection(struct window_copy_cmd_state *cs)
                    638: {
                    639:        struct window_mode_entry        *wme = cs->wme;
                    640:        struct window_copy_mode_data    *data = wme->data;
                    641:
                    642:        data->cursordrag = CURSORDRAG_NONE;
1.214     nicm      643:        data->lineflag = LINE_SEL_NONE;
1.213     nicm      644:        return (WINDOW_COPY_CMD_NOTHING);
                    645: }
                    646:
                    647: static enum window_copy_cmd_action
                    648: window_copy_cmd_bottom_line(struct window_copy_cmd_state *cs)
                    649: {
                    650:        struct window_mode_entry        *wme = cs->wme;
                    651:        struct window_copy_mode_data    *data = wme->data;
                    652:
                    653:        data->cx = 0;
                    654:        data->cy = screen_size_y(&data->screen) - 1;
                    655:
                    656:        window_copy_update_selection(wme, 1);
                    657:        return (WINDOW_COPY_CMD_REDRAW);
                    658: }
                    659:
                    660: static enum window_copy_cmd_action
                    661: window_copy_cmd_cancel(__unused struct window_copy_cmd_state *cs)
                    662: {
                    663:        return (WINDOW_COPY_CMD_CANCEL);
                    664: }
                    665:
                    666: static enum window_copy_cmd_action
                    667: window_copy_cmd_clear_selection(struct window_copy_cmd_state *cs)
                    668: {
                    669:        struct window_mode_entry        *wme = cs->wme;
                    670:
                    671:        window_copy_clear_selection(wme);
                    672:        return (WINDOW_COPY_CMD_REDRAW);
                    673: }
                    674:
                    675: static enum window_copy_cmd_action
                    676: window_copy_cmd_copy_end_of_line(struct window_copy_cmd_state *cs)
                    677: {
                    678:        struct window_mode_entry        *wme = cs->wme;
1.215   ! nicm      679:        struct client                   *c = cs->c;
1.213     nicm      680:        struct session                  *s = cs->s;
1.215   ! nicm      681:        struct winlink                  *wl = cs->wl;
        !           682:        struct window_pane              *wp = wme->wp;
1.213     nicm      683:        u_int                            np = wme->prefix;
1.215   ! nicm      684:        char                            *prefix = NULL;
        !           685:
        !           686:        if (cs->args->argc == 2)
        !           687:                prefix = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
1.213     nicm      688:
                    689:        window_copy_start_selection(wme);
                    690:        for (; np > 1; np--)
                    691:                window_copy_cursor_down(wme, 0);
                    692:        window_copy_cursor_end_of_line(wme);
                    693:
                    694:        if (s != NULL) {
1.215   ! nicm      695:                window_copy_copy_selection(wme, prefix);
        !           696:
        !           697:                free(prefix);
1.213     nicm      698:                return (WINDOW_COPY_CMD_CANCEL);
                    699:        }
1.215   ! nicm      700:
        !           701:        free(prefix);
1.213     nicm      702:        return (WINDOW_COPY_CMD_REDRAW);
                    703: }
                    704:
                    705: static enum window_copy_cmd_action
                    706: window_copy_cmd_copy_line(struct window_copy_cmd_state *cs)
                    707: {
                    708:        struct window_mode_entry        *wme = cs->wme;
1.215   ! nicm      709:        struct client                   *c = cs->c;
1.213     nicm      710:        struct session                  *s = cs->s;
1.215   ! nicm      711:        struct winlink                  *wl = cs->wl;
        !           712:        struct window_pane              *wp = wme->wp;
1.213     nicm      713:        u_int                            np = wme->prefix;
1.215   ! nicm      714:        char                            *prefix = NULL;
        !           715:
        !           716:        if (cs->args->argc == 2)
        !           717:                prefix = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
1.213     nicm      718:
                    719:        window_copy_cursor_start_of_line(wme);
                    720:        window_copy_start_selection(wme);
                    721:        for (; np > 1; np--)
                    722:                window_copy_cursor_down(wme, 0);
                    723:        window_copy_cursor_end_of_line(wme);
                    724:
                    725:        if (s != NULL) {
1.215   ! nicm      726:                window_copy_copy_selection(wme, prefix);
        !           727:
        !           728:                free(prefix);
1.213     nicm      729:                return (WINDOW_COPY_CMD_CANCEL);
                    730:        }
1.215   ! nicm      731:
        !           732:        free(prefix);
1.213     nicm      733:        return (WINDOW_COPY_CMD_REDRAW);
                    734: }
                    735:
                    736: static enum window_copy_cmd_action
                    737: window_copy_cmd_copy_selection(struct window_copy_cmd_state *cs)
                    738: {
                    739:        struct window_mode_entry        *wme = cs->wme;
1.215   ! nicm      740:        struct client                   *c = cs->c;
1.213     nicm      741:        struct session                  *s = cs->s;
1.215   ! nicm      742:        struct winlink                  *wl = cs->wl;
        !           743:        struct window_pane              *wp = wme->wp;
        !           744:        char                            *prefix = NULL;
        !           745:
        !           746:        if (cs->args->argc == 2)
        !           747:                prefix = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
1.213     nicm      748:
                    749:        if (s != NULL)
1.215   ! nicm      750:                window_copy_copy_selection(wme, prefix);
1.213     nicm      751:        window_copy_clear_selection(wme);
1.215   ! nicm      752:
        !           753:        free(prefix);
1.213     nicm      754:        return (WINDOW_COPY_CMD_REDRAW);
                    755: }
                    756:
                    757: static enum window_copy_cmd_action
                    758: window_copy_cmd_copy_selection_and_cancel(struct window_copy_cmd_state *cs)
                    759: {
                    760:        struct window_mode_entry        *wme = cs->wme;
1.215   ! nicm      761:        struct client                   *c = cs->c;
1.213     nicm      762:        struct session                  *s = cs->s;
1.215   ! nicm      763:        struct winlink                  *wl = cs->wl;
        !           764:        struct window_pane              *wp = wme->wp;
        !           765:        char                            *prefix = NULL;
        !           766:
        !           767:        if (cs->args->argc == 2)
        !           768:                prefix = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
1.213     nicm      769:
                    770:        if (s != NULL)
1.215   ! nicm      771:                window_copy_copy_selection(wme, prefix);
1.213     nicm      772:        window_copy_clear_selection(wme);
1.215   ! nicm      773:
        !           774:        free(prefix);
1.213     nicm      775:        return (WINDOW_COPY_CMD_CANCEL);
                    776: }
                    777:
                    778: static enum window_copy_cmd_action
                    779: window_copy_cmd_cursor_down(struct window_copy_cmd_state *cs)
                    780: {
                    781:        struct window_mode_entry        *wme = cs->wme;
                    782:        u_int                            np = wme->prefix;
                    783:
                    784:        for (; np != 0; np--)
                    785:                window_copy_cursor_down(wme, 0);
                    786:        return (WINDOW_COPY_CMD_NOTHING);
                    787: }
                    788:
                    789: static enum window_copy_cmd_action
                    790: window_copy_cmd_cursor_left(struct window_copy_cmd_state *cs)
                    791: {
                    792:        struct window_mode_entry        *wme = cs->wme;
                    793:        u_int                            np = wme->prefix;
                    794:
                    795:        for (; np != 0; np--)
                    796:                window_copy_cursor_left(wme);
                    797:        return (WINDOW_COPY_CMD_NOTHING);
                    798: }
                    799:
                    800: static enum window_copy_cmd_action
                    801: window_copy_cmd_cursor_right(struct window_copy_cmd_state *cs)
                    802: {
                    803:        struct window_mode_entry        *wme = cs->wme;
                    804:        u_int                            np = wme->prefix;
                    805:
                    806:        for (; np != 0; np--)
                    807:                window_copy_cursor_right(wme);
                    808:        return (WINDOW_COPY_CMD_NOTHING);
                    809: }
                    810:
                    811: static enum window_copy_cmd_action
                    812: window_copy_cmd_cursor_up(struct window_copy_cmd_state *cs)
                    813: {
                    814:        struct window_mode_entry        *wme = cs->wme;
                    815:        u_int                            np = wme->prefix;
                    816:
                    817:        for (; np != 0; np--)
                    818:                window_copy_cursor_up(wme, 0);
                    819:        return (WINDOW_COPY_CMD_NOTHING);
                    820: }
                    821:
                    822: static enum window_copy_cmd_action
                    823: window_copy_cmd_end_of_line(struct window_copy_cmd_state *cs)
                    824: {
                    825:        struct window_mode_entry        *wme = cs->wme;
                    826:
                    827:        window_copy_cursor_end_of_line(wme);
                    828:        return (WINDOW_COPY_CMD_NOTHING);
                    829: }
                    830:
                    831: static enum window_copy_cmd_action
                    832: window_copy_cmd_halfpage_down(struct window_copy_cmd_state *cs)
                    833: {
                    834:        struct window_mode_entry        *wme = cs->wme;
                    835:        struct window_copy_mode_data    *data = wme->data;
                    836:        u_int                            np = wme->prefix;
                    837:
                    838:        for (; np != 0; np--) {
                    839:                if (window_copy_pagedown(wme, 1, data->scroll_exit))
                    840:                        return (WINDOW_COPY_CMD_CANCEL);
                    841:        }
                    842:        return (WINDOW_COPY_CMD_NOTHING);
                    843: }
                    844:
                    845: static enum window_copy_cmd_action
                    846: window_copy_cmd_halfpage_down_and_cancel(struct window_copy_cmd_state *cs)
                    847: {
                    848:
                    849:        struct window_mode_entry        *wme = cs->wme;
                    850:        u_int                            np = wme->prefix;
                    851:
                    852:        for (; np != 0; np--) {
                    853:                if (window_copy_pagedown(wme, 1, 1))
                    854:                        return (WINDOW_COPY_CMD_CANCEL);
                    855:        }
                    856:        return (WINDOW_COPY_CMD_NOTHING);
                    857: }
                    858:
                    859: static enum window_copy_cmd_action
                    860: window_copy_cmd_halfpage_up(struct window_copy_cmd_state *cs)
                    861: {
                    862:        struct window_mode_entry        *wme = cs->wme;
                    863:        u_int                            np = wme->prefix;
                    864:
                    865:        for (; np != 0; np--)
                    866:                window_copy_pageup1(wme, 1);
                    867:        return (WINDOW_COPY_CMD_NOTHING);
                    868: }
                    869:
                    870: static enum window_copy_cmd_action
                    871: window_copy_cmd_history_bottom(struct window_copy_cmd_state *cs)
                    872: {
                    873:        struct window_mode_entry        *wme = cs->wme;
                    874:        struct window_copy_mode_data    *data = wme->data;
                    875:
                    876:        data->cx = 0;
                    877:        data->cy = screen_size_y(&data->screen) - 1;
                    878:        data->oy = 0;
                    879:
                    880:        window_copy_update_selection(wme, 1);
                    881:        return (WINDOW_COPY_CMD_REDRAW);
                    882: }
                    883:
                    884: static enum window_copy_cmd_action
                    885: window_copy_cmd_history_top(struct window_copy_cmd_state *cs)
                    886: {
                    887:        struct window_mode_entry        *wme = cs->wme;
                    888:        struct window_copy_mode_data    *data = wme->data;
                    889:
                    890:        data->cx = 0;
                    891:        data->cy = 0;
                    892:        data->oy = screen_hsize(data->backing);
                    893:
                    894:        window_copy_update_selection(wme, 1);
                    895:        return (WINDOW_COPY_CMD_REDRAW);
                    896: }
                    897:
                    898: static enum window_copy_cmd_action
                    899: window_copy_cmd_jump_again(struct window_copy_cmd_state *cs)
                    900: {
                    901:        struct window_mode_entry        *wme = cs->wme;
                    902:        struct window_copy_mode_data    *data = wme->data;
                    903:        u_int                            np = wme->prefix;
                    904:
                    905:        switch (data->jumptype) {
                    906:        case WINDOW_COPY_JUMPFORWARD:
                    907:                for (; np != 0; np--)
                    908:                        window_copy_cursor_jump(wme);
                    909:                break;
                    910:        case WINDOW_COPY_JUMPBACKWARD:
                    911:                for (; np != 0; np--)
                    912:                        window_copy_cursor_jump_back(wme);
                    913:                break;
                    914:        case WINDOW_COPY_JUMPTOFORWARD:
                    915:                for (; np != 0; np--)
                    916:                        window_copy_cursor_jump_to(wme);
                    917:                break;
                    918:        case WINDOW_COPY_JUMPTOBACKWARD:
                    919:                for (; np != 0; np--)
                    920:                        window_copy_cursor_jump_to_back(wme);
                    921:                break;
                    922:        }
                    923:        return (WINDOW_COPY_CMD_NOTHING);
                    924: }
                    925:
                    926: static enum window_copy_cmd_action
                    927: window_copy_cmd_jump_reverse(struct window_copy_cmd_state *cs)
                    928: {
                    929:        struct window_mode_entry        *wme = cs->wme;
                    930:        struct window_copy_mode_data    *data = wme->data;
                    931:        u_int                            np = wme->prefix;
                    932:
                    933:        switch (data->jumptype) {
                    934:        case WINDOW_COPY_JUMPFORWARD:
                    935:                for (; np != 0; np--)
                    936:                        window_copy_cursor_jump_back(wme);
                    937:                break;
                    938:        case WINDOW_COPY_JUMPBACKWARD:
                    939:                for (; np != 0; np--)
                    940:                        window_copy_cursor_jump(wme);
                    941:                break;
                    942:        case WINDOW_COPY_JUMPTOFORWARD:
                    943:                for (; np != 0; np--)
                    944:                        window_copy_cursor_jump_to_back(wme);
                    945:                break;
                    946:        case WINDOW_COPY_JUMPTOBACKWARD:
                    947:                for (; np != 0; np--)
                    948:                        window_copy_cursor_jump_to(wme);
                    949:                break;
                    950:        }
                    951:        return (WINDOW_COPY_CMD_NOTHING);
                    952: }
                    953:
                    954: static enum window_copy_cmd_action
                    955: window_copy_cmd_middle_line(struct window_copy_cmd_state *cs)
                    956: {
                    957:        struct window_mode_entry        *wme = cs->wme;
                    958:        struct window_copy_mode_data    *data = wme->data;
                    959:
                    960:        data->cx = 0;
                    961:        data->cy = (screen_size_y(&data->screen) - 1) / 2;
                    962:
                    963:        window_copy_update_selection(wme, 1);
                    964:        return (WINDOW_COPY_CMD_REDRAW);
                    965: }
                    966:
                    967: static enum window_copy_cmd_action
                    968: window_copy_cmd_next_paragraph(struct window_copy_cmd_state *cs)
                    969: {
                    970:        struct window_mode_entry        *wme = cs->wme;
                    971:        u_int                            np = wme->prefix;
                    972:
                    973:        for (; np != 0; np--)
                    974:                window_copy_next_paragraph(wme);
                    975:        return (WINDOW_COPY_CMD_NOTHING);
                    976: }
                    977:
                    978: static enum window_copy_cmd_action
                    979: window_copy_cmd_next_space(struct window_copy_cmd_state *cs)
                    980: {
                    981:        struct window_mode_entry        *wme = cs->wme;
                    982:        u_int                            np = wme->prefix;
                    983:
                    984:        for (; np != 0; np--)
                    985:                window_copy_cursor_next_word(wme, " ");
                    986:        return (WINDOW_COPY_CMD_NOTHING);
                    987: }
                    988:
                    989: static enum window_copy_cmd_action
                    990: window_copy_cmd_next_space_end(struct window_copy_cmd_state *cs)
                    991: {
                    992:        struct window_mode_entry        *wme = cs->wme;
                    993:        u_int                            np = wme->prefix;
                    994:
                    995:        for (; np != 0; np--)
                    996:                window_copy_cursor_next_word_end(wme, " ");
                    997:        return (WINDOW_COPY_CMD_NOTHING);
                    998: }
                    999:
                   1000: static enum window_copy_cmd_action
                   1001: window_copy_cmd_next_word(struct window_copy_cmd_state *cs)
                   1002: {
                   1003:        struct window_mode_entry        *wme = cs->wme;
                   1004:        struct session                  *s = cs->s;
                   1005:        u_int                            np = wme->prefix;
                   1006:        const char                      *ws;
                   1007:
                   1008:        ws = options_get_string(s->options, "word-separators");
                   1009:        for (; np != 0; np--)
                   1010:                window_copy_cursor_next_word(wme, ws);
                   1011:        return (WINDOW_COPY_CMD_NOTHING);
                   1012: }
                   1013:
                   1014: static enum window_copy_cmd_action
                   1015: window_copy_cmd_next_word_end(struct window_copy_cmd_state *cs)
                   1016: {
                   1017:        struct window_mode_entry        *wme = cs->wme;
                   1018:        struct session                  *s = cs->s;
                   1019:        u_int                            np = wme->prefix;
                   1020:        const char                      *ws;
                   1021:
                   1022:        ws = options_get_string(s->options, "word-separators");
                   1023:        for (; np != 0; np--)
                   1024:                window_copy_cursor_next_word_end(wme, ws);
                   1025:        return (WINDOW_COPY_CMD_NOTHING);
                   1026: }
                   1027:
                   1028: static enum window_copy_cmd_action
                   1029: window_copy_cmd_other_end(struct window_copy_cmd_state *cs)
                   1030: {
                   1031:        struct window_mode_entry        *wme = cs->wme;
                   1032:        u_int                            np = wme->prefix;
                   1033:
                   1034:        if ((np % 2) != 0)
                   1035:                window_copy_other_end(wme);
                   1036:        return (WINDOW_COPY_CMD_NOTHING);
                   1037: }
                   1038:
                   1039: static enum window_copy_cmd_action
                   1040: window_copy_cmd_page_down(struct window_copy_cmd_state *cs)
                   1041: {
                   1042:        struct window_mode_entry        *wme = cs->wme;
                   1043:        struct window_copy_mode_data    *data = wme->data;
                   1044:        u_int                            np = wme->prefix;
                   1045:
                   1046:        for (; np != 0; np--) {
                   1047:                if (window_copy_pagedown(wme, 0, data->scroll_exit))
                   1048:                        return (WINDOW_COPY_CMD_CANCEL);
                   1049:        }
                   1050:        return (WINDOW_COPY_CMD_NOTHING);
                   1051: }
                   1052:
                   1053: static enum window_copy_cmd_action
                   1054: window_copy_cmd_page_down_and_cancel(struct window_copy_cmd_state *cs)
                   1055: {
                   1056:        struct window_mode_entry        *wme = cs->wme;
                   1057:        u_int                            np = wme->prefix;
                   1058:
                   1059:        for (; np != 0; np--) {
                   1060:                if (window_copy_pagedown(wme, 0, 1))
                   1061:                        return (WINDOW_COPY_CMD_CANCEL);
                   1062:        }
                   1063:        return (WINDOW_COPY_CMD_NOTHING);
                   1064: }
                   1065:
                   1066: static enum window_copy_cmd_action
                   1067: window_copy_cmd_page_up(struct window_copy_cmd_state *cs)
                   1068: {
                   1069:        struct window_mode_entry        *wme = cs->wme;
                   1070:        u_int                            np = wme->prefix;
                   1071:
                   1072:        for (; np != 0; np--)
                   1073:                window_copy_pageup1(wme, 0);
                   1074:        return (WINDOW_COPY_CMD_NOTHING);
                   1075: }
                   1076:
                   1077: static enum window_copy_cmd_action
                   1078: window_copy_cmd_previous_paragraph(struct window_copy_cmd_state *cs)
                   1079: {
                   1080:        struct window_mode_entry        *wme = cs->wme;
                   1081:        u_int                            np = wme->prefix;
                   1082:
                   1083:        for (; np != 0; np--)
                   1084:                window_copy_previous_paragraph(wme);
                   1085:        return (WINDOW_COPY_CMD_NOTHING);
                   1086: }
                   1087:
                   1088: static enum window_copy_cmd_action
                   1089: window_copy_cmd_previous_space(struct window_copy_cmd_state *cs)
                   1090: {
                   1091:        struct window_mode_entry        *wme = cs->wme;
                   1092:        u_int                            np = wme->prefix;
                   1093:
                   1094:        for (; np != 0; np--)
                   1095:                window_copy_cursor_previous_word(wme, " ");
                   1096:        return (WINDOW_COPY_CMD_NOTHING);
                   1097: }
                   1098:
                   1099: static enum window_copy_cmd_action
                   1100: window_copy_cmd_previous_word(struct window_copy_cmd_state *cs)
                   1101: {
                   1102:        struct window_mode_entry        *wme = cs->wme;
                   1103:        struct session                  *s = cs->s;
                   1104:        u_int                            np = wme->prefix;
                   1105:        const char                      *ws;
                   1106:
                   1107:        ws = options_get_string(s->options, "word-separators");
                   1108:        for (; np != 0; np--)
                   1109:                window_copy_cursor_previous_word(wme, ws);
                   1110:        return (WINDOW_COPY_CMD_NOTHING);
                   1111: }
                   1112:
                   1113: static enum window_copy_cmd_action
                   1114: window_copy_cmd_rectangle_toggle(struct window_copy_cmd_state *cs)
                   1115: {
                   1116:        struct window_mode_entry        *wme = cs->wme;
                   1117:        struct window_copy_mode_data    *data = wme->data;
                   1118:
                   1119:        data->lineflag = LINE_SEL_NONE;
                   1120:        window_copy_rectangle_toggle(wme);
                   1121:
                   1122:        return (WINDOW_COPY_CMD_NOTHING);
                   1123: }
                   1124:
                   1125: static enum window_copy_cmd_action
                   1126: window_copy_cmd_scroll_down(struct window_copy_cmd_state *cs)
                   1127: {
                   1128:        struct window_mode_entry        *wme = cs->wme;
                   1129:        struct window_copy_mode_data    *data = wme->data;
                   1130:        u_int                            np = wme->prefix;
                   1131:
                   1132:        for (; np != 0; np--)
                   1133:                window_copy_cursor_down(wme, 1);
                   1134:        if (data->scroll_exit && data->oy == 0)
                   1135:                return (WINDOW_COPY_CMD_CANCEL);
                   1136:        return (WINDOW_COPY_CMD_NOTHING);
                   1137: }
                   1138:
                   1139: static enum window_copy_cmd_action
                   1140: window_copy_cmd_scroll_down_and_cancel(struct window_copy_cmd_state *cs)
                   1141: {
                   1142:        struct window_mode_entry        *wme = cs->wme;
                   1143:        struct window_copy_mode_data    *data = wme->data;
                   1144:        u_int                            np = wme->prefix;
                   1145:
                   1146:        for (; np != 0; np--)
                   1147:                window_copy_cursor_down(wme, 1);
                   1148:        if (data->oy == 0)
                   1149:                return (WINDOW_COPY_CMD_CANCEL);
                   1150:        return (WINDOW_COPY_CMD_NOTHING);
                   1151: }
                   1152:
                   1153: static enum window_copy_cmd_action
                   1154: window_copy_cmd_scroll_up(struct window_copy_cmd_state *cs)
                   1155: {
                   1156:        struct window_mode_entry        *wme = cs->wme;
                   1157:        u_int                            np = wme->prefix;
                   1158:
                   1159:        for (; np != 0; np--)
                   1160:                window_copy_cursor_up(wme, 1);
                   1161:        return (WINDOW_COPY_CMD_NOTHING);
                   1162: }
                   1163:
                   1164: static enum window_copy_cmd_action
                   1165: window_copy_cmd_search_again(struct window_copy_cmd_state *cs)
                   1166: {
                   1167:        struct window_mode_entry        *wme = cs->wme;
                   1168:        struct window_copy_mode_data    *data = wme->data;
                   1169:        u_int                            np = wme->prefix;
                   1170:
                   1171:        if (data->searchtype == WINDOW_COPY_SEARCHUP) {
                   1172:                for (; np != 0; np--)
                   1173:                        window_copy_search_up(wme);
                   1174:        } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
                   1175:                for (; np != 0; np--)
                   1176:                        window_copy_search_down(wme);
                   1177:        }
                   1178:        return (WINDOW_COPY_CMD_NOTHING);
                   1179: }
                   1180:
                   1181: static enum window_copy_cmd_action
                   1182: window_copy_cmd_search_reverse(struct window_copy_cmd_state *cs)
                   1183: {
                   1184:        struct window_mode_entry        *wme = cs->wme;
                   1185:        struct window_copy_mode_data    *data = wme->data;
                   1186:        u_int                            np = wme->prefix;
                   1187:
                   1188:        if (data->searchtype == WINDOW_COPY_SEARCHUP) {
                   1189:                for (; np != 0; np--)
                   1190:                        window_copy_search_down(wme);
                   1191:        } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
                   1192:                for (; np != 0; np--)
                   1193:                        window_copy_search_up(wme);
                   1194:        }
                   1195:        return (WINDOW_COPY_CMD_NOTHING);
                   1196: }
                   1197:
                   1198: static enum window_copy_cmd_action
                   1199: window_copy_cmd_select_line(struct window_copy_cmd_state *cs)
                   1200: {
                   1201:        struct window_mode_entry        *wme = cs->wme;
                   1202:        struct window_copy_mode_data    *data = wme->data;
                   1203:        u_int                            np = wme->prefix;
                   1204:
                   1205:        data->lineflag = LINE_SEL_LEFT_RIGHT;
                   1206:        data->rectflag = 0;
                   1207:
                   1208:        window_copy_cursor_start_of_line(wme);
                   1209:        window_copy_start_selection(wme);
                   1210:        for (; np > 1; np--)
                   1211:                window_copy_cursor_down(wme, 0);
                   1212:        window_copy_cursor_end_of_line(wme);
                   1213:
                   1214:        return (WINDOW_COPY_CMD_REDRAW);
                   1215: }
                   1216:
                   1217: static enum window_copy_cmd_action
                   1218: window_copy_cmd_select_word(struct window_copy_cmd_state *cs)
                   1219: {
                   1220:        struct window_mode_entry        *wme = cs->wme;
                   1221:        struct session                  *s = cs->s;
                   1222:        struct window_copy_mode_data    *data = wme->data;
                   1223:        const char                      *ws;
                   1224:
                   1225:        data->lineflag = LINE_SEL_LEFT_RIGHT;
                   1226:        data->rectflag = 0;
                   1227:
                   1228:        ws = options_get_string(s->options, "word-separators");
                   1229:        window_copy_cursor_previous_word(wme, ws);
                   1230:        window_copy_start_selection(wme);
                   1231:        window_copy_cursor_next_word_end(wme, ws);
                   1232:
                   1233:        return (WINDOW_COPY_CMD_REDRAW);
                   1234: }
                   1235:
                   1236: static enum window_copy_cmd_action
                   1237: window_copy_cmd_start_of_line(struct window_copy_cmd_state *cs)
                   1238: {
                   1239:        struct window_mode_entry        *wme = cs->wme;
                   1240:
                   1241:        window_copy_cursor_start_of_line(wme);
                   1242:        return (WINDOW_COPY_CMD_NOTHING);
                   1243: }
                   1244:
                   1245: static enum window_copy_cmd_action
                   1246: window_copy_cmd_top_line(struct window_copy_cmd_state *cs)
                   1247: {
                   1248:        struct window_mode_entry        *wme = cs->wme;
                   1249:        struct window_copy_mode_data    *data = wme->data;
                   1250:
                   1251:        data->cx = 0;
                   1252:        data->cy = 0;
                   1253:
                   1254:        window_copy_update_selection(wme, 1);
                   1255:        return (WINDOW_COPY_CMD_REDRAW);
                   1256: }
                   1257:
                   1258: static enum window_copy_cmd_action
                   1259: window_copy_cmd_copy_pipe(struct window_copy_cmd_state *cs)
                   1260: {
                   1261:        struct window_mode_entry        *wme = cs->wme;
1.215   ! nicm     1262:        struct client                   *c = cs->c;
1.213     nicm     1263:        struct session                  *s = cs->s;
1.215   ! nicm     1264:        struct winlink                  *wl = cs->wl;
        !          1265:        struct window_pane              *wp = wme->wp;
        !          1266:        char                            *command = NULL;
        !          1267:        char                            *prefix = NULL;
        !          1268:
        !          1269:        if (cs->args->argc == 3)
        !          1270:                prefix = format_single(NULL, cs->args->argv[2], c, s, wl, wp);
        !          1271:
        !          1272:        if (s != NULL && *cs->args->argv[1] != '\0') {
        !          1273:                command = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
        !          1274:                window_copy_copy_pipe(wme, s, prefix, command);
        !          1275:                free(command);
        !          1276:        }
1.213     nicm     1277:
1.215   ! nicm     1278:        free(prefix);
1.213     nicm     1279:        return (WINDOW_COPY_CMD_NOTHING);
                   1280: }
                   1281:
                   1282: static enum window_copy_cmd_action
                   1283: window_copy_cmd_copy_pipe_and_cancel(struct window_copy_cmd_state *cs)
                   1284: {
                   1285:        struct window_mode_entry        *wme = cs->wme;
1.215   ! nicm     1286:        struct client                   *c = cs->c;
1.213     nicm     1287:        struct session                  *s = cs->s;
1.215   ! nicm     1288:        struct winlink                  *wl = cs->wl;
        !          1289:        struct window_pane              *wp = wme->wp;
        !          1290:        char                            *command = NULL;
        !          1291:        char                            *prefix = NULL;
        !          1292:
        !          1293:        if (cs->args->argc == 3)
        !          1294:                prefix = format_single(NULL, cs->args->argv[2], c, s, wl, wp);
        !          1295:
        !          1296:        if (s != NULL && *cs->args->argv[1] != '\0') {
        !          1297:                command = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
        !          1298:                window_copy_copy_pipe(wme, s, prefix, command);
        !          1299:                free(command);
1.213     nicm     1300:
1.215   ! nicm     1301:                free(prefix);
1.213     nicm     1302:                return (WINDOW_COPY_CMD_CANCEL);
                   1303:        }
1.215   ! nicm     1304:
        !          1305:        free(prefix);
1.213     nicm     1306:        return (WINDOW_COPY_CMD_NOTHING);
                   1307: }
                   1308:
                   1309: static enum window_copy_cmd_action
                   1310: window_copy_cmd_goto_line(struct window_copy_cmd_state *cs)
                   1311: {
                   1312:        struct window_mode_entry        *wme = cs->wme;
                   1313:        const char                      *argument = cs->args->argv[1];
                   1314:
                   1315:        if (*argument != '\0')
                   1316:                window_copy_goto_line(wme, argument);
                   1317:        return (WINDOW_COPY_CMD_NOTHING);
                   1318: }
                   1319:
                   1320: static enum window_copy_cmd_action
                   1321: window_copy_cmd_jump_backward(struct window_copy_cmd_state *cs)
                   1322: {
                   1323:        struct window_mode_entry        *wme = cs->wme;
                   1324:        struct window_copy_mode_data    *data = wme->data;
                   1325:        u_int                            np = wme->prefix;
                   1326:        const char                      *argument = cs->args->argv[1];
                   1327:
                   1328:        if (*argument != '\0') {
                   1329:                data->jumptype = WINDOW_COPY_JUMPBACKWARD;
                   1330:                data->jumpchar = *argument;
                   1331:                for (; np != 0; np--)
                   1332:                        window_copy_cursor_jump_back(wme);
                   1333:        }
                   1334:        return (WINDOW_COPY_CMD_NOTHING);
                   1335: }
                   1336:
                   1337: static enum window_copy_cmd_action
                   1338: window_copy_cmd_jump_forward(struct window_copy_cmd_state *cs)
                   1339: {
                   1340:        struct window_mode_entry        *wme = cs->wme;
                   1341:        struct window_copy_mode_data    *data = wme->data;
                   1342:        u_int                            np = wme->prefix;
                   1343:        const char                      *argument = cs->args->argv[1];
                   1344:
                   1345:        if (*argument != '\0') {
                   1346:                data->jumptype = WINDOW_COPY_JUMPFORWARD;
                   1347:                data->jumpchar = *argument;
                   1348:                for (; np != 0; np--)
1.215   ! nicm     1349:                        window_copy_cursor_jump(wme);
1.213     nicm     1350:        }
                   1351:        return (WINDOW_COPY_CMD_NOTHING);
                   1352: }
                   1353:
                   1354: static enum window_copy_cmd_action
                   1355: window_copy_cmd_jump_to_backward(struct window_copy_cmd_state *cs)
                   1356: {
                   1357:        struct window_mode_entry        *wme = cs->wme;
                   1358:        struct window_copy_mode_data    *data = wme->data;
                   1359:        u_int                            np = wme->prefix;
                   1360:        const char                      *argument = cs->args->argv[1];
                   1361:
                   1362:        if (*argument != '\0') {
                   1363:                data->jumptype = WINDOW_COPY_JUMPTOBACKWARD;
                   1364:                data->jumpchar = *argument;
                   1365:                for (; np != 0; np--)
                   1366:                        window_copy_cursor_jump_to_back(wme);
                   1367:        }
                   1368:        return (WINDOW_COPY_CMD_NOTHING);
                   1369: }
                   1370:
                   1371: static enum window_copy_cmd_action
                   1372: window_copy_cmd_jump_to_forward(struct window_copy_cmd_state *cs)
                   1373: {
                   1374:        struct window_mode_entry        *wme = cs->wme;
                   1375:        struct window_copy_mode_data    *data = wme->data;
                   1376:        u_int                            np = wme->prefix;
                   1377:        const char                      *argument = cs->args->argv[1];
                   1378:
                   1379:        if (*argument != '\0') {
                   1380:                data->jumptype = WINDOW_COPY_JUMPTOFORWARD;
                   1381:                data->jumpchar = *argument;
                   1382:                for (; np != 0; np--)
                   1383:                        window_copy_cursor_jump_to(wme);
                   1384:        }
                   1385:        return (WINDOW_COPY_CMD_NOTHING);
                   1386: }
                   1387:
                   1388: static enum window_copy_cmd_action
                   1389: window_copy_cmd_search_backward(struct window_copy_cmd_state *cs)
                   1390: {
                   1391:        struct window_mode_entry        *wme = cs->wme;
                   1392:        struct window_copy_mode_data    *data = wme->data;
                   1393:        u_int                            np = wme->prefix;
                   1394:        const char                      *argument = cs->args->argv[1];
                   1395:
                   1396:        if (*argument != '\0') {
                   1397:                data->searchtype = WINDOW_COPY_SEARCHUP;
                   1398:                free(data->searchstr);
                   1399:                data->searchstr = xstrdup(argument);
                   1400:                for (; np != 0; np--)
                   1401:                        window_copy_search_up(wme);
                   1402:        }
                   1403:        return (WINDOW_COPY_CMD_NOTHING);
                   1404: }
                   1405:
                   1406: static enum window_copy_cmd_action
                   1407: window_copy_cmd_search_forward(struct window_copy_cmd_state *cs)
                   1408: {
                   1409:        struct window_mode_entry        *wme = cs->wme;
                   1410:        struct window_copy_mode_data    *data = wme->data;
                   1411:        u_int                            np = wme->prefix;
                   1412:        const char                      *argument = cs->args->argv[1];
                   1413:
                   1414:        if (*argument != '\0') {
                   1415:                data->searchtype = WINDOW_COPY_SEARCHDOWN;
                   1416:                free(data->searchstr);
                   1417:                data->searchstr = xstrdup(argument);
                   1418:                for (; np != 0; np--)
                   1419:                        window_copy_search_down(wme);
                   1420:        }
                   1421:        return (WINDOW_COPY_CMD_NOTHING);
                   1422: }
                   1423:
                   1424: static enum window_copy_cmd_action
                   1425: window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs)
                   1426: {
                   1427:        struct window_mode_entry        *wme = cs->wme;
                   1428:        struct window_copy_mode_data    *data = wme->data;
                   1429:        const char                      *argument = cs->args->argv[1];
                   1430:        enum window_copy_cmd_action      action = WINDOW_COPY_CMD_NOTHING;
                   1431:        const char                      *ss = data->searchstr;
                   1432:
                   1433:        if (data->searchx == -1 || data->searchy == -1) {
                   1434:                data->searchx = data->cx;
                   1435:                data->searchy = data->cy;
                   1436:                data->searcho = data->oy;
                   1437:        } else if (ss != NULL && strcmp(argument, ss) != 0) {
                   1438:                data->cx = data->searchx;
                   1439:                data->cy = data->searchy;
                   1440:                data->oy = data->searcho;
                   1441:                action = WINDOW_COPY_CMD_REDRAW;
                   1442:        }
                   1443:
                   1444:        if (*argument == '\0') {
                   1445:                window_copy_clear_marks(wme);
                   1446:                return (WINDOW_COPY_CMD_REDRAW);
                   1447:        }
                   1448:
                   1449:        switch (*argument++) {
                   1450:        case '=':
                   1451:        case '-':
                   1452:                data->searchtype = WINDOW_COPY_SEARCHUP;
                   1453:                free(data->searchstr);
                   1454:                data->searchstr = xstrdup(argument);
                   1455:                if (!window_copy_search_up(wme)) {
                   1456:                        window_copy_clear_marks(wme);
                   1457:                        return (WINDOW_COPY_CMD_REDRAW);
                   1458:                }
                   1459:                break;
                   1460:        case '+':
                   1461:                data->searchtype = WINDOW_COPY_SEARCHDOWN;
                   1462:                free(data->searchstr);
                   1463:                data->searchstr = xstrdup(argument);
                   1464:                if (!window_copy_search_down(wme)) {
                   1465:                        window_copy_clear_marks(wme);
                   1466:                        return (WINDOW_COPY_CMD_REDRAW);
                   1467:                }
                   1468:                break;
                   1469:        }
                   1470:        return (action);
                   1471: }
                   1472:
                   1473: static enum window_copy_cmd_action
                   1474: window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs)
                   1475: {
                   1476:        struct window_mode_entry        *wme = cs->wme;
                   1477:        struct window_copy_mode_data    *data = wme->data;
                   1478:        const char                      *argument = cs->args->argv[1];
                   1479:        enum window_copy_cmd_action      action = WINDOW_COPY_CMD_NOTHING;
                   1480:        const char                      *ss = data->searchstr;
                   1481:
                   1482:        if (data->searchx == -1 || data->searchy == -1) {
                   1483:                data->searchx = data->cx;
                   1484:                data->searchy = data->cy;
                   1485:                data->searcho = data->oy;
                   1486:        } else if (ss != NULL && strcmp(argument, ss) != 0) {
                   1487:                data->cx = data->searchx;
                   1488:                data->cy = data->searchy;
                   1489:                data->oy = data->searcho;
                   1490:                action = WINDOW_COPY_CMD_REDRAW;
                   1491:        }
                   1492:
                   1493:        if (*argument == '\0') {
                   1494:                window_copy_clear_marks(wme);
                   1495:                return (WINDOW_COPY_CMD_REDRAW);
                   1496:        }
                   1497:
                   1498:        switch (*argument++) {
                   1499:        case '=':
                   1500:        case '+':
                   1501:                data->searchtype = WINDOW_COPY_SEARCHDOWN;
                   1502:                free(data->searchstr);
                   1503:                data->searchstr = xstrdup(argument);
                   1504:                if (!window_copy_search_down(wme)) {
                   1505:                        window_copy_clear_marks(wme);
                   1506:                        return (WINDOW_COPY_CMD_REDRAW);
                   1507:                }
                   1508:                break;
                   1509:        case '-':
                   1510:                data->searchtype = WINDOW_COPY_SEARCHUP;
                   1511:                free(data->searchstr);
                   1512:                data->searchstr = xstrdup(argument);
                   1513:                if (!window_copy_search_up(wme)) {
                   1514:                        window_copy_clear_marks(wme);
                   1515:                        return (WINDOW_COPY_CMD_REDRAW);
                   1516:                }
                   1517:        }
                   1518:        return (action);
                   1519: }
                   1520:
                   1521: static const struct {
                   1522:        const char                       *command;
                   1523:        int                               minargs;
                   1524:        int                               maxargs;
                   1525:        enum window_copy_cmd_action     (*f)(struct window_copy_cmd_state *);
                   1526: } window_copy_cmd_table[] = {
                   1527:        { "append-selection", 0, 0,
                   1528:          window_copy_cmd_append_selection },
                   1529:        { "append-selection-and-cancel", 0, 0,
                   1530:          window_copy_cmd_append_selection_and_cancel },
                   1531:        { "back-to-indentation", 0, 0,
                   1532:          window_copy_cmd_back_to_indentation },
                   1533:        { "begin-selection", 0, 0,
                   1534:          window_copy_cmd_begin_selection },
                   1535:        { "bottom-line", 0, 0,
                   1536:          window_copy_cmd_bottom_line },
                   1537:        { "cancel", 0, 0,
                   1538:          window_copy_cmd_cancel },
                   1539:        { "clear-selection", 0, 0,
                   1540:          window_copy_cmd_clear_selection },
1.215   ! nicm     1541:        { "copy-end-of-line", 0, 1,
1.213     nicm     1542:          window_copy_cmd_copy_end_of_line },
1.215   ! nicm     1543:        { "copy-line", 0, 1,
1.213     nicm     1544:          window_copy_cmd_copy_line },
1.215   ! nicm     1545:        { "copy-pipe", 1, 2,
1.213     nicm     1546:          window_copy_cmd_copy_pipe },
1.215   ! nicm     1547:        { "copy-pipe-and-cancel", 1, 2,
1.213     nicm     1548:          window_copy_cmd_copy_pipe_and_cancel },
1.215   ! nicm     1549:        { "copy-selection", 0, 1,
1.213     nicm     1550:          window_copy_cmd_copy_selection },
1.215   ! nicm     1551:        { "copy-selection-and-cancel", 0, 1,
1.213     nicm     1552:          window_copy_cmd_copy_selection_and_cancel },
                   1553:        { "cursor-down", 0, 0,
                   1554:          window_copy_cmd_cursor_down },
                   1555:        { "cursor-left", 0, 0,
                   1556:          window_copy_cmd_cursor_left },
                   1557:        { "cursor-right", 0, 0,
                   1558:          window_copy_cmd_cursor_right },
                   1559:        { "cursor-up", 0, 0,
                   1560:          window_copy_cmd_cursor_up },
                   1561:        { "end-of-line", 0, 0,
                   1562:          window_copy_cmd_end_of_line },
                   1563:        { "goto-line", 1, 1,
                   1564:          window_copy_cmd_goto_line },
                   1565:        { "halfpage-down", 0, 0,
                   1566:          window_copy_cmd_halfpage_down },
                   1567:        { "halfpage-down-and-cancel", 0, 0,
                   1568:          window_copy_cmd_halfpage_down_and_cancel },
                   1569:        { "halfpage-up", 0, 0,
                   1570:          window_copy_cmd_halfpage_up },
                   1571:        { "history-bottom", 0, 0,
                   1572:          window_copy_cmd_history_bottom },
                   1573:        { "history-top", 0, 0,
                   1574:          window_copy_cmd_history_top },
                   1575:        { "jump-again", 0, 0,
                   1576:          window_copy_cmd_jump_again },
                   1577:        { "jump-backward", 1, 1,
                   1578:          window_copy_cmd_jump_backward },
                   1579:        { "jump-forward", 1, 1,
                   1580:          window_copy_cmd_jump_forward },
                   1581:        { "jump-reverse", 0, 0,
                   1582:          window_copy_cmd_jump_reverse },
                   1583:        { "jump-to-backward", 1, 1,
                   1584:          window_copy_cmd_jump_to_backward },
                   1585:        { "jump-to-forward", 1, 1,
                   1586:          window_copy_cmd_jump_to_forward },
                   1587:        { "middle-line", 0, 0,
                   1588:          window_copy_cmd_middle_line },
                   1589:        { "next-paragraph", 0, 0,
                   1590:          window_copy_cmd_next_paragraph },
                   1591:        { "next-space", 0, 0,
                   1592:          window_copy_cmd_next_space },
                   1593:        { "next-space-end", 0, 0,
                   1594:          window_copy_cmd_next_space_end },
                   1595:        { "next-word", 0, 0,
                   1596:          window_copy_cmd_next_word },
                   1597:        { "next-word-end", 0, 0,
                   1598:          window_copy_cmd_next_word_end },
                   1599:        { "other-end", 0, 0,
                   1600:          window_copy_cmd_other_end },
                   1601:        { "page-down", 0, 0,
                   1602:          window_copy_cmd_page_down },
                   1603:        { "page-down-and-cancel", 0, 0,
                   1604:          window_copy_cmd_page_down_and_cancel },
                   1605:        { "page-up", 0, 0,
                   1606:          window_copy_cmd_page_up },
                   1607:        { "previous-paragraph", 0, 0,
                   1608:          window_copy_cmd_previous_paragraph },
                   1609:        { "previous-space", 0, 0,
                   1610:          window_copy_cmd_previous_space },
                   1611:        { "previous-word", 0, 0,
                   1612:          window_copy_cmd_previous_word },
                   1613:        { "rectangle-toggle", 0, 0,
                   1614:          window_copy_cmd_rectangle_toggle },
                   1615:        { "scroll-down", 0, 0,
                   1616:          window_copy_cmd_scroll_down },
                   1617:        { "scroll-down-and-cancel", 0, 0,
                   1618:          window_copy_cmd_scroll_down_and_cancel },
                   1619:        { "scroll-up", 0, 0,
                   1620:          window_copy_cmd_scroll_up },
                   1621:        { "search-again", 0, 0,
                   1622:          window_copy_cmd_search_again },
                   1623:        { "search-backward", 1, 1,
                   1624:          window_copy_cmd_search_backward },
                   1625:        { "search-backward-incremental", 1, 1,
                   1626:          window_copy_cmd_search_backward_incremental },
                   1627:        { "search-forward", 1, 1,
                   1628:          window_copy_cmd_search_forward },
                   1629:        { "search-forward-incremental", 1, 1,
                   1630:          window_copy_cmd_search_forward_incremental },
                   1631:        { "search-reverse", 0, 0,
                   1632:          window_copy_cmd_search_reverse },
                   1633:        { "select-line", 0, 0,
                   1634:          window_copy_cmd_select_line },
                   1635:        { "select-word", 0, 0,
                   1636:          window_copy_cmd_select_word },
                   1637:        { "start-of-line", 0, 0,
                   1638:          window_copy_cmd_start_of_line },
                   1639:        { "stop-selection", 0, 0,
                   1640:          window_copy_cmd_stop_selection },
                   1641:        { "top-line", 0, 0,
                   1642:          window_copy_cmd_top_line },
                   1643: };
                   1644:
1.157     nicm     1645: static void
1.208     nicm     1646: window_copy_command(struct window_mode_entry *wme, struct client *c,
1.215   ! nicm     1647:     struct session *s, struct winlink *wl, struct args *args,
1.208     nicm     1648:     struct mouse_event *m)
1.1       nicm     1649: {
1.208     nicm     1650:        struct window_copy_mode_data    *data = wme->data;
1.213     nicm     1651:        struct window_copy_cmd_state     cs;
                   1652:        enum window_copy_cmd_action      action;
                   1653:        const char                      *command;
                   1654:        u_int                            i;
1.155     nicm     1655:
                   1656:        if (args->argc == 0)
                   1657:                return;
                   1658:        command = args->argv[0];
1.21      nicm     1659:
1.202     nicm     1660:        if (m != NULL && m->valid && !MOUSE_WHEEL(m->b))
1.156     nicm     1661:                window_copy_move_mouse(m);
                   1662:
1.213     nicm     1663:        cs.wme = wme;
                   1664:        cs.args = args;
                   1665:        cs.m = m;
1.215   ! nicm     1666:
1.213     nicm     1667:        cs.c = c;
                   1668:        cs.s = s;
1.215   ! nicm     1669:        cs.wl = wl;
1.213     nicm     1670:
                   1671:        action = WINDOW_COPY_CMD_NOTHING;
                   1672:        for (i = 0; i < nitems(window_copy_cmd_table); i++) {
                   1673:                if (strcmp(window_copy_cmd_table[i].command, command) == 0) {
                   1674:                        if (args->argc - 1 < window_copy_cmd_table[i].minargs ||
                   1675:                            args->argc - 1 > window_copy_cmd_table[i].maxargs)
1.155     nicm     1676:                                break;
1.213     nicm     1677:                        action = window_copy_cmd_table[i].f (&cs);
                   1678:                        break;
1.163     nicm     1679:                }
1.1       nicm     1680:        }
1.21      nicm     1681:
1.162     nicm     1682:        if (strncmp(command, "search-", 7) != 0 && data->searchmark != NULL) {
1.208     nicm     1683:                window_copy_clear_marks(wme);
1.213     nicm     1684:                if (action == WINDOW_COPY_CMD_NOTHING)
                   1685:                        action = WINDOW_COPY_CMD_REDRAW;
1.163     nicm     1686:                data->searchx = data->searchy = -1;
1.162     nicm     1687:        }
1.209     nicm     1688:        wme->prefix = 1;
                   1689:
1.213     nicm     1690:        if (action == WINDOW_COPY_CMD_CANCEL)
                   1691:                window_pane_reset_mode(wme->wp);
                   1692:        else if (action == WINDOW_COPY_CMD_REDRAW)
1.208     nicm     1693:                window_copy_redraw_screen(wme);
1.50      nicm     1694: }
                   1695:
1.157     nicm     1696: static void
1.208     nicm     1697: window_copy_scroll_to(struct window_mode_entry *wme, u_int px, u_int py)
1.21      nicm     1698: {
1.208     nicm     1699:        struct window_copy_mode_data    *data = wme->data;
1.54      nicm     1700:        struct grid                     *gd = data->backing->grid;
1.21      nicm     1701:        u_int                            offset, gap;
                   1702:
                   1703:        data->cx = px;
                   1704:
1.185     nicm     1705:        if (py >= gd->hsize - data->oy && py < gd->hsize - data->oy + gd->sy)
                   1706:                data->cy = py - (gd->hsize - data->oy);
                   1707:        else {
                   1708:                gap = gd->sy / 4;
                   1709:                if (py < gd->sy) {
                   1710:                        offset = 0;
                   1711:                        data->cy = py;
                   1712:                } else if (py > gd->hsize + gd->sy - gap) {
                   1713:                        offset = gd->hsize;
                   1714:                        data->cy = py - gd->hsize;
                   1715:                } else {
                   1716:                        offset = py + gap - gd->sy;
                   1717:                        data->cy = py - offset;
                   1718:                }
                   1719:                data->oy = gd->hsize - offset;
1.21      nicm     1720:        }
                   1721:
1.208     nicm     1722:        window_copy_update_selection(wme, 1);
                   1723:        window_copy_redraw_screen(wme);
1.21      nicm     1724: }
                   1725:
1.157     nicm     1726: static int
1.118     nicm     1727: window_copy_search_compare(struct grid *gd, u_int px, u_int py,
                   1728:     struct grid *sgd, u_int spx, int cis)
1.21      nicm     1729: {
1.140     nicm     1730:        struct grid_cell         gc, sgc;
                   1731:        const struct utf8_data  *ud, *sud;
1.21      nicm     1732:
1.140     nicm     1733:        grid_get_cell(gd, px, py, &gc);
                   1734:        ud = &gc.data;
                   1735:        grid_get_cell(sgd, spx, 0, &sgc);
                   1736:        sud = &sgc.data;
1.35      nicm     1737:
1.140     nicm     1738:        if (ud->size != sud->size || ud->width != sud->width)
1.21      nicm     1739:                return (0);
1.97      nicm     1740:
1.140     nicm     1741:        if (cis && ud->size == 1)
                   1742:                return (tolower(ud->data[0]) == sud->data[0]);
1.97      nicm     1743:
1.140     nicm     1744:        return (memcmp(ud->data, sud->data, ud->size) == 0);
1.21      nicm     1745: }
                   1746:
1.157     nicm     1747: static int
1.21      nicm     1748: window_copy_search_lr(struct grid *gd,
1.97      nicm     1749:     struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
1.21      nicm     1750: {
                   1751:        u_int   ax, bx, px;
1.97      nicm     1752:        int     matched;
1.21      nicm     1753:
                   1754:        for (ax = first; ax < last; ax++) {
1.181     nicm     1755:                if (ax + sgd->sx > gd->sx)
1.21      nicm     1756:                        break;
                   1757:                for (bx = 0; bx < sgd->sx; bx++) {
                   1758:                        px = ax + bx;
1.97      nicm     1759:                        matched = window_copy_search_compare(gd, px, py, sgd,
                   1760:                            bx, cis);
                   1761:                        if (!matched)
1.21      nicm     1762:                                break;
                   1763:                }
                   1764:                if (bx == sgd->sx) {
                   1765:                        *ppx = ax;
                   1766:                        return (1);
                   1767:                }
                   1768:        }
                   1769:        return (0);
                   1770: }
                   1771:
1.157     nicm     1772: static int
1.21      nicm     1773: window_copy_search_rl(struct grid *gd,
1.97      nicm     1774:     struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
1.21      nicm     1775: {
                   1776:        u_int   ax, bx, px;
1.97      nicm     1777:        int     matched;
1.21      nicm     1778:
                   1779:        for (ax = last + 1; ax > first; ax--) {
1.24      nicm     1780:                if (gd->sx - (ax - 1) < sgd->sx)
                   1781:                        continue;
1.21      nicm     1782:                for (bx = 0; bx < sgd->sx; bx++) {
                   1783:                        px = ax - 1 + bx;
1.97      nicm     1784:                        matched = window_copy_search_compare(gd, px, py, sgd,
                   1785:                            bx, cis);
                   1786:                        if (!matched)
1.21      nicm     1787:                                break;
                   1788:                }
                   1789:                if (bx == sgd->sx) {
                   1790:                        *ppx = ax - 1;
                   1791:                        return (1);
                   1792:                }
                   1793:        }
                   1794:        return (0);
                   1795: }
                   1796:
1.157     nicm     1797: static void
1.150     nicm     1798: window_copy_move_left(struct screen *s, u_int *fx, u_int *fy)
1.21      nicm     1799: {
1.150     nicm     1800:        if (*fx == 0) { /* left */
                   1801:                if (*fy == 0) /* top */
                   1802:                        return;
                   1803:                *fx = screen_size_x(s) - 1;
                   1804:                *fy = *fy - 1;
                   1805:        } else
                   1806:                *fx = *fx - 1;
                   1807: }
1.21      nicm     1808:
1.157     nicm     1809: static void
1.150     nicm     1810: window_copy_move_right(struct screen *s, u_int *fx, u_int *fy)
                   1811: {
                   1812:        if (*fx == screen_size_x(s) - 1) { /* right */
                   1813:                if (*fy == screen_hsize(s) + screen_size_y(s)) /* bottom */
1.21      nicm     1814:                        return;
1.150     nicm     1815:                *fx = 0;
                   1816:                *fy = *fy + 1;
1.21      nicm     1817:        } else
1.150     nicm     1818:                *fx = *fx + 1;
                   1819: }
1.21      nicm     1820:
1.157     nicm     1821: static int
1.150     nicm     1822: window_copy_is_lowercase(const char *ptr)
                   1823: {
                   1824:        while (*ptr != '\0') {
                   1825:                if (*ptr != tolower((u_char)*ptr))
                   1826:                        return (0);
                   1827:                ++ptr;
1.97      nicm     1828:        }
1.150     nicm     1829:        return (1);
                   1830: }
1.97      nicm     1831:
1.150     nicm     1832: /*
                   1833:  * Search for text stored in sgd starting from position fx,fy up to endline. If
                   1834:  * found, jump to it. If cis then ignore case. The direction is 0 for searching
                   1835:  * up, down otherwise. If wrap then go to begin/end of grid and try again if
                   1836:  * not found.
                   1837:  */
1.163     nicm     1838: static int
1.208     nicm     1839: window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
1.150     nicm     1840:     struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap,
                   1841:     int direction)
                   1842: {
                   1843:        u_int   i, px;
                   1844:        int     found;
                   1845:
                   1846:        found = 0;
                   1847:        if (direction) {
                   1848:                for (i = fy; i <= endline; i++) {
                   1849:                        found = window_copy_search_lr(gd, sgd, &px, i, fx,
                   1850:                            gd->sx, cis);
                   1851:                        if (found)
                   1852:                                break;
                   1853:                        fx = 0;
                   1854:                }
                   1855:        } else {
                   1856:                for (i = fy + 1; endline < i; i--) {
                   1857:                        found = window_copy_search_rl(gd, sgd, &px, i - 1, 0,
                   1858:                            fx, cis);
                   1859:                        if (found) {
                   1860:                                i--;
                   1861:                                break;
                   1862:                        }
                   1863:                        fx = gd->sx;
1.21      nicm     1864:                }
                   1865:        }
1.150     nicm     1866:
1.163     nicm     1867:        if (found) {
1.208     nicm     1868:                window_copy_scroll_to(wme, px, i);
1.163     nicm     1869:                return (1);
                   1870:        }
                   1871:        if (wrap) {
1.208     nicm     1872:                return (window_copy_search_jump(wme, gd, sgd,
1.163     nicm     1873:                    direction ? 0 : gd->sx - 1,
1.150     nicm     1874:                    direction ? 0 : gd->hsize + gd->sy - 1, fy, cis, 0,
1.163     nicm     1875:                    direction));
1.21      nicm     1876:        }
1.163     nicm     1877:        return (0);
1.21      nicm     1878: }
                   1879:
1.150     nicm     1880: /*
                   1881:  * Search in for text searchstr. If direction is 0 then search up, otherwise
1.184     nicm     1882:  * down.
1.150     nicm     1883:  */
1.163     nicm     1884: static int
1.208     nicm     1885: window_copy_search(struct window_mode_entry *wme, int direction)
1.21      nicm     1886: {
1.208     nicm     1887:        struct window_pane              *wp = wme->wp;
                   1888:        struct window_copy_mode_data    *data = wme->data;
1.54      nicm     1889:        struct screen                   *s = data->backing, ss;
1.21      nicm     1890:        struct screen_write_ctx          ctx;
1.150     nicm     1891:        struct grid                     *gd = s->grid;
                   1892:        u_int                            fx, fy, endline;
1.163     nicm     1893:        int                              wrapflag, cis, found;
1.21      nicm     1894:
1.174     nicm     1895:        free(wp->searchstr);
                   1896:        wp->searchstr = xstrdup(data->searchstr);
                   1897:
1.150     nicm     1898:        fx = data->cx;
                   1899:        fy = screen_hsize(data->backing) - data->oy + data->cy;
1.21      nicm     1900:
1.162     nicm     1901:        screen_init(&ss, screen_write_strlen("%s", data->searchstr), 1, 0);
1.21      nicm     1902:        screen_write_start(&ctx, NULL, &ss);
1.162     nicm     1903:        screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", data->searchstr);
1.21      nicm     1904:        screen_write_stop(&ctx);
                   1905:
1.184     nicm     1906:        if (direction)
                   1907:                window_copy_move_right(s, &fx, &fy);
                   1908:        else
                   1909:                window_copy_move_left(s, &fx, &fy);
1.150     nicm     1910:
                   1911:        wrapflag = options_get_number(wp->window->options, "wrap-search");
1.162     nicm     1912:        cis = window_copy_is_lowercase(data->searchstr);
1.21      nicm     1913:
1.150     nicm     1914:        if (direction)
                   1915:                endline = gd->hsize + gd->sy - 1;
                   1916:        else
                   1917:                endline = 0;
1.208     nicm     1918:        found = window_copy_search_jump(wme, gd, ss.grid, fx, fy, endline, cis,
1.162     nicm     1919:            wrapflag, direction);
                   1920:
1.208     nicm     1921:        if (window_copy_search_marks(wme, &ss))
                   1922:                window_copy_redraw_screen(wme);
1.21      nicm     1923:
1.150     nicm     1924:        screen_free(&ss);
1.163     nicm     1925:        return (found);
1.150     nicm     1926: }
1.97      nicm     1927:
1.162     nicm     1928: static int
1.208     nicm     1929: window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp)
1.162     nicm     1930: {
1.208     nicm     1931:        struct window_copy_mode_data    *data = wme->data;
1.162     nicm     1932:        struct screen                   *s = data->backing, ss;
                   1933:        struct screen_write_ctx          ctx;
                   1934:        struct grid                     *gd = s->grid;
1.170     nicm     1935:        int                              found, cis, which = -1;
1.162     nicm     1936:        u_int                            px, py, b, nfound = 0, width;
                   1937:
                   1938:        if (ssp == NULL) {
                   1939:                width = screen_write_strlen("%s", data->searchstr);
                   1940:                screen_init(&ss, width, 1, 0);
                   1941:                screen_write_start(&ctx, NULL, &ss);
                   1942:                screen_write_nputs(&ctx, -1, &grid_default_cell, "%s",
                   1943:                    data->searchstr);
                   1944:                screen_write_stop(&ctx);
                   1945:                ssp = &ss;
                   1946:        } else
                   1947:                width = screen_size_x(ssp);
                   1948:
                   1949:        cis = window_copy_is_lowercase(data->searchstr);
                   1950:
                   1951:        free(data->searchmark);
                   1952:        data->searchmark = bit_alloc((gd->hsize + gd->sy) * gd->sx);
                   1953:
                   1954:        for (py = 0; py < gd->hsize + gd->sy; py++) {
                   1955:                px = 0;
                   1956:                for (;;) {
                   1957:                        found = window_copy_search_lr(gd, ssp->grid, &px, py,
                   1958:                            px, gd->sx, cis);
                   1959:                        if (!found)
                   1960:                                break;
1.170     nicm     1961:
1.162     nicm     1962:                        nfound++;
1.170     nicm     1963:                        if (px == data->cx && py == gd->hsize + data->cy - data->oy)
                   1964:                                which = nfound;
1.162     nicm     1965:
                   1966:                        b = (py * gd->sx) + px;
                   1967:                        bit_nset(data->searchmark, b, b + width - 1);
                   1968:
                   1969:                        px++;
                   1970:                }
                   1971:        }
                   1972:
1.170     nicm     1973:        if (which != -1)
                   1974:                data->searchthis = 1 + nfound - which;
                   1975:        else
                   1976:                data->searchthis = -1;
                   1977:        data->searchcount = nfound;
                   1978:
1.162     nicm     1979:        if (ssp == &ss)
                   1980:                screen_free(&ss);
                   1981:        return (nfound);
                   1982: }
                   1983:
1.157     nicm     1984: static void
1.208     nicm     1985: window_copy_clear_marks(struct window_mode_entry *wme)
1.163     nicm     1986: {
1.208     nicm     1987:        struct window_copy_mode_data    *data = wme->data;
1.163     nicm     1988:
                   1989:        free(data->searchmark);
                   1990:        data->searchmark = NULL;
                   1991: }
                   1992:
                   1993: static int
1.208     nicm     1994: window_copy_search_up(struct window_mode_entry *wme)
1.150     nicm     1995: {
1.208     nicm     1996:        return (window_copy_search(wme, 0));
1.150     nicm     1997: }
1.21      nicm     1998:
1.163     nicm     1999: static int
1.208     nicm     2000: window_copy_search_down(struct window_mode_entry *wme)
1.150     nicm     2001: {
1.208     nicm     2002:        return (window_copy_search(wme, 1));
1.21      nicm     2003: }
                   2004:
1.157     nicm     2005: static void
1.208     nicm     2006: window_copy_goto_line(struct window_mode_entry *wme, const char *linestr)
1.21      nicm     2007: {
1.208     nicm     2008:        struct window_copy_mode_data    *data = wme->data;
1.21      nicm     2009:        const char                      *errstr;
1.199     nicm     2010:        int                              lineno;
1.21      nicm     2011:
1.199     nicm     2012:        lineno = strtonum(linestr, -1, INT_MAX, &errstr);
1.21      nicm     2013:        if (errstr != NULL)
                   2014:                return;
1.199     nicm     2015:        if (lineno < 0 || (u_int)lineno > screen_hsize(data->backing))
                   2016:                lineno = screen_hsize(data->backing);
1.35      nicm     2017:
1.21      nicm     2018:        data->oy = lineno;
1.208     nicm     2019:        window_copy_update_selection(wme, 1);
                   2020:        window_copy_redraw_screen(wme);
1.21      nicm     2021: }
                   2022:
1.157     nicm     2023: static void
1.208     nicm     2024: window_copy_write_line(struct window_mode_entry *wme,
                   2025:     struct screen_write_ctx *ctx, u_int py)
1.1       nicm     2026: {
1.208     nicm     2027:        struct window_pane              *wp = wme->wp;
                   2028:        struct window_copy_mode_data    *data = wme->data;
1.1       nicm     2029:        struct screen                   *s = &data->screen;
1.136     nicm     2030:        struct options                  *oo = wp->window->options;
1.1       nicm     2031:        struct grid_cell                 gc;
1.100     nicm     2032:        char                             hdr[512];
1.162     nicm     2033:        size_t                           size = 0;
1.21      nicm     2034:
1.101     nicm     2035:        style_apply(&gc, oo, "mode-style");
1.164     nicm     2036:        gc.flags |= GRID_FLAG_NOPALETTE;
1.1       nicm     2037:
1.201     nicm     2038:        if (py == 0 && s->rupper < s->rlower) {
1.170     nicm     2039:                if (data->searchmark == NULL) {
                   2040:                        size = xsnprintf(hdr, sizeof hdr,
                   2041:                            "[%u/%u]", data->oy, screen_hsize(data->backing));
                   2042:                } else {
                   2043:                        if (data->searchthis == -1) {
                   2044:                                size = xsnprintf(hdr, sizeof hdr,
                   2045:                                    "(%u results) [%d/%u]", data->searchcount,
                   2046:                                    data->oy, screen_hsize(data->backing));
                   2047:                        } else {
                   2048:                                size = xsnprintf(hdr, sizeof hdr,
                   2049:                                    "(%u/%u results) [%d/%u]", data->searchthis,
                   2050:                                    data->searchcount, data->oy,
                   2051:                                    screen_hsize(data->backing));
                   2052:                        }
                   2053:                }
1.62      nicm     2054:                if (size > screen_size_x(s))
                   2055:                        size = screen_size_x(s);
1.212     nicm     2056:                screen_write_cursormove(ctx, screen_size_x(s) - size, 0, 0);
1.1       nicm     2057:                screen_write_puts(ctx, &gc, "%s", hdr);
                   2058:        } else
                   2059:                size = 0;
                   2060:
1.105     nicm     2061:        if (size < screen_size_x(s)) {
1.212     nicm     2062:                screen_write_cursormove(ctx, 0, py, 0);
1.162     nicm     2063:                screen_write_copy(ctx, data->backing, 0,
1.105     nicm     2064:                    (screen_hsize(data->backing) - data->oy) + py,
1.162     nicm     2065:                    screen_size_x(s) - size, 1, data->searchmark, &gc);
1.105     nicm     2066:        }
1.18      nicm     2067:
                   2068:        if (py == data->cy && data->cx == screen_size_x(s)) {
                   2069:                memcpy(&gc, &grid_default_cell, sizeof gc);
1.212     nicm     2070:                screen_write_cursormove(ctx, screen_size_x(s) - 1, py, 0);
1.18      nicm     2071:                screen_write_putc(ctx, &gc, '$');
                   2072:        }
1.1       nicm     2073: }
                   2074:
1.157     nicm     2075: static void
1.208     nicm     2076: window_copy_write_lines(struct window_mode_entry *wme,
                   2077:     struct screen_write_ctx *ctx, u_int py, u_int ny)
1.1       nicm     2078: {
                   2079:        u_int   yy;
                   2080:
                   2081:        for (yy = py; yy < py + ny; yy++)
1.208     nicm     2082:                window_copy_write_line(wme, ctx, py);
1.121     nicm     2083: }
                   2084:
1.157     nicm     2085: static void
1.208     nicm     2086: window_copy_redraw_selection(struct window_mode_entry *wme, u_int old_y)
1.121     nicm     2087: {
1.208     nicm     2088:        struct window_copy_mode_data    *data = wme->data;
1.121     nicm     2089:        u_int                            new_y, start, end;
                   2090:
                   2091:        new_y = data->cy;
                   2092:        if (old_y <= new_y) {
                   2093:                start = old_y;
                   2094:                end = new_y;
                   2095:        } else {
                   2096:                start = new_y;
                   2097:                end = old_y;
                   2098:        }
1.208     nicm     2099:        window_copy_redraw_lines(wme, start, end - start + 1);
1.1       nicm     2100: }
                   2101:
1.157     nicm     2102: static void
1.208     nicm     2103: window_copy_redraw_lines(struct window_mode_entry *wme, u_int py, u_int ny)
1.1       nicm     2104: {
1.208     nicm     2105:        struct window_pane              *wp = wme->wp;
                   2106:        struct window_copy_mode_data    *data = wme->data;
1.1       nicm     2107:        struct screen_write_ctx          ctx;
                   2108:        u_int                            i;
                   2109:
                   2110:        screen_write_start(&ctx, wp, NULL);
                   2111:        for (i = py; i < py + ny; i++)
1.208     nicm     2112:                window_copy_write_line(wme, &ctx, i);
1.212     nicm     2113:        screen_write_cursormove(&ctx, data->cx, data->cy, 0);
1.1       nicm     2114:        screen_write_stop(&ctx);
                   2115: }
                   2116:
1.157     nicm     2117: static void
1.208     nicm     2118: window_copy_redraw_screen(struct window_mode_entry *wme)
1.1       nicm     2119: {
1.208     nicm     2120:        struct window_copy_mode_data    *data = wme->data;
1.1       nicm     2121:
1.208     nicm     2122:        window_copy_redraw_lines(wme, 0, screen_size_y(&data->screen));
1.1       nicm     2123: }
                   2124:
1.157     nicm     2125: static void
1.208     nicm     2126: window_copy_synchronize_cursor(struct window_mode_entry *wme)
1.161     nicm     2127: {
1.208     nicm     2128:        struct window_copy_mode_data    *data = wme->data;
1.161     nicm     2129:        u_int                            xx, yy;
                   2130:
                   2131:        xx = data->cx;
                   2132:        yy = screen_hsize(data->backing) + data->cy - data->oy;
                   2133:
                   2134:        switch (data->cursordrag) {
                   2135:        case CURSORDRAG_ENDSEL:
                   2136:                data->endselx = xx;
                   2137:                data->endsely = yy;
                   2138:                break;
                   2139:        case CURSORDRAG_SEL:
                   2140:                data->selx = xx;
                   2141:                data->sely = yy;
                   2142:                break;
                   2143:        case CURSORDRAG_NONE:
                   2144:                break;
                   2145:        }
                   2146: }
                   2147:
                   2148: static void
1.208     nicm     2149: window_copy_update_cursor(struct window_mode_entry *wme, u_int cx, u_int cy)
1.1       nicm     2150: {
1.208     nicm     2151:        struct window_pane              *wp = wme->wp;
                   2152:        struct window_copy_mode_data    *data = wme->data;
1.18      nicm     2153:        struct screen                   *s = &data->screen;
1.1       nicm     2154:        struct screen_write_ctx          ctx;
1.18      nicm     2155:        u_int                            old_cx, old_cy;
1.1       nicm     2156:
1.18      nicm     2157:        old_cx = data->cx; old_cy = data->cy;
                   2158:        data->cx = cx; data->cy = cy;
                   2159:        if (old_cx == screen_size_x(s))
1.208     nicm     2160:                window_copy_redraw_lines(wme, old_cy, 1);
1.18      nicm     2161:        if (data->cx == screen_size_x(s))
1.208     nicm     2162:                window_copy_redraw_lines(wme, data->cy, 1);
1.18      nicm     2163:        else {
                   2164:                screen_write_start(&ctx, wp, NULL);
1.212     nicm     2165:                screen_write_cursormove(&ctx, data->cx, data->cy, 0);
1.18      nicm     2166:                screen_write_stop(&ctx);
                   2167:        }
1.1       nicm     2168: }
                   2169:
1.157     nicm     2170: static void
1.208     nicm     2171: window_copy_start_selection(struct window_mode_entry *wme)
1.1       nicm     2172: {
1.208     nicm     2173:        struct window_copy_mode_data    *data = wme->data;
1.1       nicm     2174:
1.18      nicm     2175:        data->selx = data->cx;
1.54      nicm     2176:        data->sely = screen_hsize(data->backing) + data->cy - data->oy;
1.1       nicm     2177:
1.161     nicm     2178:        data->endselx = data->selx;
                   2179:        data->endsely = data->sely;
                   2180:
                   2181:        data->cursordrag = CURSORDRAG_ENDSEL;
                   2182:
1.208     nicm     2183:        window_copy_set_selection(wme, 1);
1.1       nicm     2184: }
                   2185:
1.157     nicm     2186: static int
1.208     nicm     2187: window_copy_adjust_selection(struct window_mode_entry *wme, u_int *selx,
                   2188:     u_int *sely)
1.161     nicm     2189: {
1.208     nicm     2190:        struct window_copy_mode_data    *data = wme->data;
1.161     nicm     2191:        struct screen                   *s = &data->screen;
                   2192:        u_int                            sx, sy, ty;
                   2193:        int                              relpos;
                   2194:
                   2195:        sx = *selx;
                   2196:        sy = *sely;
                   2197:
                   2198:        ty = screen_hsize(data->backing) - data->oy;
                   2199:        if (sy < ty) {
                   2200:                relpos = WINDOW_COPY_REL_POS_ABOVE;
                   2201:                if (!data->rectflag)
                   2202:                        sx = 0;
                   2203:                sy = 0;
                   2204:        } else if (sy > ty + screen_size_y(s) - 1) {
                   2205:                relpos = WINDOW_COPY_REL_POS_BELOW;
                   2206:                if (!data->rectflag)
                   2207:                        sx = screen_size_x(s) - 1;
                   2208:                sy = screen_size_y(s) - 1;
                   2209:        } else {
                   2210:                relpos = WINDOW_COPY_REL_POS_ON_SCREEN;
                   2211:                sy -= ty;
                   2212:        }
                   2213:
                   2214:        *selx = sx;
1.176     nicm     2215:        *sely = sy;
1.161     nicm     2216:        return (relpos);
                   2217: }
                   2218:
                   2219: static int
1.208     nicm     2220: window_copy_update_selection(struct window_mode_entry *wme, int may_redraw)
1.1       nicm     2221: {
1.208     nicm     2222:        struct window_copy_mode_data    *data = wme->data;
1.1       nicm     2223:        struct screen                   *s = &data->screen;
1.192     nicm     2224:
                   2225:        if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
                   2226:                return (0);
1.208     nicm     2227:        return (window_copy_set_selection(wme, may_redraw));
1.192     nicm     2228: }
                   2229:
                   2230: static int
1.208     nicm     2231: window_copy_set_selection(struct window_mode_entry *wme, int may_redraw)
1.192     nicm     2232: {
1.208     nicm     2233:        struct window_pane              *wp = wme->wp;
                   2234:        struct window_copy_mode_data    *data = wme->data;
1.192     nicm     2235:        struct screen                   *s = &data->screen;
1.136     nicm     2236:        struct options                  *oo = wp->window->options;
1.1       nicm     2237:        struct grid_cell                 gc;
1.161     nicm     2238:        u_int                            sx, sy, cy, endsx, endsy;
                   2239:        int                              startrelpos, endrelpos;
1.1       nicm     2240:
1.208     nicm     2241:        window_copy_synchronize_cursor(wme);
1.1       nicm     2242:
                   2243:        /* Adjust the selection. */
                   2244:        sx = data->selx;
                   2245:        sy = data->sely;
1.208     nicm     2246:        startrelpos = window_copy_adjust_selection(wme, &sx, &sy);
1.161     nicm     2247:
                   2248:        /* Adjust the end of selection. */
                   2249:        endsx = data->endselx;
                   2250:        endsy = data->endsely;
1.208     nicm     2251:        endrelpos = window_copy_adjust_selection(wme, &endsx, &endsy);
1.161     nicm     2252:
                   2253:        /* Selection is outside of the current screen */
                   2254:        if (startrelpos == endrelpos &&
                   2255:            startrelpos != WINDOW_COPY_REL_POS_ON_SCREEN) {
                   2256:                screen_hide_selection(s);
                   2257:                return (0);
                   2258:        }
1.1       nicm     2259:
1.161     nicm     2260:        /* Set colours and selection. */
                   2261:        style_apply(&gc, oo, "mode-style");
1.164     nicm     2262:        gc.flags |= GRID_FLAG_NOPALETTE;
1.192     nicm     2263:        screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag,
                   2264:            data->modekeys, &gc);
1.42      nicm     2265:
1.96      nicm     2266:        if (data->rectflag && may_redraw) {
1.42      nicm     2267:                /*
                   2268:                 * Can't rely on the caller to redraw the right lines for
                   2269:                 * rectangle selection - find the highest line and the number
                   2270:                 * of lines, and redraw just past that in both directions
                   2271:                 */
                   2272:                cy = data->cy;
1.182     nicm     2273:                if (data->cursordrag == CURSORDRAG_ENDSEL) {
                   2274:                        if (sy < cy)
1.208     nicm     2275:                                window_copy_redraw_lines(wme, sy, cy - sy + 1);
1.182     nicm     2276:                        else
1.208     nicm     2277:                                window_copy_redraw_lines(wme, cy, sy - cy + 1);
1.182     nicm     2278:                } else {
1.208     nicm     2279:                        if (endsy < cy) {
                   2280:                                window_copy_redraw_lines(wme, endsy,
                   2281:                                    cy - endsy + 1);
                   2282:                        } else {
                   2283:                                window_copy_redraw_lines(wme, cy,
                   2284:                                    endsy - cy + 1);
                   2285:                        }
1.182     nicm     2286:                }
1.42      nicm     2287:        }
                   2288:
1.1       nicm     2289:        return (1);
                   2290: }
                   2291:
1.157     nicm     2292: static void *
1.208     nicm     2293: window_copy_get_selection(struct window_mode_entry *wme, size_t *len)
1.1       nicm     2294: {
1.208     nicm     2295:        struct window_pane              *wp = wme->wp;
                   2296:        struct window_copy_mode_data    *data = wme->data;
1.1       nicm     2297:        struct screen                   *s = &data->screen;
                   2298:        char                            *buf;
1.42      nicm     2299:        size_t                           off;
1.111     nicm     2300:        u_int                            i, xx, yy, sx, sy, ex, ey, ey_last;
1.188     nicm     2301:        u_int                            firstsx, lastex, restex, restsx, selx;
1.69      nicm     2302:        int                              keys;
1.1       nicm     2303:
1.192     nicm     2304:        if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE)
1.89      nicm     2305:                return (NULL);
1.1       nicm     2306:
                   2307:        buf = xmalloc(1);
                   2308:        off = 0;
                   2309:
                   2310:        *buf = '\0';
                   2311:
                   2312:        /*
                   2313:         * The selection extends from selx,sely to (adjusted) cx,cy on
                   2314:         * the base screen.
                   2315:         */
                   2316:
                   2317:        /* Find start and end. */
1.161     nicm     2318:        xx = data->endselx;
                   2319:        yy = data->endsely;
1.2       nicm     2320:        if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
1.1       nicm     2321:                sx = xx; sy = yy;
                   2322:                ex = data->selx; ey = data->sely;
                   2323:        } else {
                   2324:                sx = data->selx; sy = data->sely;
                   2325:                ex = xx; ey = yy;
                   2326:        }
                   2327:
                   2328:        /* Trim ex to end of line. */
1.208     nicm     2329:        ey_last = window_copy_find_length(wme, ey);
1.111     nicm     2330:        if (ex > ey_last)
                   2331:                ex = ey_last;
1.1       nicm     2332:
1.42      nicm     2333:        /*
                   2334:         * Deal with rectangle-copy if necessary; four situations: start of
                   2335:         * first line (firstsx), end of last line (lastex), start (restsx) and
                   2336:         * end (restex) of all other lines.
                   2337:         */
                   2338:        xx = screen_size_x(s);
1.69      nicm     2339:
                   2340:        /*
                   2341:         * Behave according to mode-keys. If it is emacs, copy like emacs,
                   2342:         * keeping the top-left-most character, and dropping the
                   2343:         * bottom-right-most, regardless of copy direction. If it is vi, also
                   2344:         * keep bottom-right-most character.
                   2345:         */
1.136     nicm     2346:        keys = options_get_number(wp->window->options, "mode-keys");
1.42      nicm     2347:        if (data->rectflag) {
                   2348:                /*
                   2349:                 * Need to ignore the column with the cursor in it, which for
                   2350:                 * rectangular copy means knowing which side the cursor is on.
                   2351:                 */
1.188     nicm     2352:                if (data->cursordrag == CURSORDRAG_ENDSEL)
                   2353:                        selx = data->selx;
                   2354:                else
                   2355:                        selx = data->endselx;
                   2356:                if (selx < data->cx) {
1.42      nicm     2357:                        /* Selection start is on the left. */
1.69      nicm     2358:                        if (keys == MODEKEY_EMACS) {
                   2359:                                lastex = data->cx;
                   2360:                                restex = data->cx;
                   2361:                        }
                   2362:                        else {
                   2363:                                lastex = data->cx + 1;
                   2364:                                restex = data->cx + 1;
                   2365:                        }
1.188     nicm     2366:                        firstsx = selx;
                   2367:                        restsx = selx;
1.42      nicm     2368:                } else {
                   2369:                        /* Cursor is on the left. */
1.188     nicm     2370:                        lastex = selx + 1;
                   2371:                        restex = selx + 1;
1.64      nicm     2372:                        firstsx = data->cx;
                   2373:                        restsx = data->cx;
1.42      nicm     2374:                }
                   2375:        } else {
1.69      nicm     2376:                if (keys == MODEKEY_EMACS)
                   2377:                        lastex = ex;
1.74      nicm     2378:                else
1.69      nicm     2379:                        lastex = ex + 1;
1.42      nicm     2380:                restex = xx;
                   2381:                firstsx = sx;
                   2382:                restsx = 0;
                   2383:        }
                   2384:
1.1       nicm     2385:        /* Copy the lines. */
1.110     nicm     2386:        for (i = sy; i <= ey; i++) {
1.208     nicm     2387:                window_copy_copy_line(wme, &buf, &off, i,
1.110     nicm     2388:                    (i == sy ? firstsx : restsx),
                   2389:                    (i == ey ? lastex : restex));
1.1       nicm     2390:        }
                   2391:
1.26      nicm     2392:        /* Don't bother if no data. */
                   2393:        if (off == 0) {
1.81      nicm     2394:                free(buf);
1.89      nicm     2395:                return (NULL);
1.26      nicm     2396:        }
1.111     nicm     2397:        if (keys == MODEKEY_EMACS || lastex <= ey_last)
                   2398:                off -= 1; /* remove final \n (unless at end in vi mode) */
                   2399:        *len = off;
1.89      nicm     2400:        return (buf);
                   2401: }
                   2402:
1.157     nicm     2403: static void
1.215   ! nicm     2404: window_copy_copy_buffer(struct window_mode_entry *wme, const char *prefix,
        !          2405:     void *buf, size_t len)
1.89      nicm     2406: {
1.208     nicm     2407:        struct window_pane      *wp = wme->wp;
                   2408:        struct screen_write_ctx  ctx;
1.72      nicm     2409:
1.178     nicm     2410:        if (options_get_number(global_options, "set-clipboard") != 0) {
1.91      nicm     2411:                screen_write_start(&ctx, wp, NULL);
                   2412:                screen_write_setselection(&ctx, buf, len);
                   2413:                screen_write_stop(&ctx);
1.179     nicm     2414:                notify_pane("pane-set-clipboard", wp);
1.91      nicm     2415:        }
1.1       nicm     2416:
1.215   ! nicm     2417:        paste_add(prefix, buf, len);
1.89      nicm     2418: }
                   2419:
1.157     nicm     2420: static void
1.208     nicm     2421: window_copy_copy_pipe(struct window_mode_entry *wme, struct session *s,
1.215   ! nicm     2422:     const char *prefix, const char *command)
1.89      nicm     2423: {
1.215   ! nicm     2424:        void            *buf;
        !          2425:        size_t           len;
        !          2426:        struct job      *job;
1.89      nicm     2427:
1.208     nicm     2428:        buf = window_copy_get_selection(wme, &len);
1.89      nicm     2429:        if (buf == NULL)
                   2430:                return;
                   2431:
1.215   ! nicm     2432:        job = job_run(command, s, NULL, NULL, NULL, NULL, NULL, JOB_NOWAIT);
1.196     nicm     2433:        bufferevent_write(job_get_event(job), buf, len);
1.215   ! nicm     2434:        window_copy_copy_buffer(wme, prefix, buf, len);
1.89      nicm     2435: }
                   2436:
1.157     nicm     2437: static void
1.215   ! nicm     2438: window_copy_copy_selection(struct window_mode_entry *wme, const char *prefix)
1.89      nicm     2439: {
1.203     nicm     2440:        char    *buf;
1.114     nicm     2441:        size_t   len;
1.89      nicm     2442:
1.208     nicm     2443:        buf = window_copy_get_selection(wme, &len);
1.203     nicm     2444:        if (buf != NULL)
1.215   ! nicm     2445:                window_copy_copy_buffer(wme, prefix, buf, len);
1.103     nicm     2446: }
                   2447:
1.157     nicm     2448: static void
1.208     nicm     2449: window_copy_append_selection(struct window_mode_entry *wme)
1.103     nicm     2450: {
1.208     nicm     2451:        struct window_pane              *wp = wme->wp;
1.108     nicm     2452:        char                            *buf;
                   2453:        struct paste_buffer             *pb;
1.203     nicm     2454:        const char                      *bufdata, *bufname;
1.132     nicm     2455:        size_t                           len, bufsize;
1.108     nicm     2456:        struct screen_write_ctx          ctx;
1.103     nicm     2457:
1.208     nicm     2458:        buf = window_copy_get_selection(wme, &len);
1.103     nicm     2459:        if (buf == NULL)
                   2460:                return;
                   2461:
1.178     nicm     2462:        if (options_get_number(global_options, "set-clipboard") != 0) {
1.103     nicm     2463:                screen_write_start(&ctx, wp, NULL);
                   2464:                screen_write_setselection(&ctx, buf, len);
                   2465:                screen_write_stop(&ctx);
1.179     nicm     2466:                notify_pane("pane-set-clipboard", wp);
1.103     nicm     2467:        }
                   2468:
1.203     nicm     2469:        pb = paste_get_top(&bufname);
1.103     nicm     2470:        if (pb != NULL) {
1.132     nicm     2471:                bufdata = paste_buffer_data(pb, &bufsize);
                   2472:                buf = xrealloc(buf, len + bufsize);
                   2473:                memmove(buf + bufsize, buf, len);
                   2474:                memcpy(buf, bufdata, bufsize);
                   2475:                len += bufsize;
1.103     nicm     2476:        }
1.108     nicm     2477:        if (paste_set(buf, len, bufname, NULL) != 0)
1.103     nicm     2478:                free(buf);
1.1       nicm     2479: }
                   2480:
1.157     nicm     2481: static void
1.208     nicm     2482: window_copy_copy_line(struct window_mode_entry *wme, char **buf, size_t *off,
                   2483:     u_int sy, u_int sx, u_int ex)
1.1       nicm     2484: {
1.208     nicm     2485:        struct window_copy_mode_data    *data = wme->data;
1.54      nicm     2486:        struct grid                     *gd = data->backing->grid;
1.140     nicm     2487:        struct grid_cell                 gc;
1.54      nicm     2488:        struct grid_line                *gl;
1.86      nicm     2489:        struct utf8_data                 ud;
1.54      nicm     2490:        u_int                            i, xx, wrapped = 0;
1.115     nicm     2491:        const char                      *s;
1.1       nicm     2492:
                   2493:        if (sx > ex)
                   2494:                return;
                   2495:
1.16      nicm     2496:        /*
                   2497:         * Work out if the line was wrapped at the screen edge and all of it is
                   2498:         * on screen.
                   2499:         */
1.190     nicm     2500:        gl = grid_get_line(gd, sy);
1.35      nicm     2501:        if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
1.16      nicm     2502:                wrapped = 1;
                   2503:
                   2504:        /* If the line was wrapped, don't strip spaces (use the full length). */
                   2505:        if (wrapped)
                   2506:                xx = gl->cellsize;
                   2507:        else
1.208     nicm     2508:                xx = window_copy_find_length(wme, sy);
1.1       nicm     2509:        if (ex > xx)
                   2510:                ex = xx;
                   2511:        if (sx > xx)
                   2512:                sx = xx;
                   2513:
                   2514:        if (sx < ex) {
                   2515:                for (i = sx; i < ex; i++) {
1.140     nicm     2516:                        grid_get_cell(gd, i, sy, &gc);
                   2517:                        if (gc.flags & GRID_FLAG_PADDING)
1.1       nicm     2518:                                continue;
1.140     nicm     2519:                        utf8_copy(&ud, &gc.data);
                   2520:                        if (ud.size == 1 && (gc.attr & GRID_ATTR_CHARSET)) {
1.115     nicm     2521:                                s = tty_acs_get(NULL, ud.data[0]);
                   2522:                                if (s != NULL && strlen(s) <= sizeof ud.data) {
                   2523:                                        ud.size = strlen(s);
1.117     nicm     2524:                                        memcpy(ud.data, s, ud.size);
1.115     nicm     2525:                                }
                   2526:                        }
1.86      nicm     2527:
1.116     nicm     2528:                        *buf = xrealloc(*buf, (*off) + ud.size);
1.86      nicm     2529:                        memcpy(*buf + *off, ud.data, ud.size);
                   2530:                        *off += ud.size;
1.1       nicm     2531:                }
                   2532:        }
                   2533:
1.16      nicm     2534:        /* Only add a newline if the line wasn't wrapped. */
1.44      nicm     2535:        if (!wrapped || ex != xx) {
1.116     nicm     2536:                *buf = xrealloc(*buf, (*off) + 1);
1.16      nicm     2537:                (*buf)[(*off)++] = '\n';
                   2538:        }
1.1       nicm     2539: }
                   2540:
1.157     nicm     2541: static void
1.208     nicm     2542: window_copy_clear_selection(struct window_mode_entry *wme)
1.47      nicm     2543: {
1.208     nicm     2544:        struct window_copy_mode_data   *data = wme->data;
1.47      nicm     2545:        u_int                           px, py;
                   2546:
                   2547:        screen_clear_selection(&data->screen);
                   2548:
1.161     nicm     2549:        data->cursordrag = CURSORDRAG_NONE;
1.197     nicm     2550:        data->lineflag = LINE_SEL_NONE;
1.161     nicm     2551:
1.54      nicm     2552:        py = screen_hsize(data->backing) + data->cy - data->oy;
1.208     nicm     2553:        px = window_copy_find_length(wme, py);
1.47      nicm     2554:        if (data->cx > px)
1.208     nicm     2555:                window_copy_update_cursor(wme, px, data->cy);
1.47      nicm     2556: }
                   2557:
1.157     nicm     2558: static int
1.208     nicm     2559: window_copy_in_set(struct window_mode_entry *wme, u_int px, u_int py,
                   2560:     const char *set)
1.1       nicm     2561: {
1.208     nicm     2562:        struct window_copy_mode_data    *data = wme->data;
1.140     nicm     2563:        struct grid_cell                 gc;
                   2564:        const struct utf8_data          *ud;
1.204     nicm     2565:        struct utf8_data                *copy;
                   2566:        struct utf8_data                *loop;
                   2567:        int                              found = 0;
1.140     nicm     2568:
                   2569:        grid_get_cell(data->backing->grid, px, py, &gc);
1.204     nicm     2570:        if (gc.flags & GRID_FLAG_PADDING)
                   2571:                return (0);
                   2572:        ud = &gc.data;
1.1       nicm     2573:
1.204     nicm     2574:        copy = utf8_fromcstr(set);
                   2575:        for (loop = copy; loop->size != 0; loop++) {
                   2576:                if (loop->size != ud->size)
                   2577:                        continue;
                   2578:                if (memcmp(loop->data, ud->data, loop->size) == 0) {
                   2579:                        found = 1;
                   2580:                        break;
                   2581:                }
                   2582:        }
                   2583:        free(copy);
                   2584:
                   2585:        return (found);
1.1       nicm     2586: }
                   2587:
1.157     nicm     2588: static u_int
1.208     nicm     2589: window_copy_find_length(struct window_mode_entry *wme, u_int py)
1.1       nicm     2590: {
1.208     nicm     2591:        struct window_copy_mode_data    *data = wme->data;
1.54      nicm     2592:        struct screen                   *s = data->backing;
1.140     nicm     2593:        struct grid_cell                 gc;
1.54      nicm     2594:        u_int                            px;
1.1       nicm     2595:
1.4       nicm     2596:        /*
                   2597:         * If the pane has been resized, its grid can contain old overlong
                   2598:         * lines. grid_peek_cell does not allow accessing cells beyond the
                   2599:         * width of the grid, and screen_write_copy treats them as spaces, so
                   2600:         * ignore them here too.
                   2601:         */
1.190     nicm     2602:        px = grid_get_line(s->grid, py)->cellsize;
1.54      nicm     2603:        if (px > screen_size_x(s))
                   2604:                px = screen_size_x(s);
1.1       nicm     2605:        while (px > 0) {
1.140     nicm     2606:                grid_get_cell(s->grid, px - 1, py, &gc);
                   2607:                if (gc.data.size != 1 || *gc.data.data != ' ')
1.1       nicm     2608:                        break;
                   2609:                px--;
                   2610:        }
                   2611:        return (px);
                   2612: }
                   2613:
1.157     nicm     2614: static void
1.208     nicm     2615: window_copy_cursor_start_of_line(struct window_mode_entry *wme)
1.5       nicm     2616: {
1.208     nicm     2617:        struct window_copy_mode_data    *data = wme->data;
1.58      nicm     2618:        struct screen                   *back_s = data->backing;
                   2619:        struct grid                     *gd = back_s->grid;
                   2620:        u_int                            py;
                   2621:
1.192     nicm     2622:        if (data->cx == 0 && data->lineflag == LINE_SEL_NONE) {
1.58      nicm     2623:                py = screen_hsize(back_s) + data->cy - data->oy;
1.118     nicm     2624:                while (py > 0 &&
1.190     nicm     2625:                    grid_get_line(gd, py - 1)->flags & GRID_LINE_WRAPPED) {
1.208     nicm     2626:                        window_copy_cursor_up(wme, 0);
1.58      nicm     2627:                        py = screen_hsize(back_s) + data->cy - data->oy;
                   2628:                }
                   2629:        }
1.208     nicm     2630:        window_copy_update_cursor(wme, 0, data->cy);
                   2631:        if (window_copy_update_selection(wme, 1))
                   2632:                window_copy_redraw_lines(wme, data->cy, 1);
1.6       nicm     2633: }
                   2634:
1.157     nicm     2635: static void
1.208     nicm     2636: window_copy_cursor_back_to_indentation(struct window_mode_entry *wme)
1.6       nicm     2637: {
1.208     nicm     2638:        struct window_copy_mode_data    *data = wme->data;
1.6       nicm     2639:        u_int                            px, py, xx;
1.140     nicm     2640:        struct grid_cell                 gc;
1.6       nicm     2641:
                   2642:        px = 0;
1.54      nicm     2643:        py = screen_hsize(data->backing) + data->cy - data->oy;
1.208     nicm     2644:        xx = window_copy_find_length(wme, py);
1.6       nicm     2645:
                   2646:        while (px < xx) {
1.140     nicm     2647:                grid_get_cell(data->backing->grid, px, py, &gc);
                   2648:                if (gc.data.size != 1 || *gc.data.data != ' ')
1.6       nicm     2649:                        break;
                   2650:                px++;
                   2651:        }
                   2652:
1.208     nicm     2653:        window_copy_update_cursor(wme, px, data->cy);
                   2654:        if (window_copy_update_selection(wme, 1))
                   2655:                window_copy_redraw_lines(wme, data->cy, 1);
1.5       nicm     2656: }
                   2657:
1.157     nicm     2658: static void
1.208     nicm     2659: window_copy_cursor_end_of_line(struct window_mode_entry *wme)
1.5       nicm     2660: {
1.208     nicm     2661:        struct window_copy_mode_data    *data = wme->data;
1.54      nicm     2662:        struct screen                   *back_s = data->backing;
                   2663:        struct grid                     *gd = back_s->grid;
1.190     nicm     2664:        struct grid_line                *gl;
1.5       nicm     2665:        u_int                            px, py;
                   2666:
1.54      nicm     2667:        py = screen_hsize(back_s) + data->cy - data->oy;
1.208     nicm     2668:        px = window_copy_find_length(wme, py);
1.5       nicm     2669:
1.192     nicm     2670:        if (data->cx == px && data->lineflag == LINE_SEL_NONE) {
                   2671:                if (data->screen.sel != NULL && data->rectflag)
1.54      nicm     2672:                        px = screen_size_x(back_s);
1.190     nicm     2673:                gl = grid_get_line(gd, py);
                   2674:                if (gl->flags & GRID_LINE_WRAPPED) {
                   2675:                        while (py < gd->sy + gd->hsize) {
                   2676:                                gl = grid_get_line(gd, py);
                   2677:                                if (~gl->flags & GRID_LINE_WRAPPED)
                   2678:                                        break;
1.208     nicm     2679:                                window_copy_cursor_down(wme, 0);
1.190     nicm     2680:                                py = screen_hsize(back_s) + data->cy - data->oy;
1.49      nicm     2681:                        }
1.208     nicm     2682:                        px = window_copy_find_length(wme, py);
1.49      nicm     2683:                }
                   2684:        }
1.208     nicm     2685:        window_copy_update_cursor(wme, px, data->cy);
1.49      nicm     2686:
1.208     nicm     2687:        if (window_copy_update_selection(wme, 1))
                   2688:                window_copy_redraw_lines(wme, data->cy, 1);
1.95      nicm     2689: }
                   2690:
1.157     nicm     2691: static void
1.208     nicm     2692: window_copy_other_end(struct window_mode_entry *wme)
1.95      nicm     2693: {
1.208     nicm     2694:        struct window_copy_mode_data    *data = wme->data;
1.95      nicm     2695:        struct screen                   *s = &data->screen;
1.161     nicm     2696:        u_int                            selx, sely, cy, yy, hsize;
1.95      nicm     2697:
1.192     nicm     2698:        if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
1.95      nicm     2699:                return;
                   2700:
1.192     nicm     2701:        if (data->lineflag == LINE_SEL_LEFT_RIGHT)
                   2702:                data->lineflag = LINE_SEL_RIGHT_LEFT;
                   2703:        else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
                   2704:                data->lineflag = LINE_SEL_LEFT_RIGHT;
1.118     nicm     2705:
1.161     nicm     2706:        switch (data->cursordrag) {
                   2707:                case CURSORDRAG_NONE:
                   2708:                case CURSORDRAG_SEL:
                   2709:                        data->cursordrag = CURSORDRAG_ENDSEL;
                   2710:                        break;
                   2711:                case CURSORDRAG_ENDSEL:
                   2712:                        data->cursordrag = CURSORDRAG_SEL;
                   2713:                        break;
                   2714:        }
                   2715:
                   2716:        selx = data->endselx;
                   2717:        sely = data->endsely;
                   2718:        if (data->cursordrag == CURSORDRAG_SEL) {
                   2719:                selx = data->selx;
                   2720:                sely = data->sely;
                   2721:        }
                   2722:
1.95      nicm     2723:        cy = data->cy;
                   2724:        yy = screen_hsize(data->backing) + data->cy - data->oy;
                   2725:
                   2726:        data->cx = selx;
                   2727:
1.122     nicm     2728:        hsize = screen_hsize(data->backing);
1.161     nicm     2729:        if (sely < hsize - data->oy) { /* above */
1.122     nicm     2730:                data->oy = hsize - sely;
1.95      nicm     2731:                data->cy = 0;
1.161     nicm     2732:        } else if (sely > hsize - data->oy + screen_size_y(s)) { /* below */
1.122     nicm     2733:                data->oy = hsize - sely + screen_size_y(s) - 1;
1.95      nicm     2734:                data->cy = screen_size_y(s) - 1;
                   2735:        } else
                   2736:                data->cy = cy + sely - yy;
                   2737:
1.208     nicm     2738:        window_copy_update_selection(wme, 1);
                   2739:        window_copy_redraw_screen(wme);
1.5       nicm     2740: }
                   2741:
1.157     nicm     2742: static void
1.208     nicm     2743: window_copy_cursor_left(struct window_mode_entry *wme)
1.1       nicm     2744: {
1.208     nicm     2745:        struct window_copy_mode_data    *data = wme->data;
1.168     nicm     2746:        u_int                            py, cx;
                   2747:        struct grid_cell                 gc;
1.1       nicm     2748:
1.145     nicm     2749:        py = screen_hsize(data->backing) + data->cy - data->oy;
1.168     nicm     2750:        cx = data->cx;
                   2751:        while (cx > 0) {
                   2752:                grid_get_cell(data->backing->grid, cx, py, &gc);
                   2753:                if (~gc.flags & GRID_FLAG_PADDING)
                   2754:                        break;
                   2755:                cx--;
                   2756:        }
                   2757:        if (cx == 0 && py > 0) {
1.208     nicm     2758:                window_copy_cursor_up(wme, 0);
                   2759:                window_copy_cursor_end_of_line(wme);
1.168     nicm     2760:        } else if (cx > 0) {
1.208     nicm     2761:                window_copy_update_cursor(wme, cx - 1, data->cy);
                   2762:                if (window_copy_update_selection(wme, 1))
                   2763:                        window_copy_redraw_lines(wme, data->cy, 1);
1.1       nicm     2764:        }
                   2765: }
                   2766:
1.157     nicm     2767: static void
1.208     nicm     2768: window_copy_cursor_right(struct window_mode_entry *wme)
1.1       nicm     2769: {
1.208     nicm     2770:        struct window_copy_mode_data    *data = wme->data;
1.168     nicm     2771:        u_int                            px, py, yy, cx, cy;
                   2772:        struct grid_cell                 gc;
1.1       nicm     2773:
1.145     nicm     2774:        py = screen_hsize(data->backing) + data->cy - data->oy;
                   2775:        yy = screen_hsize(data->backing) + screen_size_y(data->backing) - 1;
1.192     nicm     2776:        if (data->screen.sel != NULL && data->rectflag)
1.47      nicm     2777:                px = screen_size_x(&data->screen);
1.168     nicm     2778:        else
1.208     nicm     2779:                px = window_copy_find_length(wme, py);
1.1       nicm     2780:
1.145     nicm     2781:        if (data->cx >= px && py < yy) {
1.208     nicm     2782:                window_copy_cursor_start_of_line(wme);
                   2783:                window_copy_cursor_down(wme, 0);
1.145     nicm     2784:        } else if (data->cx < px) {
1.168     nicm     2785:                cx = data->cx + 1;
                   2786:                cy = screen_hsize(data->backing) + data->cy - data->oy;
                   2787:                while (cx < px) {
                   2788:                        grid_get_cell(data->backing->grid, cx, cy, &gc);
                   2789:                        if (~gc.flags & GRID_FLAG_PADDING)
                   2790:                                break;
                   2791:                        cx++;
                   2792:                }
1.208     nicm     2793:                window_copy_update_cursor(wme, cx, data->cy);
                   2794:                if (window_copy_update_selection(wme, 1))
                   2795:                        window_copy_redraw_lines(wme, data->cy, 1);
1.1       nicm     2796:        }
                   2797: }
                   2798:
1.157     nicm     2799: static void
1.208     nicm     2800: window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only)
1.1       nicm     2801: {
1.208     nicm     2802:        struct window_copy_mode_data    *data = wme->data;
1.36      nicm     2803:        struct screen                   *s = &data->screen;
1.1       nicm     2804:        u_int                            ox, oy, px, py;
                   2805:
1.54      nicm     2806:        oy = screen_hsize(data->backing) + data->cy - data->oy;
1.208     nicm     2807:        ox = window_copy_find_length(wme, oy);
1.77      nicm     2808:        if (data->cx != ox) {
1.25      nicm     2809:                data->lastcx = data->cx;
                   2810:                data->lastsx = ox;
                   2811:        }
1.1       nicm     2812:
1.192     nicm     2813:        if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
1.208     nicm     2814:                window_copy_other_end(wme);
1.118     nicm     2815:
1.25      nicm     2816:        data->cx = data->lastcx;
1.28      nicm     2817:        if (scroll_only || data->cy == 0) {
1.208     nicm     2818:                window_copy_scroll_down(wme, 1);
1.36      nicm     2819:                if (scroll_only) {
                   2820:                        if (data->cy == screen_size_y(s) - 1)
1.208     nicm     2821:                                window_copy_redraw_lines(wme, data->cy, 1);
1.36      nicm     2822:                        else
1.208     nicm     2823:                                window_copy_redraw_lines(wme, data->cy, 2);
1.36      nicm     2824:                }
1.28      nicm     2825:        } else {
1.208     nicm     2826:                window_copy_update_cursor(wme, data->cx, data->cy - 1);
                   2827:                if (window_copy_update_selection(wme, 1)) {
1.36      nicm     2828:                        if (data->cy == screen_size_y(s) - 1)
1.208     nicm     2829:                                window_copy_redraw_lines(wme, data->cy, 1);
1.36      nicm     2830:                        else
1.208     nicm     2831:                                window_copy_redraw_lines(wme, data->cy, 2);
1.36      nicm     2832:                }
1.1       nicm     2833:        }
                   2834:
1.198     nicm     2835:        if (data->screen.sel == NULL || !data->rectflag) {
1.54      nicm     2836:                py = screen_hsize(data->backing) + data->cy - data->oy;
1.208     nicm     2837:                px = window_copy_find_length(wme, py);
1.49      nicm     2838:                if ((data->cx >= data->lastsx && data->cx != px) ||
                   2839:                    data->cx > px)
1.208     nicm     2840:                        window_copy_cursor_end_of_line(wme);
1.47      nicm     2841:        }
1.118     nicm     2842:
1.192     nicm     2843:        if (data->lineflag == LINE_SEL_LEFT_RIGHT)
1.208     nicm     2844:                window_copy_cursor_end_of_line(wme);
1.192     nicm     2845:        else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
1.208     nicm     2846:                window_copy_cursor_start_of_line(wme);
1.1       nicm     2847: }
                   2848:
1.157     nicm     2849: static void
1.208     nicm     2850: window_copy_cursor_down(struct window_mode_entry *wme, int scroll_only)
1.1       nicm     2851: {
1.208     nicm     2852:        struct window_copy_mode_data    *data = wme->data;
1.1       nicm     2853:        struct screen                   *s = &data->screen;
                   2854:        u_int                            ox, oy, px, py;
                   2855:
1.54      nicm     2856:        oy = screen_hsize(data->backing) + data->cy - data->oy;
1.208     nicm     2857:        ox = window_copy_find_length(wme, oy);
1.77      nicm     2858:        if (data->cx != ox) {
1.25      nicm     2859:                data->lastcx = data->cx;
                   2860:                data->lastsx = ox;
                   2861:        }
1.1       nicm     2862:
1.192     nicm     2863:        if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
1.208     nicm     2864:                window_copy_other_end(wme);
1.118     nicm     2865:
1.25      nicm     2866:        data->cx = data->lastcx;
1.28      nicm     2867:        if (scroll_only || data->cy == screen_size_y(s) - 1) {
1.208     nicm     2868:                window_copy_scroll_up(wme, 1);
1.31      nicm     2869:                if (scroll_only && data->cy > 0)
1.208     nicm     2870:                        window_copy_redraw_lines(wme, data->cy - 1, 2);
1.28      nicm     2871:        } else {
1.208     nicm     2872:                window_copy_update_cursor(wme, data->cx, data->cy + 1);
                   2873:                if (window_copy_update_selection(wme, 1))
                   2874:                        window_copy_redraw_lines(wme, data->cy - 1, 2);
1.1       nicm     2875:        }
                   2876:
1.192     nicm     2877:        if (data->screen.sel == NULL || !data->rectflag) {
1.54      nicm     2878:                py = screen_hsize(data->backing) + data->cy - data->oy;
1.208     nicm     2879:                px = window_copy_find_length(wme, py);
1.49      nicm     2880:                if ((data->cx >= data->lastsx && data->cx != px) ||
                   2881:                    data->cx > px)
1.208     nicm     2882:                        window_copy_cursor_end_of_line(wme);
1.52      nicm     2883:        }
1.118     nicm     2884:
1.192     nicm     2885:        if (data->lineflag == LINE_SEL_LEFT_RIGHT)
1.208     nicm     2886:                window_copy_cursor_end_of_line(wme);
1.192     nicm     2887:        else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
1.208     nicm     2888:                window_copy_cursor_start_of_line(wme);
1.52      nicm     2889: }
                   2890:
1.157     nicm     2891: static void
1.208     nicm     2892: window_copy_cursor_jump(struct window_mode_entry *wme)
1.52      nicm     2893: {
1.208     nicm     2894:        struct window_copy_mode_data    *data = wme->data;
1.54      nicm     2895:        struct screen                   *back_s = data->backing;
1.140     nicm     2896:        struct grid_cell                 gc;
1.67      nicm     2897:        u_int                            px, py, xx;
1.52      nicm     2898:
                   2899:        px = data->cx + 1;
1.54      nicm     2900:        py = screen_hsize(back_s) + data->cy - data->oy;
1.208     nicm     2901:        xx = window_copy_find_length(wme, py);
1.52      nicm     2902:
                   2903:        while (px < xx) {
1.140     nicm     2904:                grid_get_cell(back_s->grid, px, py, &gc);
                   2905:                if (!(gc.flags & GRID_FLAG_PADDING) &&
                   2906:                    gc.data.size == 1 && *gc.data.data == data->jumpchar) {
1.208     nicm     2907:                        window_copy_update_cursor(wme, px, data->cy);
                   2908:                        if (window_copy_update_selection(wme, 1))
                   2909:                                window_copy_redraw_lines(wme, data->cy, 1);
1.52      nicm     2910:                        return;
                   2911:                }
                   2912:                px++;
                   2913:        }
                   2914: }
                   2915:
1.157     nicm     2916: static void
1.208     nicm     2917: window_copy_cursor_jump_back(struct window_mode_entry *wme)
1.52      nicm     2918: {
1.208     nicm     2919:        struct window_copy_mode_data    *data = wme->data;
1.54      nicm     2920:        struct screen                   *back_s = data->backing;
1.140     nicm     2921:        struct grid_cell                 gc;
1.67      nicm     2922:        u_int                            px, py;
1.52      nicm     2923:
                   2924:        px = data->cx;
1.54      nicm     2925:        py = screen_hsize(back_s) + data->cy - data->oy;
1.52      nicm     2926:
                   2927:        if (px > 0)
                   2928:                px--;
                   2929:
                   2930:        for (;;) {
1.140     nicm     2931:                grid_get_cell(back_s->grid, px, py, &gc);
                   2932:                if (!(gc.flags & GRID_FLAG_PADDING) &&
                   2933:                    gc.data.size == 1 && *gc.data.data == data->jumpchar) {
1.208     nicm     2934:                        window_copy_update_cursor(wme, px, data->cy);
                   2935:                        if (window_copy_update_selection(wme, 1))
                   2936:                                window_copy_redraw_lines(wme, data->cy, 1);
1.76      nicm     2937:                        return;
                   2938:                }
                   2939:                if (px == 0)
                   2940:                        break;
                   2941:                px--;
                   2942:        }
                   2943: }
                   2944:
1.157     nicm     2945: static void
1.208     nicm     2946: window_copy_cursor_jump_to(struct window_mode_entry *wme)
1.76      nicm     2947: {
1.208     nicm     2948:        struct window_copy_mode_data    *data = wme->data;
1.76      nicm     2949:        struct screen                   *back_s = data->backing;
1.140     nicm     2950:        struct grid_cell                 gc;
1.76      nicm     2951:        u_int                            px, py, xx;
                   2952:
1.184     nicm     2953:        px = data->cx + 2;
1.76      nicm     2954:        py = screen_hsize(back_s) + data->cy - data->oy;
1.208     nicm     2955:        xx = window_copy_find_length(wme, py);
1.76      nicm     2956:
                   2957:        while (px < xx) {
1.140     nicm     2958:                grid_get_cell(back_s->grid, px, py, &gc);
                   2959:                if (!(gc.flags & GRID_FLAG_PADDING) &&
                   2960:                    gc.data.size == 1 && *gc.data.data == data->jumpchar) {
1.208     nicm     2961:                        window_copy_update_cursor(wme, px - 1, data->cy);
                   2962:                        if (window_copy_update_selection(wme, 1))
                   2963:                                window_copy_redraw_lines(wme, data->cy, 1);
1.76      nicm     2964:                        return;
                   2965:                }
                   2966:                px++;
                   2967:        }
                   2968: }
                   2969:
1.157     nicm     2970: static void
1.208     nicm     2971: window_copy_cursor_jump_to_back(struct window_mode_entry *wme)
1.76      nicm     2972: {
1.208     nicm     2973:        struct window_copy_mode_data    *data = wme->data;
1.76      nicm     2974:        struct screen                   *back_s = data->backing;
1.140     nicm     2975:        struct grid_cell                 gc;
1.76      nicm     2976:        u_int                            px, py;
                   2977:
                   2978:        px = data->cx;
                   2979:        py = screen_hsize(back_s) + data->cy - data->oy;
                   2980:
                   2981:        if (px > 0)
1.127     nicm     2982:                px--;
                   2983:
1.184     nicm     2984:        if (px > 0)
1.76      nicm     2985:                px--;
                   2986:
                   2987:        for (;;) {
1.140     nicm     2988:                grid_get_cell(back_s->grid, px, py, &gc);
                   2989:                if (!(gc.flags & GRID_FLAG_PADDING) &&
                   2990:                    gc.data.size == 1 && *gc.data.data == data->jumpchar) {
1.208     nicm     2991:                        window_copy_update_cursor(wme, px + 1, data->cy);
                   2992:                        if (window_copy_update_selection(wme, 1))
                   2993:                                window_copy_redraw_lines(wme, data->cy, 1);
1.52      nicm     2994:                        return;
                   2995:                }
                   2996:                if (px == 0)
                   2997:                        break;
                   2998:                px--;
1.47      nicm     2999:        }
1.1       nicm     3000: }
                   3001:
1.157     nicm     3002: static void
1.208     nicm     3003: window_copy_cursor_next_word(struct window_mode_entry *wme,
                   3004:     const char *separators)
1.40      nicm     3005: {
1.208     nicm     3006:        struct window_copy_mode_data    *data = wme->data;
1.54      nicm     3007:        struct screen                   *back_s = data->backing;
1.40      nicm     3008:        u_int                            px, py, xx, yy;
1.48      nicm     3009:        int                              expected = 0;
1.40      nicm     3010:
                   3011:        px = data->cx;
1.54      nicm     3012:        py = screen_hsize(back_s) + data->cy - data->oy;
1.208     nicm     3013:        xx = window_copy_find_length(wme, py);
1.54      nicm     3014:        yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
1.40      nicm     3015:
1.48      nicm     3016:        /*
                   3017:         * First skip past any nonword characters and then any word characters.
                   3018:         *
                   3019:         * expected is initially set to 0 for the former and then 1 for the
                   3020:         * latter.
                   3021:         */
                   3022:        do {
                   3023:                while (px > xx ||
1.208     nicm     3024:                    window_copy_in_set(wme, px, py, separators) == expected) {
1.48      nicm     3025:                        /* Move down if we're past the end of the line. */
                   3026:                        if (px > xx) {
                   3027:                                if (py == yy)
                   3028:                                        return;
1.208     nicm     3029:                                window_copy_cursor_down(wme, 0);
1.48      nicm     3030:                                px = 0;
                   3031:
1.54      nicm     3032:                                py = screen_hsize(back_s) + data->cy - data->oy;
1.208     nicm     3033:                                xx = window_copy_find_length(wme, py);
1.48      nicm     3034:                        } else
                   3035:                                px++;
                   3036:                }
                   3037:                expected = !expected;
                   3038:        } while (expected == 1);
1.40      nicm     3039:
1.208     nicm     3040:        window_copy_update_cursor(wme, px, data->cy);
                   3041:        if (window_copy_update_selection(wme, 1))
                   3042:                window_copy_redraw_lines(wme, data->cy, 1);
1.40      nicm     3043: }
                   3044:
1.157     nicm     3045: static void
1.208     nicm     3046: window_copy_cursor_next_word_end(struct window_mode_entry *wme,
1.106     nicm     3047:     const char *separators)
1.1       nicm     3048: {
1.208     nicm     3049:        struct window_pane              *wp = wme->wp;
                   3050:        struct window_copy_mode_data    *data = wme->data;
1.136     nicm     3051:        struct options                  *oo = wp->window->options;
1.54      nicm     3052:        struct screen                   *back_s = data->backing;
1.39      nicm     3053:        u_int                            px, py, xx, yy;
1.94      nicm     3054:        int                              keys, expected = 1;
1.1       nicm     3055:
1.18      nicm     3056:        px = data->cx;
1.54      nicm     3057:        py = screen_hsize(back_s) + data->cy - data->oy;
1.208     nicm     3058:        xx = window_copy_find_length(wme, py);
1.54      nicm     3059:        yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
1.1       nicm     3060:
1.94      nicm     3061:        keys = options_get_number(oo, "mode-keys");
1.208     nicm     3062:        if (keys == MODEKEY_VI && !window_copy_in_set(wme, px, py, separators))
1.94      nicm     3063:                px++;
                   3064:
1.48      nicm     3065:        /*
                   3066:         * First skip past any word characters, then any nonword characters.
                   3067:         *
                   3068:         * expected is initially set to 1 for the former and then 0 for the
                   3069:         * latter.
                   3070:         */
                   3071:        do {
                   3072:                while (px > xx ||
1.208     nicm     3073:                    window_copy_in_set(wme, px, py, separators) == expected) {
1.48      nicm     3074:                        /* Move down if we're past the end of the line. */
                   3075:                        if (px > xx) {
                   3076:                                if (py == yy)
                   3077:                                        return;
1.208     nicm     3078:                                window_copy_cursor_down(wme, 0);
1.48      nicm     3079:                                px = 0;
                   3080:
1.54      nicm     3081:                                py = screen_hsize(back_s) + data->cy - data->oy;
1.208     nicm     3082:                                xx = window_copy_find_length(wme, py);
1.48      nicm     3083:                        } else
                   3084:                                px++;
                   3085:                }
                   3086:                expected = !expected;
                   3087:        } while (expected == 0);
1.92      nicm     3088:
1.94      nicm     3089:        if (keys == MODEKEY_VI && px != 0)
1.92      nicm     3090:                px--;
1.18      nicm     3091:
1.208     nicm     3092:        window_copy_update_cursor(wme, px, data->cy);
                   3093:        if (window_copy_update_selection(wme, 1))
                   3094:                window_copy_redraw_lines(wme, data->cy, 1);
1.1       nicm     3095: }
                   3096:
1.8       nicm     3097: /* Move to the previous place where a word begins. */
1.157     nicm     3098: static void
1.208     nicm     3099: window_copy_cursor_previous_word(struct window_mode_entry *wme,
1.106     nicm     3100:     const char *separators)
1.1       nicm     3101: {
1.208     nicm     3102:        struct window_copy_mode_data    *data = wme->data;
1.8       nicm     3103:        u_int                            px, py;
1.1       nicm     3104:
1.18      nicm     3105:        px = data->cx;
1.54      nicm     3106:        py = screen_hsize(data->backing) + data->cy - data->oy;
1.1       nicm     3107:
1.8       nicm     3108:        /* Move back to the previous word character. */
1.1       nicm     3109:        for (;;) {
1.8       nicm     3110:                if (px > 0) {
                   3111:                        px--;
1.208     nicm     3112:                        if (!window_copy_in_set(wme, px, py, separators))
1.1       nicm     3113:                                break;
1.8       nicm     3114:                } else {
                   3115:                        if (data->cy == 0 &&
1.54      nicm     3116:                            (screen_hsize(data->backing) == 0 ||
                   3117:                            data->oy >= screen_hsize(data->backing) - 1))
1.8       nicm     3118:                                goto out;
1.208     nicm     3119:                        window_copy_cursor_up(wme, 0);
1.1       nicm     3120:
1.54      nicm     3121:                        py = screen_hsize(data->backing) + data->cy - data->oy;
1.208     nicm     3122:                        px = window_copy_find_length(wme, py);
1.1       nicm     3123:                }
1.8       nicm     3124:        }
1.1       nicm     3125:
1.8       nicm     3126:        /* Move back to the beginning of this word. */
1.208     nicm     3127:        while (px > 0 && !window_copy_in_set(wme, px - 1, py, separators))
1.1       nicm     3128:                px--;
1.8       nicm     3129:
1.1       nicm     3130: out:
1.208     nicm     3131:        window_copy_update_cursor(wme, px, data->cy);
                   3132:        if (window_copy_update_selection(wme, 1))
                   3133:                window_copy_redraw_lines(wme, data->cy, 1);
1.1       nicm     3134: }
                   3135:
1.157     nicm     3136: static void
1.208     nicm     3137: window_copy_scroll_up(struct window_mode_entry *wme, u_int ny)
1.1       nicm     3138: {
1.208     nicm     3139:        struct window_pane              *wp = wme->wp;
                   3140:        struct window_copy_mode_data    *data = wme->data;
1.1       nicm     3141:        struct screen                   *s = &data->screen;
                   3142:        struct screen_write_ctx          ctx;
                   3143:
                   3144:        if (data->oy < ny)
                   3145:                ny = data->oy;
                   3146:        if (ny == 0)
                   3147:                return;
                   3148:        data->oy -= ny;
                   3149:
1.208     nicm     3150:        window_copy_update_selection(wme, 0);
1.96      nicm     3151:
1.1       nicm     3152:        screen_write_start(&ctx, wp, NULL);
1.212     nicm     3153:        screen_write_cursormove(&ctx, 0, 0, 0);
1.159     nicm     3154:        screen_write_deleteline(&ctx, ny, 8);
1.208     nicm     3155:        window_copy_write_lines(wme, &ctx, screen_size_y(s) - ny, ny);
                   3156:        window_copy_write_line(wme, &ctx, 0);
1.31      nicm     3157:        if (screen_size_y(s) > 1)
1.208     nicm     3158:                window_copy_write_line(wme, &ctx, 1);
1.31      nicm     3159:        if (screen_size_y(s) > 3)
1.208     nicm     3160:                window_copy_write_line(wme, &ctx, screen_size_y(s) - 2);
1.192     nicm     3161:        if (s->sel != NULL && screen_size_y(s) > ny)
1.208     nicm     3162:                window_copy_write_line(wme, &ctx, screen_size_y(s) - ny - 1);
1.212     nicm     3163:        screen_write_cursormove(&ctx, data->cx, data->cy, 0);
1.1       nicm     3164:        screen_write_stop(&ctx);
                   3165: }
                   3166:
1.157     nicm     3167: static void
1.208     nicm     3168: window_copy_scroll_down(struct window_mode_entry *wme, u_int ny)
1.1       nicm     3169: {
1.208     nicm     3170:        struct window_pane              *wp = wme->wp;
                   3171:        struct window_copy_mode_data    *data = wme->data;
1.1       nicm     3172:        struct screen                   *s = &data->screen;
                   3173:        struct screen_write_ctx          ctx;
                   3174:
1.54      nicm     3175:        if (ny > screen_hsize(data->backing))
1.1       nicm     3176:                return;
                   3177:
1.54      nicm     3178:        if (data->oy > screen_hsize(data->backing) - ny)
                   3179:                ny = screen_hsize(data->backing) - data->oy;
1.1       nicm     3180:        if (ny == 0)
                   3181:                return;
                   3182:        data->oy += ny;
                   3183:
1.208     nicm     3184:        window_copy_update_selection(wme, 0);
1.96      nicm     3185:
1.1       nicm     3186:        screen_write_start(&ctx, wp, NULL);
1.212     nicm     3187:        screen_write_cursormove(&ctx, 0, 0, 0);
1.159     nicm     3188:        screen_write_insertline(&ctx, ny, 8);
1.208     nicm     3189:        window_copy_write_lines(wme, &ctx, 0, ny);
1.192     nicm     3190:        if (s->sel != NULL && screen_size_y(s) > ny)
1.208     nicm     3191:                window_copy_write_line(wme, &ctx, ny);
1.96      nicm     3192:        else if (ny == 1) /* nuke position */
1.208     nicm     3193:                window_copy_write_line(wme, &ctx, 1);
1.212     nicm     3194:        screen_write_cursormove(&ctx, data->cx, data->cy, 0);
1.1       nicm     3195:        screen_write_stop(&ctx);
                   3196: }
1.42      nicm     3197:
1.157     nicm     3198: static void
1.208     nicm     3199: window_copy_rectangle_toggle(struct window_mode_entry *wme)
1.42      nicm     3200: {
1.208     nicm     3201:        struct window_copy_mode_data    *data = wme->data;
1.47      nicm     3202:        u_int                            px, py;
1.42      nicm     3203:
                   3204:        data->rectflag = !data->rectflag;
1.47      nicm     3205:
1.54      nicm     3206:        py = screen_hsize(data->backing) + data->cy - data->oy;
1.208     nicm     3207:        px = window_copy_find_length(wme, py);
1.47      nicm     3208:        if (data->cx > px)
1.208     nicm     3209:                window_copy_update_cursor(wme, px, data->cy);
1.42      nicm     3210:
1.208     nicm     3211:        window_copy_update_selection(wme, 1);
                   3212:        window_copy_redraw_screen(wme);
1.156     nicm     3213: }
                   3214:
1.157     nicm     3215: static void
1.156     nicm     3216: window_copy_move_mouse(struct mouse_event *m)
                   3217: {
1.211     nicm     3218:        struct window_pane              *wp;
                   3219:        struct window_mode_entry        *wme;
                   3220:        u_int                            x, y;
1.156     nicm     3221:
                   3222:        wp = cmd_mouse_pane(m, NULL, NULL);
1.211     nicm     3223:        if (wp == NULL)
                   3224:                return;
                   3225:        wme = TAILQ_FIRST(&wp->modes);
                   3226:        if (wme == NULL || wme->mode != &window_copy_mode)
1.156     nicm     3227:                return;
                   3228:
1.183     nicm     3229:        if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
1.156     nicm     3230:                return;
                   3231:
1.211     nicm     3232:        window_copy_update_cursor(wme, x, y);
1.126     nicm     3233: }
                   3234:
                   3235: void
1.141     nicm     3236: window_copy_start_drag(struct client *c, struct mouse_event *m)
1.126     nicm     3237: {
1.211     nicm     3238:        struct window_pane              *wp;
                   3239:        struct window_mode_entry        *wme;
                   3240:        u_int                            x, y;
1.126     nicm     3241:
1.155     nicm     3242:        if (c == NULL)
                   3243:                return;
                   3244:
1.126     nicm     3245:        wp = cmd_mouse_pane(m, NULL, NULL);
1.211     nicm     3246:        if (wp == NULL)
                   3247:                return;
                   3248:        wme = TAILQ_FIRST(&wp->modes);
                   3249:        if (wme == NULL || wme->mode != &window_copy_mode)
1.126     nicm     3250:                return;
                   3251:
                   3252:        if (cmd_mouse_at(wp, m, &x, &y, 1) != 0)
                   3253:                return;
                   3254:
                   3255:        c->tty.mouse_drag_update = window_copy_drag_update;
1.155     nicm     3256:        c->tty.mouse_drag_release = NULL; /* will fire MouseDragEnd key */
1.126     nicm     3257:
1.211     nicm     3258:        window_copy_update_cursor(wme, x, y);
                   3259:        window_copy_start_selection(wme);
                   3260:        window_copy_redraw_screen(wme);
1.126     nicm     3261: }
                   3262:
1.157     nicm     3263: static void
1.211     nicm     3264: window_copy_drag_update(struct client *c, struct mouse_event *m)
1.126     nicm     3265: {
                   3266:        struct window_pane              *wp;
1.211     nicm     3267:        struct window_mode_entry        *wme;
1.126     nicm     3268:        struct window_copy_mode_data    *data;
                   3269:        u_int                            x, y, old_cy;
                   3270:
1.211     nicm     3271:        if (c == NULL)
                   3272:                return;
                   3273:
1.126     nicm     3274:        wp = cmd_mouse_pane(m, NULL, NULL);
1.211     nicm     3275:        if (wp == NULL)
1.126     nicm     3276:                return;
1.211     nicm     3277:        wme = TAILQ_FIRST(&wp->modes);
                   3278:        if (wme == NULL || wme->mode != &window_copy_mode)
                   3279:                return;
                   3280:        data = wme->data;
1.126     nicm     3281:
                   3282:        if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
                   3283:                return;
                   3284:        old_cy = data->cy;
                   3285:
1.211     nicm     3286:        window_copy_update_cursor(wme, x, y);
                   3287:        if (window_copy_update_selection(wme, 1))
                   3288:                window_copy_redraw_selection(wme, old_cy);
1.42      nicm     3289: }