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

1.1     ! nicm        1: /* $OpenBSD$ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
        !            15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
        !            16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18:
        !            19: #include <sys/types.h>
        !            20:
        !            21: #include <string.h>
        !            22:
        !            23: #include "tmux.h"
        !            24:
        !            25: struct screen *window_copy_init(struct window_pane *);
        !            26: void   window_copy_free(struct window_pane *);
        !            27: void   window_copy_resize(struct window_pane *, u_int, u_int);
        !            28: void   window_copy_key(struct window_pane *, struct client *, int);
        !            29: void   window_copy_mouse(
        !            30:            struct window_pane *, struct client *, u_char, u_char, u_char);
        !            31:
        !            32: void   window_copy_redraw_lines(struct window_pane *, u_int, u_int);
        !            33: void   window_copy_redraw_screen(struct window_pane *);
        !            34: void   window_copy_write_line(
        !            35:            struct window_pane *, struct screen_write_ctx *, u_int);
        !            36: void   window_copy_write_lines(
        !            37:            struct window_pane *, struct screen_write_ctx *, u_int, u_int);
        !            38: void   window_copy_write_column(
        !            39:            struct window_pane *, struct screen_write_ctx *, u_int);
        !            40: void   window_copy_write_columns(
        !            41:            struct window_pane *, struct screen_write_ctx *, u_int, u_int);
        !            42:
        !            43: void   window_copy_update_cursor(struct window_pane *);
        !            44: void   window_copy_start_selection(struct window_pane *);
        !            45: int    window_copy_update_selection(struct window_pane *);
        !            46: void   window_copy_copy_selection(struct window_pane *, struct client *);
        !            47: void   window_copy_copy_line(
        !            48:            struct window_pane *, char **, size_t *, u_int, u_int, u_int);
        !            49: int    window_copy_is_space(struct window_pane *, u_int, u_int);
        !            50: u_int  window_copy_find_length(struct window_pane *, u_int);
        !            51: void   window_copy_cursor_start_of_line(struct window_pane *);
        !            52: void   window_copy_cursor_end_of_line(struct window_pane *);
        !            53: void   window_copy_cursor_left(struct window_pane *);
        !            54: void   window_copy_cursor_right(struct window_pane *);
        !            55: void   window_copy_cursor_up(struct window_pane *);
        !            56: void   window_copy_cursor_down(struct window_pane *);
        !            57: void   window_copy_cursor_next_word(struct window_pane *);
        !            58: void   window_copy_cursor_previous_word(struct window_pane *);
        !            59: void   window_copy_scroll_left(struct window_pane *, u_int);
        !            60: void   window_copy_scroll_right(struct window_pane *, u_int);
        !            61: void   window_copy_scroll_up(struct window_pane *, u_int);
        !            62: void   window_copy_scroll_down(struct window_pane *, u_int);
        !            63:
        !            64: const struct window_mode window_copy_mode = {
        !            65:        window_copy_init,
        !            66:        window_copy_free,
        !            67:        window_copy_resize,
        !            68:        window_copy_key,
        !            69:        window_copy_mouse,
        !            70:        NULL,
        !            71: };
        !            72:
        !            73: struct window_copy_mode_data {
        !            74:        struct screen   screen;
        !            75:
        !            76:        struct mode_key_data    mdata;
        !            77:
        !            78:        u_int   ox;
        !            79:        u_int   oy;
        !            80:
        !            81:        u_int   selx;
        !            82:        u_int   sely;
        !            83:
        !            84:        u_int   cx;
        !            85:        u_int   cy;
        !            86: };
        !            87:
        !            88: struct screen *
        !            89: window_copy_init(struct window_pane *wp)
        !            90: {
        !            91:        struct window_copy_mode_data    *data;
        !            92:        struct screen                   *s;
        !            93:        struct screen_write_ctx          ctx;
        !            94:        u_int                            i;
        !            95:
        !            96:        wp->modedata = data = xmalloc(sizeof *data);
        !            97:        data->ox = 0;
        !            98:        data->oy = 0;
        !            99:        data->cx = wp->base.cx;
        !           100:        data->cy = wp->base.cy;
        !           101:
        !           102:        s = &data->screen;
        !           103:        screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
        !           104:        s->mode |= MODE_MOUSE;
        !           105:
        !           106:        mode_key_init(&data->mdata,
        !           107:            options_get_number(&wp->window->options, "mode-keys"), 0);
        !           108:
        !           109:        s->cx = data->cx;
        !           110:        s->cy = data->cy;
        !           111:
        !           112:        screen_write_start(&ctx, NULL, s);
        !           113:        for (i = 0; i < screen_size_y(s); i++)
        !           114:                window_copy_write_line(wp, &ctx, i);
        !           115:        screen_write_cursormove(&ctx, data->cx, data->cy);
        !           116:        screen_write_stop(&ctx);
        !           117:
        !           118:        return (s);
        !           119: }
        !           120:
        !           121: void
        !           122: window_copy_free(struct window_pane *wp)
        !           123: {
        !           124:        struct window_copy_mode_data    *data = wp->modedata;
        !           125:
        !           126:        mode_key_free(&data->mdata);
        !           127:
        !           128:        screen_free(&data->screen);
        !           129:        xfree(data);
        !           130: }
        !           131:
        !           132: void
        !           133: window_copy_pageup(struct window_pane *wp)
        !           134: {
        !           135:        struct window_copy_mode_data    *data = wp->modedata;
        !           136:        struct screen                   *s = &data->screen;
        !           137:
        !           138:        if (data->oy + screen_size_y(s) > screen_hsize(&wp->base))
        !           139:                data->oy = screen_hsize(&wp->base);
        !           140:        else
        !           141:                data->oy += screen_size_y(s);
        !           142:        window_copy_update_selection(wp);
        !           143:        window_copy_redraw_screen(wp);
        !           144: }
        !           145:
        !           146: void
        !           147: window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
        !           148: {
        !           149:        struct window_copy_mode_data    *data = wp->modedata;
        !           150:        struct screen                   *s = &data->screen;
        !           151:        struct screen_write_ctx          ctx;
        !           152:
        !           153:        screen_resize(s, sx, sy);
        !           154:        screen_write_start(&ctx, NULL, s);
        !           155:        window_copy_write_lines(wp, &ctx, 0, screen_size_y(s) - 1);
        !           156:        screen_write_stop(&ctx);
        !           157:        window_copy_update_selection(wp);
        !           158: }
        !           159:
        !           160: void
        !           161: window_copy_key(struct window_pane *wp, struct client *c, int key)
        !           162: {
        !           163:        struct window_copy_mode_data    *data = wp->modedata;
        !           164:        struct screen                   *s = &data->screen;
        !           165:
        !           166:        switch (mode_key_lookup(&data->mdata, key)) {
        !           167:        case MODEKEYCMD_QUIT:
        !           168:                window_pane_reset_mode(wp);
        !           169:                break;
        !           170:        case MODEKEYCMD_LEFT:
        !           171:                window_copy_cursor_left(wp);
        !           172:                return;
        !           173:        case MODEKEYCMD_RIGHT:
        !           174:                window_copy_cursor_right(wp);
        !           175:                return;
        !           176:        case MODEKEYCMD_UP:
        !           177:                window_copy_cursor_up(wp);
        !           178:                return;
        !           179:        case MODEKEYCMD_DOWN:
        !           180:                window_copy_cursor_down(wp);
        !           181:                return;
        !           182:        case MODEKEYCMD_PREVIOUSPAGE:
        !           183:                window_copy_pageup(wp);
        !           184:                break;
        !           185:        case MODEKEYCMD_NEXTPAGE:
        !           186:                if (data->oy < screen_size_y(s))
        !           187:                        data->oy = 0;
        !           188:                else
        !           189:                        data->oy -= screen_size_y(s);
        !           190:                window_copy_update_selection(wp);
        !           191:                window_copy_redraw_screen(wp);
        !           192:                break;
        !           193:        case MODEKEYCMD_STARTSELECTION:
        !           194:                window_copy_start_selection(wp);
        !           195:                break;
        !           196:        case MODEKEYCMD_CLEARSELECTION:
        !           197:                screen_clear_selection(&data->screen);
        !           198:                window_copy_redraw_screen(wp);
        !           199:                break;
        !           200:        case MODEKEYCMD_COPYSELECTION:
        !           201:                if (c != NULL && c->session != NULL) {
        !           202:                        window_copy_copy_selection(wp, c);
        !           203:                        window_pane_reset_mode(wp);
        !           204:                }
        !           205:                break;
        !           206:        case MODEKEYCMD_STARTOFLINE:
        !           207:                window_copy_cursor_start_of_line(wp);
        !           208:                break;
        !           209:        case MODEKEYCMD_ENDOFLINE:
        !           210:                window_copy_cursor_end_of_line(wp);
        !           211:                break;
        !           212:        case MODEKEYCMD_NEXTWORD:
        !           213:                window_copy_cursor_next_word(wp);
        !           214:                break;
        !           215:        case MODEKEYCMD_PREVIOUSWORD:
        !           216:                window_copy_cursor_previous_word(wp);
        !           217:                break;
        !           218:        default:
        !           219:                break;
        !           220:        }
        !           221: }
        !           222:
        !           223: void
        !           224: window_copy_mouse(struct window_pane *wp,
        !           225:     unused struct client *c, u_char b, u_char x, u_char y)
        !           226: {
        !           227:        struct window_copy_mode_data    *data = wp->modedata;
        !           228:        struct screen                   *s = &data->screen;
        !           229:
        !           230:        if ((b & 3) == 3)
        !           231:                return;
        !           232:        if (x >= screen_size_x(s))
        !           233:                return;
        !           234:        if (y >= screen_size_y(s))
        !           235:                return;
        !           236:
        !           237:        data->cx = x;
        !           238:        data->cy = y;
        !           239:
        !           240:        if (window_copy_update_selection(wp))
        !           241:                window_copy_redraw_screen(wp);
        !           242:        window_copy_update_cursor(wp);
        !           243: }
        !           244:
        !           245: void
        !           246: window_copy_write_line(struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
        !           247: {
        !           248:        struct window_copy_mode_data    *data = wp->modedata;
        !           249:        struct screen                   *s = &data->screen;
        !           250:        struct grid_cell                 gc;
        !           251:        char                             hdr[32];
        !           252:        size_t                           size;
        !           253:
        !           254:        if (py == 0) {
        !           255:                memcpy(&gc, &grid_default_cell, sizeof gc);
        !           256:                size = xsnprintf(hdr, sizeof hdr,
        !           257:                    "[%u,%u/%u]", data->ox, data->oy, screen_hsize(&wp->base));
        !           258:                gc.bg = options_get_number(&wp->window->options, "mode-fg");
        !           259:                gc.fg = options_get_number(&wp->window->options, "mode-bg");
        !           260:                gc.attr |= options_get_number(&wp->window->options, "mode-attr");
        !           261:                screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
        !           262:                screen_write_puts(ctx, &gc, "%s", hdr);
        !           263:        } else
        !           264:                size = 0;
        !           265:
        !           266:        screen_write_cursormove(ctx, 0, py);
        !           267:        screen_write_copy(ctx, &wp->base, data->ox, (screen_hsize(&wp->base) -
        !           268:            data->oy) + py, screen_size_x(s) - size, 1);
        !           269: }
        !           270:
        !           271: void
        !           272: window_copy_write_lines(
        !           273:     struct window_pane *wp, struct screen_write_ctx *ctx, u_int py, u_int ny)
        !           274: {
        !           275:        u_int   yy;
        !           276:
        !           277:        for (yy = py; yy < py + ny; yy++)
        !           278:                window_copy_write_line(wp, ctx, py);
        !           279: }
        !           280:
        !           281: void
        !           282: window_copy_write_column(
        !           283:     struct window_pane *wp, struct screen_write_ctx *ctx, u_int px)
        !           284: {
        !           285:        struct window_copy_mode_data    *data = wp->modedata;
        !           286:        struct screen                   *s = &data->screen;
        !           287:
        !           288:        screen_write_cursormove(ctx, px, 0);
        !           289:        screen_write_copy(ctx, &wp->base,
        !           290:            data->ox + px, screen_hsize(&wp->base) - data->oy, 1, screen_size_y(s));
        !           291: }
        !           292:
        !           293: void
        !           294: window_copy_write_columns(
        !           295:     struct window_pane *wp, struct screen_write_ctx *ctx, u_int px, u_int nx)
        !           296: {
        !           297:        u_int   xx;
        !           298:
        !           299:        for (xx = px; xx < px + nx; xx++)
        !           300:                window_copy_write_column(wp, ctx, xx);
        !           301: }
        !           302:
        !           303: void
        !           304: window_copy_redraw_lines(struct window_pane *wp, u_int py, u_int ny)
        !           305: {
        !           306:        struct window_copy_mode_data    *data = wp->modedata;
        !           307:        struct screen_write_ctx          ctx;
        !           308:        u_int                            i;
        !           309:
        !           310:        screen_write_start(&ctx, wp, NULL);
        !           311:        for (i = py; i < py + ny; i++)
        !           312:                window_copy_write_line(wp, &ctx, i);
        !           313:        screen_write_cursormove(&ctx, data->cx, data->cy);
        !           314:        screen_write_stop(&ctx);
        !           315: }
        !           316:
        !           317: void
        !           318: window_copy_redraw_screen(struct window_pane *wp)
        !           319: {
        !           320:        struct window_copy_mode_data    *data = wp->modedata;
        !           321:
        !           322:        window_copy_redraw_lines(wp, 0, screen_size_y(&data->screen));
        !           323: }
        !           324:
        !           325: void
        !           326: window_copy_update_cursor(struct window_pane *wp)
        !           327: {
        !           328:        struct window_copy_mode_data    *data = wp->modedata;
        !           329:        struct screen_write_ctx          ctx;
        !           330:
        !           331:        screen_write_start(&ctx, wp, NULL);
        !           332:        screen_write_cursormove(&ctx, data->cx, data->cy);
        !           333:        screen_write_stop(&ctx);
        !           334: }
        !           335:
        !           336: void
        !           337: window_copy_start_selection(struct window_pane *wp)
        !           338: {
        !           339:        struct window_copy_mode_data    *data = wp->modedata;
        !           340:        struct screen                   *s = &data->screen;
        !           341:
        !           342:        data->selx = data->cx + data->ox;
        !           343:        data->sely = screen_hsize(&wp->base) + data->cy - data->oy;
        !           344:
        !           345:        s->sel.flag = 1;
        !           346:        window_copy_update_selection(wp);
        !           347: }
        !           348:
        !           349: int
        !           350: window_copy_update_selection(struct window_pane *wp)
        !           351: {
        !           352:        struct window_copy_mode_data    *data = wp->modedata;
        !           353:        struct screen                   *s = &data->screen;
        !           354:        struct grid_cell                 gc;
        !           355:        u_int                            sx, sy, tx, ty;
        !           356:
        !           357:        if (!s->sel.flag)
        !           358:                return (0);
        !           359:
        !           360:        /* Set colours. */
        !           361:        memcpy(&gc, &grid_default_cell, sizeof gc);
        !           362:        gc.bg = options_get_number(&wp->window->options, "mode-fg");
        !           363:        gc.fg = options_get_number(&wp->window->options, "mode-bg");
        !           364:        gc.attr |= options_get_number(&wp->window->options, "mode-attr");
        !           365:
        !           366:        /* Find top-left of screen. */
        !           367:        tx = data->ox;
        !           368:        ty = screen_hsize(&wp->base) - data->oy;
        !           369:
        !           370:        /* Adjust the selection. */
        !           371:        sx = data->selx;
        !           372:        sy = data->sely;
        !           373:        if (sy < ty) {
        !           374:                /* Above it. */
        !           375:                sx = 0;
        !           376:                sy = 0;
        !           377:        } else if (sy > ty + screen_size_y(s) - 1) {
        !           378:                /* Below it. */
        !           379:                sx = screen_size_x(s) - 1;
        !           380:                sy = screen_size_y(s) - 1;
        !           381:        } else if (sx < tx) {
        !           382:                /* To the left. */
        !           383:                sx = 0;
        !           384:        } else if (sx > tx + screen_size_x(s) - 1) {
        !           385:                /* To the right. */
        !           386:                sx = 0;
        !           387:                sy++;
        !           388:                if (sy > screen_size_y(s) - 1)
        !           389:                        sy = screen_size_y(s) - 1;
        !           390:        } else {
        !           391:                sx -= tx;
        !           392:                sy -= ty;
        !           393:        }
        !           394:        sy = screen_hsize(s) + sy;
        !           395:
        !           396:        screen_set_selection(
        !           397:            s, sx, sy, data->cx, screen_hsize(s) + data->cy, &gc);
        !           398:        return (1);
        !           399: }
        !           400:
        !           401: void
        !           402: window_copy_copy_selection(struct window_pane *wp, struct client *c)
        !           403: {
        !           404:        struct window_copy_mode_data    *data = wp->modedata;
        !           405:        struct screen                   *s = &data->screen;
        !           406:        char                            *buf;
        !           407:        size_t                           off;
        !           408:        u_int                            i, xx, yy, sx, sy, ex, ey, limit;
        !           409:
        !           410:        if (!s->sel.flag)
        !           411:                return;
        !           412:
        !           413:        buf = xmalloc(1);
        !           414:        off = 0;
        !           415:
        !           416:        *buf = '\0';
        !           417:
        !           418:        /*
        !           419:         * The selection extends from selx,sely to (adjusted) cx,cy on
        !           420:         * the base screen.
        !           421:         */
        !           422:
        !           423:        /* Find start and end. */
        !           424:        xx = data->cx + data->ox;
        !           425:        yy = screen_hsize(&wp->base) + data->cy - data->oy;
        !           426:        if (xx < data->selx || (yy == data->sely && xx < data->selx)) {
        !           427:                sx = xx; sy = yy;
        !           428:                ex = data->selx; ey = data->sely;
        !           429:        } else {
        !           430:                sx = data->selx; sy = data->sely;
        !           431:                ex = xx; ey = yy;
        !           432:        }
        !           433:
        !           434:        /* Trim ex to end of line. */
        !           435:        xx = window_copy_find_length(wp, ey);
        !           436:        if (ex > xx)
        !           437:                ex = xx;
        !           438:
        !           439:        /* Copy the lines. */
        !           440:        if (sy == ey)
        !           441:                window_copy_copy_line(wp, &buf, &off, sy, sx, ex);
        !           442:        else {
        !           443:                xx = window_copy_find_length(wp, sy);
        !           444:                window_copy_copy_line(wp, &buf, &off, sy, sx, xx);
        !           445:                if (ey - sy > 1) {
        !           446:                        for (i = sy + 1; i < ey - 1; i++) {
        !           447:                                xx = window_copy_find_length(wp, i);
        !           448:                                window_copy_copy_line(wp, &buf, &off, i, 0, xx);
        !           449:                        }
        !           450:                }
        !           451:                window_copy_copy_line(wp, &buf, &off, ey, 0, ex);
        !           452:        }
        !           453:
        !           454:        /* Terminate buffer, overwriting final \n. */
        !           455:        if (off != 0)
        !           456:                buf[off - 1] = '\0';
        !           457:
        !           458:        /* Add the buffer to the stack. */
        !           459:        limit = options_get_number(&c->session->options, "buffer-limit");
        !           460:        paste_add(&c->session->buffers, buf, limit);
        !           461: }
        !           462:
        !           463: void
        !           464: window_copy_copy_line(struct window_pane *wp,
        !           465:     char **buf, size_t *off, u_int sy, u_int sx, u_int ex)
        !           466: {
        !           467:        const struct grid_cell  *gc;
        !           468:        const struct grid_utf8  *gu;
        !           469:        u_int                    i, j, xx;
        !           470:
        !           471:        if (sx > ex)
        !           472:                return;
        !           473:
        !           474:        xx = window_copy_find_length(wp, sy);
        !           475:        if (ex > xx)
        !           476:                ex = xx;
        !           477:        if (sx > xx)
        !           478:                sx = xx;
        !           479:
        !           480:        if (sx < ex) {
        !           481:                for (i = sx; i < ex; i++) {
        !           482:                        gc = grid_peek_cell(wp->base.grid, i, sy);
        !           483:                        if (gc->flags & GRID_FLAG_PADDING)
        !           484:                                continue;
        !           485:                        if (!(gc->flags & GRID_FLAG_UTF8)) {
        !           486:                                *buf = xrealloc(*buf, 1, (*off) + 1);
        !           487:                                (*buf)[(*off)++] = gc->data;
        !           488:                        } else {
        !           489:                                gu = grid_peek_utf8(wp->base.grid, i, sy);
        !           490:                                *buf = xrealloc(*buf, 1, (*off) + UTF8_SIZE);
        !           491:                                for (j = 0; j < UTF8_SIZE; j++) {
        !           492:                                        if (gu->data[j] == 0xff)
        !           493:                                                break;
        !           494:                                        (*buf)[(*off)++] = gu->data[j];
        !           495:                                }
        !           496:                        }
        !           497:                }
        !           498:        }
        !           499:
        !           500:        *buf = xrealloc(*buf, 1, (*off) + 1);
        !           501:        (*buf)[*off] = '\n';
        !           502:        (*off)++;
        !           503: }
        !           504:
        !           505: int
        !           506: window_copy_is_space(struct window_pane *wp, u_int px, u_int py)
        !           507: {
        !           508:        const struct grid_cell  *gc;
        !           509:        const char              *spaces = " -_@";
        !           510:
        !           511:        gc = grid_peek_cell(wp->base.grid, px, py);
        !           512:        if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8))
        !           513:                return (0);
        !           514:        if (gc->data == 0x00 || gc->data == 0x7f)
        !           515:                return (0);
        !           516:        return (strchr(spaces, gc->data) != NULL);
        !           517: }
        !           518:
        !           519: u_int
        !           520: window_copy_find_length(struct window_pane *wp, u_int py)
        !           521: {
        !           522:        const struct grid_cell  *gc;
        !           523:        u_int                    px;
        !           524:
        !           525:        px = wp->base.grid->size[py];
        !           526:        while (px > 0) {
        !           527:                gc = grid_peek_cell(wp->base.grid, px - 1, py);
        !           528:                if (gc->flags & GRID_FLAG_UTF8)
        !           529:                        break;
        !           530:                if (gc->data != ' ')
        !           531:                        break;
        !           532:                px--;
        !           533:        }
        !           534:        return (px);
        !           535: }
        !           536:
        !           537: void
        !           538: window_copy_cursor_start_of_line(struct window_pane *wp)
        !           539: {
        !           540:        struct window_copy_mode_data    *data = wp->modedata;
        !           541:
        !           542:        if (data->ox != 0)
        !           543:                window_copy_scroll_right(wp, data->ox);
        !           544:        data->cx = 0;
        !           545:
        !           546:        if (window_copy_update_selection(wp))
        !           547:                window_copy_redraw_lines(wp, data->cy, 1);
        !           548:        else
        !           549:                window_copy_update_cursor(wp);
        !           550: }
        !           551:
        !           552: void
        !           553: window_copy_cursor_end_of_line(struct window_pane *wp)
        !           554: {
        !           555:        struct window_copy_mode_data    *data = wp->modedata;
        !           556:        struct screen                   *s = &data->screen;
        !           557:        u_int                            px, py;
        !           558:
        !           559:        py = screen_hsize(&wp->base) + data->cy - data->oy;
        !           560:        px = window_copy_find_length(wp, py);
        !           561:
        !           562:        /* On screen. */
        !           563:        if (px > data->ox && px <= data->ox + screen_size_x(s) - 1)
        !           564:                data->cx = px - data->ox;
        !           565:
        !           566:        /* Off right of screen. */
        !           567:        if (px > data->ox + screen_size_x(s) - 1) {
        !           568:                /* Move cursor to last and scroll screen. */
        !           569:                window_copy_scroll_left(
        !           570:                    wp, px - data->ox - (screen_size_x(s) - 1));
        !           571:                data->cx = screen_size_x(s) - 1;
        !           572:        }
        !           573:
        !           574:        /* Off left of screen. */
        !           575:        if (px <= data->ox) {
        !           576:                if (px < screen_size_x(s) - 1) {
        !           577:                        /* Short enough to fit on screen. */
        !           578:                        window_copy_scroll_right(wp, data->ox);
        !           579:                        data->cx = px;
        !           580:                } else {
        !           581:                        /* Too long to fit on screen. */
        !           582:                        window_copy_scroll_right(
        !           583:                            wp, data->ox - (px - (screen_size_x(s) - 1)));
        !           584:                        data->cx = screen_size_x(s) - 1;
        !           585:                }
        !           586:        }
        !           587:
        !           588:        if (window_copy_update_selection(wp))
        !           589:                window_copy_redraw_lines(wp, data->cy, 1);
        !           590:        else
        !           591:                window_copy_update_cursor(wp);
        !           592: }
        !           593:
        !           594: void
        !           595: window_copy_cursor_left(struct window_pane *wp)
        !           596: {
        !           597:        struct window_copy_mode_data    *data = wp->modedata;
        !           598:
        !           599:        if (data->cx == 0) {
        !           600:                if (data->ox > 0)
        !           601:                        window_copy_scroll_right(wp, 1);
        !           602:                else {
        !           603:                        window_copy_cursor_up(wp);
        !           604:                        window_copy_cursor_end_of_line(wp);
        !           605:                }
        !           606:        } else {
        !           607:                data->cx--;
        !           608:                if (window_copy_update_selection(wp))
        !           609:                        window_copy_redraw_lines(wp, data->cy, 1);
        !           610:                else
        !           611:                        window_copy_update_cursor(wp);
        !           612:        }
        !           613: }
        !           614:
        !           615: void
        !           616: window_copy_cursor_right(struct window_pane *wp)
        !           617: {
        !           618:        struct window_copy_mode_data    *data = wp->modedata;
        !           619:        u_int                            px, py;
        !           620:
        !           621:        py = screen_hsize(&wp->base) + data->cy - data->oy;
        !           622:        px = window_copy_find_length(wp, py);
        !           623:
        !           624:        if (data->cx >= px) {
        !           625:                window_copy_cursor_start_of_line(wp);
        !           626:                window_copy_cursor_down(wp);
        !           627:        } else {
        !           628:                data->cx++;
        !           629:                if (window_copy_update_selection(wp))
        !           630:                        window_copy_redraw_lines(wp, data->cy, 1);
        !           631:                else
        !           632:                        window_copy_update_cursor(wp);
        !           633:        }
        !           634: }
        !           635:
        !           636: void
        !           637: window_copy_cursor_up(struct window_pane *wp)
        !           638: {
        !           639:        struct window_copy_mode_data    *data = wp->modedata;
        !           640:        u_int                            ox, oy, px, py;
        !           641:
        !           642:        oy = screen_hsize(&wp->base) + data->cy - data->oy;
        !           643:        ox = window_copy_find_length(wp, oy);
        !           644:
        !           645:        if (data->cy == 0)
        !           646:                window_copy_scroll_down(wp, 1);
        !           647:        else {
        !           648:                data->cy--;
        !           649:                if (window_copy_update_selection(wp))
        !           650:                        window_copy_redraw_lines(wp, data->cy, 2);
        !           651:                else
        !           652:                        window_copy_update_cursor(wp);
        !           653:        }
        !           654:
        !           655:        py = screen_hsize(&wp->base) + data->cy - data->oy;
        !           656:        px = window_copy_find_length(wp, py);
        !           657:
        !           658:        if (data->cx + data->ox >= px || data->cx + data->ox >= ox)
        !           659:                window_copy_cursor_end_of_line(wp);
        !           660: }
        !           661:
        !           662: void
        !           663: window_copy_cursor_down(struct window_pane *wp)
        !           664: {
        !           665:        struct window_copy_mode_data    *data = wp->modedata;
        !           666:        struct screen                   *s = &data->screen;
        !           667:        u_int                            ox, oy, px, py;
        !           668:
        !           669:        oy = screen_hsize(&wp->base) + data->cy - data->oy;
        !           670:        ox = window_copy_find_length(wp, oy);
        !           671:
        !           672:        if (data->cy == screen_size_y(s) - 1)
        !           673:                window_copy_scroll_up(wp, 1);
        !           674:        else {
        !           675:                data->cy++;
        !           676:                if (window_copy_update_selection(wp))
        !           677:                        window_copy_redraw_lines(wp, data->cy - 1, 2);
        !           678:                else
        !           679:                        window_copy_update_cursor(wp);
        !           680:        }
        !           681:
        !           682:        py = screen_hsize(&wp->base) + data->cy - data->oy;
        !           683:        px = window_copy_find_length(wp, py);
        !           684:
        !           685:        if (data->cx + data->ox >= px || data->cx + data->ox >= ox)
        !           686:                window_copy_cursor_end_of_line(wp);
        !           687: }
        !           688:
        !           689: void
        !           690: window_copy_cursor_next_word(struct window_pane *wp)
        !           691: {
        !           692:        struct window_copy_mode_data    *data = wp->modedata;
        !           693:        struct screen                   *s = &data->screen;
        !           694:        u_int                            px, py, xx, skip;
        !           695:
        !           696:        px = data->ox + data->cx;
        !           697:        py = screen_hsize(&wp->base) + data->cy - data->oy;
        !           698:        xx = window_copy_find_length(wp, py);
        !           699:
        !           700:        skip = 1;
        !           701:        if (px < xx) {
        !           702:                /* If currently on a space, skip space. */
        !           703:                if (window_copy_is_space(wp, px, py))
        !           704:                        skip = 0;
        !           705:        } else
        !           706:                skip = 0;
        !           707:        for (;;) {
        !           708:                if (px >= xx) {
        !           709:                        if (skip) {
        !           710:                                px = xx;
        !           711:                                break;
        !           712:                        }
        !           713:
        !           714:                        while (px >= xx) {
        !           715:                                if (data->cy == screen_size_y(s) - 1) {
        !           716:                                        if (data->oy == 0)
        !           717:                                                goto out;
        !           718:                                }
        !           719:
        !           720:                                px = 0;
        !           721:                                window_copy_cursor_down(wp);
        !           722:
        !           723:                                py =screen_hsize(
        !           724:                                    &wp->base) + data->cy - data->oy;
        !           725:                                xx = window_copy_find_length(wp, py);
        !           726:                        }
        !           727:                }
        !           728:
        !           729:                if (skip) {
        !           730:                        /* Currently skipping non-space (until space). */
        !           731:                        if (window_copy_is_space(wp, px, py))
        !           732:                                break;
        !           733:                } else {
        !           734:                        /* Currently skipping space (until non-space). */
        !           735:                        if (!window_copy_is_space(wp, px, py))
        !           736:                                skip = 1;
        !           737:                }
        !           738:
        !           739:                px++;
        !           740:        }
        !           741: out:
        !           742:
        !           743:        /* On screen. */
        !           744:        if (px > data->ox && px <= data->ox + screen_size_x(s) - 1)
        !           745:                data->cx = px - data->ox;
        !           746:
        !           747:        /* Off right of screen. */
        !           748:        if (px > data->ox + screen_size_x(s) - 1) {
        !           749:                /* Move cursor to last and scroll screen. */
        !           750:                window_copy_scroll_left(
        !           751:                    wp, px - data->ox - (screen_size_x(s) - 1));
        !           752:                data->cx = screen_size_x(s) - 1;
        !           753:        }
        !           754:
        !           755:        /* Off left of screen. */
        !           756:        if (px <= data->ox) {
        !           757:                if (px < screen_size_x(s) - 1) {
        !           758:                        /* Short enough to fit on screen. */
        !           759:                        window_copy_scroll_right(wp, data->ox);
        !           760:                        data->cx = px;
        !           761:                } else {
        !           762:                        /* Too long to fit on screen. */
        !           763:                        window_copy_scroll_right(
        !           764:                            wp, data->ox - (px - (screen_size_x(s) - 1)));
        !           765:                        data->cx = screen_size_x(s) - 1;
        !           766:                }
        !           767:        }
        !           768:
        !           769:        if (window_copy_update_selection(wp))
        !           770:                window_copy_redraw_lines(wp, data->cy, 1);
        !           771:        else
        !           772:                window_copy_update_cursor(wp);
        !           773: }
        !           774:
        !           775: void
        !           776: window_copy_cursor_previous_word(struct window_pane *wp)
        !           777: {
        !           778:        struct window_copy_mode_data    *data = wp->modedata;
        !           779:        struct screen                   *s = &data->screen;
        !           780:        u_int                            ox, px, py, skip;
        !           781:
        !           782:        ox = px = data->ox + data->cx;
        !           783:        py = screen_hsize(&wp->base) + data->cy - data->oy;
        !           784:
        !           785:        skip = 1;
        !           786:        if (px != 0) {
        !           787:                /* If currently on a space, skip space. */
        !           788:                if (window_copy_is_space(wp, px - 1, py))
        !           789:                        skip = 0;
        !           790:        }
        !           791:        for (;;) {
        !           792:                if (px == 0) {
        !           793:                        if (ox != 0)
        !           794:                                break;
        !           795:
        !           796:                        while (px == 0) {
        !           797:                                if (data->cy == 0 &&
        !           798:                                    (screen_hsize(&wp->base) == 0 ||
        !           799:                                    data->oy >= screen_hsize(&wp->base) - 1))
        !           800:                                        goto out;
        !           801:
        !           802:                                window_copy_cursor_up(wp);
        !           803:
        !           804:                                py = screen_hsize(
        !           805:                                    &wp->base) + data->cy - data->oy;
        !           806:                                px = window_copy_find_length(wp, py);
        !           807:                        }
        !           808:                        goto out;
        !           809:                }
        !           810:
        !           811:                if (skip) {
        !           812:                        /* Currently skipping non-space (until space). */
        !           813:                        if (window_copy_is_space(wp, px - 1, py))
        !           814:                                skip = 0;
        !           815:                } else {
        !           816:                        /* Currently skipping space (until non-space). */
        !           817:                        if (!window_copy_is_space(wp, px - 1, py))
        !           818:                                break;
        !           819:                }
        !           820:
        !           821:                px--;
        !           822:        }
        !           823: out:
        !           824:
        !           825:        /* On screen. */
        !           826:        if (px > data->ox && px <= data->ox + screen_size_x(s) - 1)
        !           827:                data->cx = px - data->ox;
        !           828:
        !           829:        /* Off right of screen. */
        !           830:        if (px > data->ox + screen_size_x(s) - 1) {
        !           831:                /* Move cursor to last and scroll screen. */
        !           832:                window_copy_scroll_left(
        !           833:                    wp, px - data->ox - (screen_size_x(s) - 1));
        !           834:                data->cx = screen_size_x(s) - 1;
        !           835:        }
        !           836:
        !           837:        /* Off left of screen. */
        !           838:        if (px <= data->ox) {
        !           839:                if (px < screen_size_x(s) - 1) {
        !           840:                        /* Short enough to fit on screen. */
        !           841:                        window_copy_scroll_right(wp, data->ox);
        !           842:                        data->cx = px;
        !           843:                } else {
        !           844:                        /* Too long to fit on screen. */
        !           845:                        window_copy_scroll_right(
        !           846:                            wp, data->ox - (px - (screen_size_x(s) - 1)));
        !           847:                        data->cx = screen_size_x(s) - 1;
        !           848:                }
        !           849:        }
        !           850:
        !           851:        if (window_copy_update_selection(wp))
        !           852:                window_copy_redraw_lines(wp, data->cy, 1);
        !           853:        else
        !           854:                window_copy_update_cursor(wp);
        !           855: }
        !           856:
        !           857: void
        !           858: window_copy_scroll_left(struct window_pane *wp, u_int nx)
        !           859: {
        !           860:        struct window_copy_mode_data    *data = wp->modedata;
        !           861:        struct screen                   *s = &data->screen;
        !           862:        struct screen_write_ctx          ctx;
        !           863:        u_int                            i;
        !           864:
        !           865:        if (data->ox > SHRT_MAX - nx)
        !           866:                nx = SHRT_MAX - data->ox;
        !           867:        if (nx == 0)
        !           868:                return;
        !           869:        data->ox += nx;
        !           870:        window_copy_update_selection(wp);
        !           871:
        !           872:        screen_write_start(&ctx, wp, NULL);
        !           873:        for (i = 1; i < screen_size_y(s); i++) {
        !           874:                screen_write_cursormove(&ctx, 0, i);
        !           875:                screen_write_deletecharacter(&ctx, nx);
        !           876:        }
        !           877:        window_copy_write_columns(wp, &ctx, screen_size_x(s) - nx, nx);
        !           878:        window_copy_write_line(wp, &ctx, 0);
        !           879:        if (s->sel.flag) {
        !           880:                window_copy_update_selection(wp);
        !           881:                window_copy_write_lines(wp, &ctx, data->cy, 1);
        !           882:        }
        !           883:        screen_write_cursormove(&ctx, data->cx, data->cy);
        !           884:        screen_write_stop(&ctx);
        !           885: }
        !           886:
        !           887: void
        !           888: window_copy_scroll_right(struct window_pane *wp, u_int nx)
        !           889: {
        !           890:        struct window_copy_mode_data    *data = wp->modedata;
        !           891:        struct screen                   *s = &data->screen;
        !           892:        struct screen_write_ctx          ctx;
        !           893:        u_int                            i;
        !           894:
        !           895:        if (data->ox < nx)
        !           896:                nx = data->ox;
        !           897:        if (nx == 0)
        !           898:                return;
        !           899:        data->ox -= nx;
        !           900:        window_copy_update_selection(wp);
        !           901:
        !           902:        screen_write_start(&ctx, wp, NULL);
        !           903:        for (i = 1; i < screen_size_y(s); i++) {
        !           904:                screen_write_cursormove(&ctx, 0, i);
        !           905:                screen_write_insertcharacter(&ctx, nx);
        !           906:        }
        !           907:        window_copy_write_columns(wp, &ctx, 0, nx);
        !           908:        window_copy_write_line(wp, &ctx, 0);
        !           909:        if (s->sel.flag)
        !           910:                window_copy_write_line(wp, &ctx, data->cy);
        !           911:        screen_write_cursormove(&ctx, data->cx, data->cy);
        !           912:        screen_write_stop(&ctx);
        !           913: }
        !           914:
        !           915: void
        !           916: window_copy_scroll_up(struct window_pane *wp, u_int ny)
        !           917: {
        !           918:        struct window_copy_mode_data    *data = wp->modedata;
        !           919:        struct screen                   *s = &data->screen;
        !           920:        struct screen_write_ctx          ctx;
        !           921:
        !           922:        if (data->oy < ny)
        !           923:                ny = data->oy;
        !           924:        if (ny == 0)
        !           925:                return;
        !           926:        data->oy -= ny;
        !           927:        window_copy_update_selection(wp);
        !           928:
        !           929:        screen_write_start(&ctx, wp, NULL);
        !           930:        screen_write_cursormove(&ctx, 0, 0);
        !           931:        screen_write_deleteline(&ctx, ny);
        !           932:        window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, ny);
        !           933:        window_copy_write_line(wp, &ctx, 0);
        !           934:        window_copy_write_line(wp, &ctx, 1);
        !           935:        if (s->sel.flag && screen_size_y(s) > ny)
        !           936:                window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1);
        !           937:        screen_write_cursormove(&ctx, data->cx, data->cy);
        !           938:        screen_write_stop(&ctx);
        !           939: }
        !           940:
        !           941: void
        !           942: window_copy_scroll_down(struct window_pane *wp, u_int ny)
        !           943: {
        !           944:        struct window_copy_mode_data    *data = wp->modedata;
        !           945:        struct screen                   *s = &data->screen;
        !           946:        struct screen_write_ctx          ctx;
        !           947:
        !           948:        if (ny > screen_hsize(&wp->base))
        !           949:                return;
        !           950:
        !           951:        if (data->oy > screen_hsize(&wp->base) - ny)
        !           952:                ny = screen_hsize(&wp->base) - data->oy;
        !           953:        if (ny == 0)
        !           954:                return;
        !           955:        data->oy += ny;
        !           956:        window_copy_update_selection(wp);
        !           957:
        !           958:        screen_write_start(&ctx, wp, NULL);
        !           959:        screen_write_cursormove(&ctx, 0, 0);
        !           960:        screen_write_insertline(&ctx, ny);
        !           961:        window_copy_write_lines(wp, &ctx, 0, ny);
        !           962:        if (s->sel.flag && screen_size_y(s) > ny)
        !           963:                window_copy_write_line(wp, &ctx, ny);
        !           964:        else if (ny == 1) /* nuke position */
        !           965:                window_copy_write_line(wp, &ctx, 1);
        !           966:        screen_write_cursormove(&ctx, data->cx, data->cy);
        !           967:        screen_write_stop(&ctx);
        !           968: }