Annotation of src/usr.bin/tmux/grid-reader.c, Revision 1.1
1.1 ! nicm 1: /* $OpenBSD$ */
! 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"
! 20:
! 21: /* Initialise virtual cursor. */
! 22: void
! 23: grid_reader_start(struct grid_reader *gr, struct grid *gd, u_int cx, u_int cy)
! 24: {
! 25: gr->gd = gd;
! 26: gr->cx = cx;
! 27: gr->cy = cy;
! 28: }
! 29:
! 30: /* Get cursor position from reader. */
! 31: void
! 32: grid_reader_get_cursor(struct grid_reader *gr, u_int *cx, u_int *cy)
! 33: {
! 34: *cx = gr->cx;
! 35: *cy = gr->cy;
! 36: }
! 37:
! 38: /* Get length of line containing the cursor. */
! 39: u_int
! 40: grid_reader_line_length(struct grid_reader *gr)
! 41: {
! 42: return (grid_line_length(gr->gd, gr->cy));
! 43: }
! 44:
! 45: /* Move cursor forward one position. */
! 46: void
! 47: grid_reader_cursor_right(struct grid_reader *gr, int wrap, int all)
! 48: {
! 49: u_int px;
! 50: struct grid_cell gc;
! 51:
! 52: if (all)
! 53: px = gr->gd->sx;
! 54: else
! 55: px = grid_reader_line_length(gr);
! 56:
! 57: if (wrap && gr->cx >= px && gr->cy < gr->gd->hsize + gr->gd->sy - 1) {
! 58: grid_reader_cursor_start_of_line(gr, 0);
! 59: grid_reader_cursor_down(gr);
! 60: } else if (gr->cx < px) {
! 61: gr->cx++;
! 62: while (gr->cx < px) {
! 63: grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
! 64: if (~gc.flags & GRID_FLAG_PADDING)
! 65: break;
! 66: gr->cx++;
! 67: }
! 68: }
! 69: }
! 70:
! 71: /* Move cursor back one position. */
! 72: void
! 73: grid_reader_cursor_left(struct grid_reader *gr)
! 74: {
! 75: struct grid_cell gc;
! 76:
! 77: while (gr->cx > 0) {
! 78: grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
! 79: if (~gc.flags & GRID_FLAG_PADDING)
! 80: break;
! 81: gr->cx--;
! 82: }
! 83: if (gr->cx == 0 && gr->cy > 0) {
! 84: grid_reader_cursor_up(gr);
! 85: grid_reader_cursor_end_of_line(gr, 0, 0);
! 86: } else if (gr->cx > 0)
! 87: gr->cx--;
! 88: }
! 89:
! 90: /* Move cursor down one line. */
! 91: void
! 92: grid_reader_cursor_down(struct grid_reader *gr)
! 93: {
! 94: struct grid_cell gc;
! 95:
! 96: if (gr->cy < gr->gd->hsize + gr->gd->sy - 1)
! 97: gr->cy++;
! 98: while (gr->cx > 0) {
! 99: grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
! 100: if (~gc.flags & GRID_FLAG_PADDING)
! 101: break;
! 102: gr->cx--;
! 103: }
! 104: }
! 105:
! 106: /* Move cursor up one line. */
! 107: void
! 108: grid_reader_cursor_up(struct grid_reader *gr)
! 109: {
! 110: struct grid_cell gc;
! 111:
! 112: if (gr->cy > 0)
! 113: gr->cy--;
! 114: while (gr->cx > 0) {
! 115: grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
! 116: if (~gc.flags & GRID_FLAG_PADDING)
! 117: break;
! 118: gr->cx--;
! 119: }
! 120: }
! 121:
! 122: /* Move cursor to the start of the line. */
! 123: void
! 124: grid_reader_cursor_start_of_line(struct grid_reader *gr, int wrap)
! 125: {
! 126: if (wrap) {
! 127: while (gr->cy > 0 &&
! 128: grid_get_line(gr->gd, gr->cy - 1)->flags &
! 129: GRID_LINE_WRAPPED)
! 130: gr->cy--;
! 131: }
! 132: gr->cx = 0;
! 133: }
! 134:
! 135: /* Move cursor to the end of the line. */
! 136: void
! 137: grid_reader_cursor_end_of_line(struct grid_reader *gr, int wrap, int all)
! 138: {
! 139: u_int yy;
! 140:
! 141: if (wrap) {
! 142: yy = gr->gd->hsize + gr->gd->sy - 1;
! 143: while (gr->cy < yy && grid_get_line(gr->gd, gr->cy)->flags &
! 144: GRID_LINE_WRAPPED)
! 145: gr->cy++;
! 146: }
! 147: if (all)
! 148: gr->cx = gr->gd->sx;
! 149: else
! 150: gr->cx = grid_reader_line_length(gr);
! 151: }
! 152:
! 153: /* Check if character under cursor is in set. */
! 154: int
! 155: grid_reader_in_set(struct grid_reader *gr, const char *set)
! 156: {
! 157: struct grid_cell gc;
! 158:
! 159: grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
! 160: if (gc.flags & GRID_FLAG_PADDING)
! 161: return (0);
! 162: return (utf8_cstrhas(set, &gc.data));
! 163: }
! 164:
! 165: /* Move cursor to the start of the next word. */
! 166: void
! 167: grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators)
! 168: {
! 169: u_int xx, yy;
! 170: int expected = 0;
! 171:
! 172: /* Do not break up wrapped words. */
! 173: if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
! 174: xx = grid_reader_line_length(gr) - 1;
! 175: else
! 176: xx = grid_reader_line_length(gr);
! 177: yy = gr->gd->hsize + gr->gd->sy - 1;
! 178:
! 179: /*
! 180: * If we started inside a word, skip over word characters. Then skip
! 181: * over separators till the next word.
! 182: *
! 183: * expected is initially set to 0 for the former and then 1 for the
! 184: * latter. It is finally set to 0 when the beginning of the next word is
! 185: * found.
! 186: */
! 187: do {
! 188: while (gr->cx > xx ||
! 189: grid_reader_in_set(gr, separators) == expected) {
! 190: /* Move down if we are past the end of the line. */
! 191: if (gr->cx > xx) {
! 192: if (gr->cy == yy)
! 193: return;
! 194: grid_reader_cursor_start_of_line(gr, 0);
! 195: grid_reader_cursor_down(gr);
! 196:
! 197: if (grid_get_line(gr->gd, gr->cy)->flags &
! 198: GRID_LINE_WRAPPED)
! 199: xx = grid_reader_line_length(gr) - 1;
! 200: else
! 201: xx = grid_reader_line_length(gr);
! 202: } else
! 203: gr->cx++;
! 204: }
! 205: expected = !expected;
! 206: } while (expected == 1);
! 207: }
! 208:
! 209: /* Move cursor to the end of the next word. */
! 210: void
! 211: grid_reader_cursor_next_word_end(struct grid_reader *gr, const char *separators)
! 212: {
! 213: u_int xx, yy;
! 214: int expected = 1;
! 215:
! 216: /* Do not break up wrapped words. */
! 217: if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
! 218: xx = grid_reader_line_length(gr) - 1;
! 219: else
! 220: xx = grid_reader_line_length(gr);
! 221: yy = gr->gd->hsize + gr->gd->sy - 1;
! 222:
! 223: /*
! 224: * If we started on a separator, skip over separators. Then skip over
! 225: * word characters till the next separator.
! 226: *
! 227: * expected is initially set to 1 for the former and then 1 for the
! 228: * latter. It is finally set to 1 when the end of the next word is
! 229: * found.
! 230: */
! 231: do {
! 232: while (gr->cx > xx ||
! 233: grid_reader_in_set(gr, separators) == expected) {
! 234: /* Move down if we are past the end of the line. */
! 235: if (gr->cx > xx) {
! 236: if (gr->cy == yy)
! 237: return;
! 238: grid_reader_cursor_start_of_line(gr, 0);
! 239: grid_reader_cursor_down(gr);
! 240:
! 241: if (grid_get_line(gr->gd, gr->cy)->flags &
! 242: GRID_LINE_WRAPPED)
! 243: xx = grid_reader_line_length(gr) - 1;
! 244: else
! 245: xx = grid_reader_line_length(gr);
! 246: } else
! 247: gr->cx++;
! 248: }
! 249: expected = !expected;
! 250: } while (expected == 0);
! 251: }
! 252:
! 253: /* Move to the previous place where a word begins. */
! 254: void
! 255: grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators,
! 256: int already)
! 257: {
! 258: int oldx, oldy, r;
! 259:
! 260: /* Move back to the previous word character. */
! 261: if (already || grid_reader_in_set(gr, separators)) {
! 262: for (;;) {
! 263: if (gr->cx > 0) {
! 264: gr->cx--;
! 265: if (!grid_reader_in_set(gr, separators))
! 266: break;
! 267: } else {
! 268: if (gr->cy == 0)
! 269: return;
! 270: grid_reader_cursor_up(gr);
! 271: grid_reader_cursor_end_of_line(gr, 0, 0);
! 272:
! 273: /* Stop if separator at EOL. */
! 274: if (gr->cx > 0) {
! 275: oldx = gr->cx;
! 276: gr->cx--;
! 277: r = grid_reader_in_set(gr, separators);
! 278: gr->cx = oldx;
! 279: if (r)
! 280: break;
! 281: }
! 282: }
! 283: }
! 284: }
! 285:
! 286: /* Move back to the beginning of this word. */
! 287: do {
! 288: oldx = gr->cx;
! 289: oldy = gr->cy;
! 290: if (gr->cx == 0) {
! 291: if (gr->cy == 0 ||
! 292: ~grid_get_line(gr->gd, gr->cy - 1)->flags &
! 293: GRID_LINE_WRAPPED)
! 294: break;
! 295: grid_reader_cursor_up(gr);
! 296: grid_reader_cursor_end_of_line(gr, 0, 0);
! 297: }
! 298: if (gr->cx > 0)
! 299: gr->cx--;
! 300: } while (!grid_reader_in_set(gr, separators));
! 301: gr->cx = oldx;
! 302: gr->cy = oldy;
! 303: }