Annotation of src/usr.bin/tmux/grid-reader.c, Revision 1.2
1.2 ! nicm 1: /* $OpenBSD: grid-reader.c,v 1.1 2020/12/22 09:22:14 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
74: grid_reader_cursor_left(struct grid_reader *gr)
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: }
84: if (gr->cx == 0 && gr->cy > 0) {
85: grid_reader_cursor_up(gr);
86: grid_reader_cursor_end_of_line(gr, 0, 0);
87: } else if (gr->cx > 0)
88: gr->cx--;
89: }
90:
91: /* Move cursor down one line. */
92: void
93: grid_reader_cursor_down(struct grid_reader *gr)
94: {
95: struct grid_cell gc;
96:
97: if (gr->cy < gr->gd->hsize + gr->gd->sy - 1)
98: gr->cy++;
99: while (gr->cx > 0) {
100: grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
101: if (~gc.flags & GRID_FLAG_PADDING)
102: break;
103: gr->cx--;
104: }
105: }
106:
107: /* Move cursor up one line. */
108: void
109: grid_reader_cursor_up(struct grid_reader *gr)
110: {
111: struct grid_cell gc;
112:
113: if (gr->cy > 0)
114: gr->cy--;
115: while (gr->cx > 0) {
116: grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
117: if (~gc.flags & GRID_FLAG_PADDING)
118: break;
119: gr->cx--;
120: }
121: }
122:
123: /* Move cursor to the start of the line. */
124: void
125: grid_reader_cursor_start_of_line(struct grid_reader *gr, int wrap)
126: {
127: if (wrap) {
128: while (gr->cy > 0 &&
129: grid_get_line(gr->gd, gr->cy - 1)->flags &
130: GRID_LINE_WRAPPED)
131: gr->cy--;
132: }
133: gr->cx = 0;
134: }
135:
136: /* Move cursor to the end of the line. */
137: void
138: grid_reader_cursor_end_of_line(struct grid_reader *gr, int wrap, int all)
139: {
140: u_int yy;
141:
142: if (wrap) {
143: yy = gr->gd->hsize + gr->gd->sy - 1;
144: while (gr->cy < yy && grid_get_line(gr->gd, gr->cy)->flags &
145: GRID_LINE_WRAPPED)
146: gr->cy++;
147: }
148: if (all)
149: gr->cx = gr->gd->sx;
150: else
151: gr->cx = grid_reader_line_length(gr);
152: }
153:
154: /* Check if character under cursor is in set. */
155: int
156: grid_reader_in_set(struct grid_reader *gr, const char *set)
157: {
158: struct grid_cell gc;
159:
160: grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
161: if (gc.flags & GRID_FLAG_PADDING)
162: return (0);
163: return (utf8_cstrhas(set, &gc.data));
164: }
165:
166: /* Move cursor to the start of the next word. */
167: void
168: grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators)
169: {
170: u_int xx, yy;
171: int expected = 0;
172:
173: /* Do not break up wrapped words. */
174: if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
175: xx = grid_reader_line_length(gr) - 1;
176: else
177: xx = grid_reader_line_length(gr);
178: yy = gr->gd->hsize + gr->gd->sy - 1;
179:
180: /*
181: * If we started inside a word, skip over word characters. Then skip
182: * over separators till the next word.
183: *
184: * expected is initially set to 0 for the former and then 1 for the
185: * latter. It is finally set to 0 when the beginning of the next word is
186: * found.
187: */
188: do {
189: while (gr->cx > xx ||
190: grid_reader_in_set(gr, separators) == expected) {
191: /* Move down if we are past the end of the line. */
192: if (gr->cx > xx) {
193: if (gr->cy == yy)
194: return;
195: grid_reader_cursor_start_of_line(gr, 0);
196: grid_reader_cursor_down(gr);
197:
198: if (grid_get_line(gr->gd, gr->cy)->flags &
199: GRID_LINE_WRAPPED)
200: xx = grid_reader_line_length(gr) - 1;
201: else
202: xx = grid_reader_line_length(gr);
203: } else
204: gr->cx++;
205: }
206: expected = !expected;
207: } while (expected == 1);
208: }
209:
210: /* Move cursor to the end of the next word. */
211: void
212: grid_reader_cursor_next_word_end(struct grid_reader *gr, const char *separators)
213: {
214: u_int xx, yy;
215: int expected = 1;
216:
217: /* Do not break up wrapped words. */
218: if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
219: xx = grid_reader_line_length(gr) - 1;
220: else
221: xx = grid_reader_line_length(gr);
222: yy = gr->gd->hsize + gr->gd->sy - 1;
223:
224: /*
225: * If we started on a separator, skip over separators. Then skip over
226: * word characters till the next separator.
227: *
228: * expected is initially set to 1 for the former and then 1 for the
229: * latter. It is finally set to 1 when the end of the next word is
230: * found.
231: */
232: do {
233: while (gr->cx > xx ||
234: grid_reader_in_set(gr, separators) == expected) {
235: /* Move down if we are past the end of the line. */
236: if (gr->cx > xx) {
237: if (gr->cy == yy)
238: return;
239: grid_reader_cursor_start_of_line(gr, 0);
240: grid_reader_cursor_down(gr);
241:
242: if (grid_get_line(gr->gd, gr->cy)->flags &
243: GRID_LINE_WRAPPED)
244: xx = grid_reader_line_length(gr) - 1;
245: else
246: xx = grid_reader_line_length(gr);
247: } else
248: gr->cx++;
249: }
250: expected = !expected;
251: } while (expected == 0);
252: }
253:
254: /* Move to the previous place where a word begins. */
255: void
256: grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators,
257: int already)
258: {
259: int oldx, oldy, r;
260:
261: /* Move back to the previous word character. */
262: if (already || grid_reader_in_set(gr, separators)) {
263: for (;;) {
264: if (gr->cx > 0) {
265: gr->cx--;
266: if (!grid_reader_in_set(gr, separators))
267: break;
268: } else {
269: if (gr->cy == 0)
270: return;
271: grid_reader_cursor_up(gr);
272: grid_reader_cursor_end_of_line(gr, 0, 0);
273:
274: /* Stop if separator at EOL. */
275: if (gr->cx > 0) {
276: oldx = gr->cx;
277: gr->cx--;
278: r = grid_reader_in_set(gr, separators);
279: gr->cx = oldx;
280: if (r)
281: break;
282: }
283: }
284: }
285: }
286:
287: /* Move back to the beginning of this word. */
288: do {
289: oldx = gr->cx;
290: oldy = gr->cy;
291: if (gr->cx == 0) {
292: if (gr->cy == 0 ||
293: ~grid_get_line(gr->gd, gr->cy - 1)->flags &
294: GRID_LINE_WRAPPED)
295: break;
296: grid_reader_cursor_up(gr);
297: grid_reader_cursor_end_of_line(gr, 0, 0);
298: }
299: if (gr->cx > 0)
300: gr->cx--;
301: } while (!grid_reader_in_set(gr, separators));
302: gr->cx = oldx;
303: gr->cy = oldy;
1.2 ! nicm 304: }
! 305:
! 306: /* Jump forward to character. */
! 307: int
! 308: grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc)
! 309: {
! 310: struct grid_cell gc;
! 311: u_int px, py, xx, yy;
! 312:
! 313: px = gr->cx;
! 314: yy = gr->gd->hsize + gr->gd->sy - 1;
! 315:
! 316: for (py = gr->cy; py <= yy; py++) {
! 317: xx = grid_line_length(gr->gd, py);
! 318: while (px < xx) {
! 319: grid_get_cell(gr->gd, px, py, &gc);
! 320: if (!(gc.flags & GRID_FLAG_PADDING) &&
! 321: gc.data.size == jc->size &&
! 322: memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
! 323: gr->cx = px;
! 324: gr->cy = py;
! 325: return 1;
! 326: }
! 327: px++;
! 328: }
! 329:
! 330: if (py == yy ||
! 331: !(grid_get_line(gr->gd, py)->flags & GRID_LINE_WRAPPED))
! 332: return 0;
! 333: px = 0;
! 334: }
! 335: return 0;
! 336: }
! 337:
! 338: /* Jump back to character. */
! 339: int
! 340: grid_reader_cursor_jump_back(struct grid_reader *gr, const struct utf8_data *jc)
! 341: {
! 342: struct grid_cell gc;
! 343: u_int px, py, xx;
! 344:
! 345: xx = gr->cx + 1;
! 346:
! 347: for (py = gr->cy + 1; py > 0; py--) {
! 348: for (px = xx; px > 0; px--) {
! 349: grid_get_cell(gr->gd, px - 1, py - 1, &gc);
! 350: if (!(gc.flags & GRID_FLAG_PADDING) &&
! 351: gc.data.size == jc->size &&
! 352: memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
! 353: gr->cx = px - 1;
! 354: gr->cy = py - 1;
! 355: return 1;
! 356: }
! 357: }
! 358:
! 359: if (py == 1 ||
! 360: !(grid_get_line(gr->gd, py - 2)->flags & GRID_LINE_WRAPPED))
! 361: return 0;
! 362: xx = grid_line_length(gr->gd, py - 2);
! 363: }
! 364: return 0;
1.1 nicm 365: }