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

Annotation of src/usr.bin/tmux/grid-reader.c, Revision 1.5

1.5     ! nicm        1: /* $OpenBSD: grid-reader.c,v 1.4 2021/04/05 08:43:48 nicm Exp $ */
1.1       nicm        2:
                      3: /*
                      4:  * Copyright (c) 2020 Anindya Mukherjee <anindya49@hotmail.com>
                      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 "tmux.h"
1.2       nicm       20: #include <string.h>
1.1       nicm       21:
                     22: /* Initialise virtual cursor. */
                     23: void
                     24: grid_reader_start(struct grid_reader *gr, struct grid *gd, u_int cx, u_int cy)
                     25: {
                     26:        gr->gd = gd;
                     27:        gr->cx = cx;
                     28:        gr->cy = cy;
                     29: }
                     30:
                     31: /* Get cursor position from reader. */
                     32: void
                     33: grid_reader_get_cursor(struct grid_reader *gr, u_int *cx, u_int *cy)
                     34: {
                     35:        *cx = gr->cx;
                     36:        *cy = gr->cy;
                     37: }
                     38:
                     39: /* Get length of line containing the cursor. */
                     40: u_int
                     41: grid_reader_line_length(struct grid_reader *gr)
                     42: {
                     43:        return (grid_line_length(gr->gd, gr->cy));
                     44: }
                     45:
                     46: /* Move cursor forward one position. */
                     47: void
                     48: grid_reader_cursor_right(struct grid_reader *gr, int wrap, int all)
                     49: {
                     50:        u_int                   px;
                     51:        struct grid_cell        gc;
                     52:
                     53:        if (all)
                     54:                px = gr->gd->sx;
                     55:        else
                     56:                px = grid_reader_line_length(gr);
                     57:
                     58:        if (wrap && gr->cx >= px && gr->cy < gr->gd->hsize + gr->gd->sy - 1) {
                     59:                grid_reader_cursor_start_of_line(gr, 0);
                     60:                grid_reader_cursor_down(gr);
                     61:        } else if (gr->cx < px) {
                     62:                gr->cx++;
                     63:                while (gr->cx < px) {
                     64:                        grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
                     65:                        if (~gc.flags & GRID_FLAG_PADDING)
                     66:                                break;
                     67:                        gr->cx++;
                     68:                }
                     69:        }
                     70: }
                     71:
                     72: /* Move cursor back one position. */
                     73: void
1.4       nicm       74: grid_reader_cursor_left(struct grid_reader *gr, int wrap)
1.1       nicm       75: {
                     76:        struct grid_cell        gc;
                     77:
                     78:        while (gr->cx > 0) {
                     79:                grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
                     80:                if (~gc.flags & GRID_FLAG_PADDING)
                     81:                        break;
                     82:                gr->cx--;
                     83:        }
1.4       nicm       84:        if (gr->cx == 0 && gr->cy > 0 &&
                     85:            (wrap ||
                     86:             grid_get_line(gr->gd, gr->cy - 1)->flags & GRID_LINE_WRAPPED)) {
1.1       nicm       87:                grid_reader_cursor_up(gr);
                     88:                grid_reader_cursor_end_of_line(gr, 0, 0);
                     89:        } else if (gr->cx > 0)
                     90:                gr->cx--;
                     91: }
                     92:
                     93: /* Move cursor down one line. */
                     94: void
                     95: grid_reader_cursor_down(struct grid_reader *gr)
                     96: {
                     97:        struct grid_cell        gc;
                     98:
                     99:        if (gr->cy < gr->gd->hsize + gr->gd->sy - 1)
                    100:                gr->cy++;
                    101:        while (gr->cx > 0) {
                    102:                grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
                    103:                if (~gc.flags & GRID_FLAG_PADDING)
                    104:                        break;
                    105:                gr->cx--;
                    106:        }
                    107: }
                    108:
                    109: /* Move cursor up one line. */
                    110: void
                    111: grid_reader_cursor_up(struct grid_reader *gr)
                    112: {
                    113:        struct grid_cell        gc;
                    114:
                    115:        if (gr->cy > 0)
                    116:                gr->cy--;
                    117:        while (gr->cx > 0) {
                    118:                grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
                    119:                if (~gc.flags & GRID_FLAG_PADDING)
                    120:                        break;
                    121:                gr->cx--;
                    122:        }
                    123: }
                    124:
                    125: /* Move cursor to the start of the line. */
                    126: void
                    127: grid_reader_cursor_start_of_line(struct grid_reader *gr, int wrap)
                    128: {
                    129:        if (wrap) {
                    130:                while (gr->cy > 0 &&
                    131:                    grid_get_line(gr->gd, gr->cy - 1)->flags &
                    132:                        GRID_LINE_WRAPPED)
                    133:                        gr->cy--;
                    134:        }
                    135:        gr->cx = 0;
                    136: }
                    137:
                    138: /* Move cursor to the end of the line. */
                    139: void
                    140: grid_reader_cursor_end_of_line(struct grid_reader *gr, int wrap, int all)
                    141: {
                    142:        u_int   yy;
                    143:
                    144:        if (wrap) {
                    145:                yy = gr->gd->hsize + gr->gd->sy - 1;
                    146:                while (gr->cy < yy && grid_get_line(gr->gd, gr->cy)->flags &
                    147:                    GRID_LINE_WRAPPED)
                    148:                        gr->cy++;
                    149:        }
                    150:        if (all)
                    151:                gr->cx = gr->gd->sx;
                    152:        else
                    153:                gr->cx = grid_reader_line_length(gr);
                    154: }
                    155:
                    156: /* Check if character under cursor is in set. */
                    157: int
                    158: grid_reader_in_set(struct grid_reader *gr, const char *set)
                    159: {
                    160:        struct grid_cell        gc;
                    161:
                    162:        grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
                    163:        if (gc.flags & GRID_FLAG_PADDING)
                    164:                return (0);
                    165:        return (utf8_cstrhas(set, &gc.data));
                    166: }
                    167:
                    168: /* Move cursor to the start of the next word. */
                    169: void
                    170: grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators)
                    171: {
                    172:        u_int   xx, yy;
                    173:        int expected = 0;
                    174:
                    175:        /* Do not break up wrapped words. */
                    176:        if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
1.3       nicm      177:                xx = gr->gd->sx - 1;
1.1       nicm      178:        else
                    179:                xx = grid_reader_line_length(gr);
                    180:        yy = gr->gd->hsize + gr->gd->sy - 1;
                    181:
                    182:        /*
                    183:         * If we started inside a word, skip over word characters. Then skip
                    184:         * over separators till the next word.
                    185:         *
                    186:         * expected is initially set to 0 for the former and then 1 for the
                    187:         * latter. It is finally set to 0 when the beginning of the next word is
                    188:         * found.
                    189:         */
                    190:        do {
                    191:                while (gr->cx > xx ||
                    192:                    grid_reader_in_set(gr, separators) == expected) {
                    193:                        /* Move down if we are past the end of the line. */
                    194:                        if (gr->cx > xx) {
                    195:                                if (gr->cy == yy)
                    196:                                        return;
                    197:                                grid_reader_cursor_start_of_line(gr, 0);
                    198:                                grid_reader_cursor_down(gr);
                    199:
                    200:                                if (grid_get_line(gr->gd, gr->cy)->flags &
                    201:                                    GRID_LINE_WRAPPED)
1.3       nicm      202:                                        xx = gr->gd->sx - 1;
1.1       nicm      203:                                else
                    204:                                        xx = grid_reader_line_length(gr);
                    205:                        } else
                    206:                                gr->cx++;
                    207:                }
                    208:                expected = !expected;
                    209:        } while (expected == 1);
                    210: }
                    211:
                    212: /* Move cursor to the end of the next word. */
                    213: void
                    214: grid_reader_cursor_next_word_end(struct grid_reader *gr, const char *separators)
                    215: {
                    216:        u_int   xx, yy;
                    217:        int     expected = 1;
                    218:
                    219:        /* Do not break up wrapped words. */
                    220:        if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
1.3       nicm      221:                xx = gr->gd->sx - 1;
1.1       nicm      222:        else
                    223:                xx = grid_reader_line_length(gr);
                    224:        yy = gr->gd->hsize + gr->gd->sy - 1;
                    225:
                    226:        /*
                    227:         * If we started on a separator, skip over separators. Then skip over
                    228:         * word characters till the next separator.
                    229:         *
                    230:         * expected is initially set to 1 for the former and then 1 for the
                    231:         * latter. It is finally set to 1 when the end of the next word is
                    232:         * found.
                    233:         */
                    234:        do {
                    235:                while (gr->cx > xx ||
                    236:                    grid_reader_in_set(gr, separators) == expected) {
                    237:                        /* Move down if we are past the end of the line. */
                    238:                        if (gr->cx > xx) {
                    239:                                if (gr->cy == yy)
                    240:                                        return;
                    241:                                grid_reader_cursor_start_of_line(gr, 0);
                    242:                                grid_reader_cursor_down(gr);
                    243:
                    244:                                if (grid_get_line(gr->gd, gr->cy)->flags &
                    245:                                    GRID_LINE_WRAPPED)
1.3       nicm      246:                                        xx = gr->gd->sx - 1;
1.1       nicm      247:                                else
                    248:                                        xx = grid_reader_line_length(gr);
                    249:                        } else
                    250:                                gr->cx++;
                    251:                }
                    252:                expected = !expected;
                    253:        } while (expected == 0);
                    254: }
                    255:
                    256: /* Move to the previous place where a word begins. */
                    257: void
                    258: grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators,
                    259:     int already)
                    260: {
                    261:        int     oldx, oldy, r;
                    262:
                    263:        /* Move back to the previous word character. */
                    264:        if (already || grid_reader_in_set(gr, separators)) {
                    265:                for (;;) {
                    266:                        if (gr->cx > 0) {
                    267:                                gr->cx--;
                    268:                                if (!grid_reader_in_set(gr, separators))
                    269:                                        break;
                    270:                        } else {
                    271:                                if (gr->cy == 0)
                    272:                                        return;
                    273:                                grid_reader_cursor_up(gr);
                    274:                                grid_reader_cursor_end_of_line(gr, 0, 0);
                    275:
                    276:                                /* Stop if separator at EOL. */
                    277:                                if (gr->cx > 0) {
                    278:                                        oldx = gr->cx;
                    279:                                        gr->cx--;
                    280:                                        r = grid_reader_in_set(gr, separators);
                    281:                                        gr->cx = oldx;
                    282:                                        if (r)
                    283:                                                break;
                    284:                                }
                    285:                        }
                    286:                }
                    287:        }
                    288:
                    289:        /* Move back to the beginning of this word. */
                    290:        do {
                    291:                oldx = gr->cx;
                    292:                oldy = gr->cy;
                    293:                if (gr->cx == 0) {
                    294:                        if (gr->cy == 0 ||
                    295:                          ~grid_get_line(gr->gd, gr->cy - 1)->flags &
                    296:                          GRID_LINE_WRAPPED)
                    297:                                break;
                    298:                        grid_reader_cursor_up(gr);
1.3       nicm      299:                        grid_reader_cursor_end_of_line(gr, 0, 1);
1.1       nicm      300:                }
                    301:                if (gr->cx > 0)
                    302:                        gr->cx--;
                    303:        } while (!grid_reader_in_set(gr, separators));
                    304:        gr->cx = oldx;
                    305:        gr->cy = oldy;
1.2       nicm      306: }
                    307:
                    308: /* Jump forward to character. */
                    309: int
                    310: grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc)
                    311: {
                    312:        struct grid_cell        gc;
                    313:        u_int                   px, py, xx, yy;
                    314:
                    315:        px = gr->cx;
                    316:        yy = gr->gd->hsize + gr->gd->sy - 1;
                    317:
                    318:        for (py = gr->cy; py <= yy; py++) {
                    319:                xx = grid_line_length(gr->gd, py);
                    320:                while (px < xx) {
                    321:                        grid_get_cell(gr->gd, px, py, &gc);
                    322:                        if (!(gc.flags & GRID_FLAG_PADDING) &&
                    323:                            gc.data.size == jc->size &&
                    324:                            memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
                    325:                                gr->cx = px;
                    326:                                gr->cy = py;
                    327:                                return 1;
                    328:                        }
                    329:                        px++;
                    330:                }
                    331:
                    332:                if (py == yy ||
                    333:                    !(grid_get_line(gr->gd, py)->flags & GRID_LINE_WRAPPED))
                    334:                        return 0;
                    335:                px = 0;
                    336:        }
                    337:        return 0;
                    338: }
                    339:
                    340: /* Jump back to character. */
                    341: int
                    342: grid_reader_cursor_jump_back(struct grid_reader *gr, const struct utf8_data *jc)
                    343: {
                    344:        struct grid_cell        gc;
                    345:        u_int                   px, py, xx;
                    346:
                    347:        xx = gr->cx + 1;
                    348:
                    349:        for (py = gr->cy + 1; py > 0; py--) {
                    350:                for (px = xx; px > 0; px--) {
                    351:                        grid_get_cell(gr->gd, px - 1, py - 1, &gc);
                    352:                        if (!(gc.flags & GRID_FLAG_PADDING) &&
                    353:                            gc.data.size == jc->size &&
                    354:                            memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
                    355:                                gr->cx = px - 1;
                    356:                                gr->cy = py - 1;
                    357:                                return 1;
                    358:                        }
                    359:                }
                    360:
                    361:                if (py == 1 ||
                    362:                    !(grid_get_line(gr->gd, py - 2)->flags & GRID_LINE_WRAPPED))
                    363:                        return 0;
                    364:                xx = grid_line_length(gr->gd, py - 2);
                    365:        }
                    366:        return 0;
1.4       nicm      367: }
                    368:
                    369: /* Jump back to the first non-blank character of the line. */
                    370: void
                    371: grid_reader_cursor_back_to_indentation(struct grid_reader *gr)
                    372: {
                    373:        struct grid_cell        gc;
1.5     ! nicm      374:        u_int                   px, py, xx, yy, oldx, oldy;
1.4       nicm      375:
                    376:        yy = gr->gd->hsize + gr->gd->sy - 1;
1.5     ! nicm      377:        oldx = gr->cx;
        !           378:        oldy = gr->cy;
1.4       nicm      379:        grid_reader_cursor_start_of_line(gr, 1);
                    380:
                    381:        for (py = gr->cy; py <= yy; py++) {
                    382:                xx = grid_line_length(gr->gd, py);
                    383:                for (px = 0; px < xx; px++) {
                    384:                        grid_get_cell(gr->gd, px, py, &gc);
1.5     ! nicm      385:                        if (gc.data.size != 1 || *gc.data.data != ' ') {
        !           386:                                gr->cx = px;
        !           387:                                gr->cy = py;
        !           388:                                return;
        !           389:                        }
1.4       nicm      390:                }
                    391:                if (~grid_get_line(gr->gd, py)->flags & GRID_LINE_WRAPPED)
                    392:                        break;
                    393:        }
1.5     ! nicm      394:        gr->cx = oldx;
        !           395:        gr->cy = oldy;
1.1       nicm      396: }