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

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