xref: /netbsd-src/external/bsd/tmux/dist/grid-reader.c (revision 6db267571823ee3b0a1d61478df085a087f2e990)
19fb66d81Schristos /* $OpenBSD$ */
29fb66d81Schristos 
39fb66d81Schristos /*
49fb66d81Schristos  * Copyright (c) 2020 Anindya Mukherjee <anindya49@hotmail.com>
59fb66d81Schristos  *
69fb66d81Schristos  * Permission to use, copy, modify, and distribute this software for any
79fb66d81Schristos  * purpose with or without fee is hereby granted, provided that the above
89fb66d81Schristos  * copyright notice and this permission notice appear in all copies.
99fb66d81Schristos  *
109fb66d81Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
119fb66d81Schristos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
129fb66d81Schristos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
139fb66d81Schristos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
149fb66d81Schristos  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
159fb66d81Schristos  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
169fb66d81Schristos  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
179fb66d81Schristos  */
189fb66d81Schristos 
199fb66d81Schristos #include "tmux.h"
209fb66d81Schristos #include <string.h>
219fb66d81Schristos 
229fb66d81Schristos /* Initialise virtual cursor. */
239fb66d81Schristos void
grid_reader_start(struct grid_reader * gr,struct grid * gd,u_int cx,u_int cy)249fb66d81Schristos grid_reader_start(struct grid_reader *gr, struct grid *gd, u_int cx, u_int cy)
259fb66d81Schristos {
269fb66d81Schristos 	gr->gd = gd;
279fb66d81Schristos 	gr->cx = cx;
289fb66d81Schristos 	gr->cy = cy;
299fb66d81Schristos }
309fb66d81Schristos 
319fb66d81Schristos /* Get cursor position from reader. */
329fb66d81Schristos void
grid_reader_get_cursor(struct grid_reader * gr,u_int * cx,u_int * cy)339fb66d81Schristos grid_reader_get_cursor(struct grid_reader *gr, u_int *cx, u_int *cy)
349fb66d81Schristos {
359fb66d81Schristos 	*cx = gr->cx;
369fb66d81Schristos 	*cy = gr->cy;
379fb66d81Schristos }
389fb66d81Schristos 
399fb66d81Schristos /* Get length of line containing the cursor. */
409fb66d81Schristos u_int
grid_reader_line_length(struct grid_reader * gr)419fb66d81Schristos grid_reader_line_length(struct grid_reader *gr)
429fb66d81Schristos {
439fb66d81Schristos 	return (grid_line_length(gr->gd, gr->cy));
449fb66d81Schristos }
459fb66d81Schristos 
469fb66d81Schristos /* Move cursor forward one position. */
479fb66d81Schristos void
grid_reader_cursor_right(struct grid_reader * gr,int wrap,int all)489fb66d81Schristos grid_reader_cursor_right(struct grid_reader *gr, int wrap, int all)
499fb66d81Schristos {
509fb66d81Schristos 	u_int			px;
519fb66d81Schristos 	struct grid_cell	gc;
529fb66d81Schristos 
539fb66d81Schristos 	if (all)
549fb66d81Schristos 		px = gr->gd->sx;
559fb66d81Schristos 	else
569fb66d81Schristos 		px = grid_reader_line_length(gr);
579fb66d81Schristos 
589fb66d81Schristos 	if (wrap && gr->cx >= px && gr->cy < gr->gd->hsize + gr->gd->sy - 1) {
599fb66d81Schristos 		grid_reader_cursor_start_of_line(gr, 0);
609fb66d81Schristos 		grid_reader_cursor_down(gr);
619fb66d81Schristos 	} else if (gr->cx < px) {
629fb66d81Schristos 		gr->cx++;
639fb66d81Schristos 		while (gr->cx < px) {
649fb66d81Schristos 			grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
659fb66d81Schristos 			if (~gc.flags & GRID_FLAG_PADDING)
669fb66d81Schristos 				break;
679fb66d81Schristos 			gr->cx++;
689fb66d81Schristos 		}
699fb66d81Schristos 	}
709fb66d81Schristos }
719fb66d81Schristos 
729fb66d81Schristos /* Move cursor back one position. */
739fb66d81Schristos void
grid_reader_cursor_left(struct grid_reader * gr,int wrap)749fb66d81Schristos grid_reader_cursor_left(struct grid_reader *gr, int wrap)
759fb66d81Schristos {
769fb66d81Schristos 	struct grid_cell	gc;
779fb66d81Schristos 
789fb66d81Schristos 	while (gr->cx > 0) {
799fb66d81Schristos 		grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
809fb66d81Schristos 		if (~gc.flags & GRID_FLAG_PADDING)
819fb66d81Schristos 			break;
829fb66d81Schristos 		gr->cx--;
839fb66d81Schristos 	}
849fb66d81Schristos 	if (gr->cx == 0 && gr->cy > 0 &&
859fb66d81Schristos 	    (wrap ||
869fb66d81Schristos 	     grid_get_line(gr->gd, gr->cy - 1)->flags & GRID_LINE_WRAPPED)) {
879fb66d81Schristos 		grid_reader_cursor_up(gr);
889fb66d81Schristos 		grid_reader_cursor_end_of_line(gr, 0, 0);
899fb66d81Schristos 	} else if (gr->cx > 0)
909fb66d81Schristos 		gr->cx--;
919fb66d81Schristos }
929fb66d81Schristos 
939fb66d81Schristos /* Move cursor down one line. */
949fb66d81Schristos void
grid_reader_cursor_down(struct grid_reader * gr)959fb66d81Schristos grid_reader_cursor_down(struct grid_reader *gr)
969fb66d81Schristos {
979fb66d81Schristos 	struct grid_cell	gc;
989fb66d81Schristos 
999fb66d81Schristos 	if (gr->cy < gr->gd->hsize + gr->gd->sy - 1)
1009fb66d81Schristos 		gr->cy++;
1019fb66d81Schristos 	while (gr->cx > 0) {
1029fb66d81Schristos 		grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
1039fb66d81Schristos 		if (~gc.flags & GRID_FLAG_PADDING)
1049fb66d81Schristos 			break;
1059fb66d81Schristos 		gr->cx--;
1069fb66d81Schristos 	}
1079fb66d81Schristos }
1089fb66d81Schristos 
1099fb66d81Schristos /* Move cursor up one line. */
1109fb66d81Schristos void
grid_reader_cursor_up(struct grid_reader * gr)1119fb66d81Schristos grid_reader_cursor_up(struct grid_reader *gr)
1129fb66d81Schristos {
1139fb66d81Schristos 	struct grid_cell	gc;
1149fb66d81Schristos 
1159fb66d81Schristos 	if (gr->cy > 0)
1169fb66d81Schristos 		gr->cy--;
1179fb66d81Schristos 	while (gr->cx > 0) {
1189fb66d81Schristos 		grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
1199fb66d81Schristos 		if (~gc.flags & GRID_FLAG_PADDING)
1209fb66d81Schristos 			break;
1219fb66d81Schristos 		gr->cx--;
1229fb66d81Schristos 	}
1239fb66d81Schristos }
1249fb66d81Schristos 
1259fb66d81Schristos /* Move cursor to the start of the line. */
1269fb66d81Schristos void
grid_reader_cursor_start_of_line(struct grid_reader * gr,int wrap)1279fb66d81Schristos grid_reader_cursor_start_of_line(struct grid_reader *gr, int wrap)
1289fb66d81Schristos {
1299fb66d81Schristos 	if (wrap) {
1309fb66d81Schristos 		while (gr->cy > 0 &&
1319fb66d81Schristos 		    grid_get_line(gr->gd, gr->cy - 1)->flags &
1329fb66d81Schristos 		        GRID_LINE_WRAPPED)
1339fb66d81Schristos 			gr->cy--;
1349fb66d81Schristos 	}
1359fb66d81Schristos 	gr->cx = 0;
1369fb66d81Schristos }
1379fb66d81Schristos 
1389fb66d81Schristos /* Move cursor to the end of the line. */
1399fb66d81Schristos void
grid_reader_cursor_end_of_line(struct grid_reader * gr,int wrap,int all)1409fb66d81Schristos grid_reader_cursor_end_of_line(struct grid_reader *gr, int wrap, int all)
1419fb66d81Schristos {
1429fb66d81Schristos 	u_int	yy;
1439fb66d81Schristos 
1449fb66d81Schristos 	if (wrap) {
1459fb66d81Schristos 		yy = gr->gd->hsize + gr->gd->sy - 1;
1469fb66d81Schristos 		while (gr->cy < yy && grid_get_line(gr->gd, gr->cy)->flags &
1479fb66d81Schristos 		    GRID_LINE_WRAPPED)
1489fb66d81Schristos 			gr->cy++;
1499fb66d81Schristos 	}
1509fb66d81Schristos 	if (all)
1519fb66d81Schristos 		gr->cx = gr->gd->sx;
1529fb66d81Schristos 	else
1539fb66d81Schristos 		gr->cx = grid_reader_line_length(gr);
1549fb66d81Schristos }
1559fb66d81Schristos 
156*6db26757Swiz /* Handle line wrapping while moving the cursor. */
157*6db26757Swiz static int
grid_reader_handle_wrap(struct grid_reader * gr,u_int * xx,u_int * yy)158*6db26757Swiz grid_reader_handle_wrap(struct grid_reader *gr, u_int *xx, u_int *yy)
159*6db26757Swiz {
160*6db26757Swiz 	/*
161*6db26757Swiz 	 * Make sure the cursor lies within the grid reader's bounding area,
162*6db26757Swiz 	 * wrapping to the next line as necessary. Return zero if the cursor
163*6db26757Swiz 	 * would wrap past the bottom of the grid.
164*6db26757Swiz 	 */
165*6db26757Swiz 	while (gr->cx > *xx) {
166*6db26757Swiz 		if (gr->cy == *yy)
167*6db26757Swiz 			return (0);
168*6db26757Swiz 		grid_reader_cursor_start_of_line(gr, 0);
169*6db26757Swiz 		grid_reader_cursor_down(gr);
170*6db26757Swiz 
171*6db26757Swiz 		if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
172*6db26757Swiz 			*xx = gr->gd->sx - 1;
173*6db26757Swiz 		else
174*6db26757Swiz 			*xx = grid_reader_line_length(gr);
175*6db26757Swiz 	}
176*6db26757Swiz 	return (1);
177*6db26757Swiz }
178*6db26757Swiz 
1799fb66d81Schristos /* Check if character under cursor is in set. */
1809fb66d81Schristos int
grid_reader_in_set(struct grid_reader * gr,const char * set)1819fb66d81Schristos grid_reader_in_set(struct grid_reader *gr, const char *set)
1829fb66d81Schristos {
1839fb66d81Schristos 	struct grid_cell	gc;
1849fb66d81Schristos 
1859fb66d81Schristos 	grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
1869fb66d81Schristos 	if (gc.flags & GRID_FLAG_PADDING)
1879fb66d81Schristos 		return (0);
1889fb66d81Schristos 	return (utf8_cstrhas(set, &gc.data));
1899fb66d81Schristos }
1909fb66d81Schristos 
1919fb66d81Schristos /* Move cursor to the start of the next word. */
1929fb66d81Schristos void
grid_reader_cursor_next_word(struct grid_reader * gr,const char * separators)1939fb66d81Schristos grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators)
1949fb66d81Schristos {
1959fb66d81Schristos 	u_int	xx, yy;
1969fb66d81Schristos 
1979fb66d81Schristos 	/* Do not break up wrapped words. */
1989fb66d81Schristos 	if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
1999fb66d81Schristos 		xx = gr->gd->sx - 1;
2009fb66d81Schristos 	else
2019fb66d81Schristos 		xx = grid_reader_line_length(gr);
2029fb66d81Schristos 	yy = gr->gd->hsize + gr->gd->sy - 1;
2039fb66d81Schristos 
2049fb66d81Schristos 	/*
205*6db26757Swiz 	 * When navigating via spaces (for example with next-space) separators
206*6db26757Swiz 	 * should be empty.
2079fb66d81Schristos 	 *
208*6db26757Swiz 	 * If we started on a separator that is not whitespace, skip over
209*6db26757Swiz 	 * subsequent separators that are not whitespace. Otherwise, if we
210*6db26757Swiz 	 * started on a non-whitespace character, skip over subsequent
211*6db26757Swiz 	 * characters that are neither whitespace nor separators. Then, skip
212*6db26757Swiz 	 * over whitespace (if any) until the next non-whitespace character.
2139fb66d81Schristos 	 */
214*6db26757Swiz 	if (!grid_reader_handle_wrap(gr, &xx, &yy))
2159fb66d81Schristos 		return;
216*6db26757Swiz 	if (!grid_reader_in_set(gr, WHITESPACE)) {
217*6db26757Swiz 		if (grid_reader_in_set(gr, separators)) {
218*6db26757Swiz 			do
2199fb66d81Schristos 				gr->cx++;
220*6db26757Swiz 			while (grid_reader_handle_wrap(gr, &xx, &yy) &&
221*6db26757Swiz 			    grid_reader_in_set(gr, separators) &&
222*6db26757Swiz 			    !grid_reader_in_set(gr, WHITESPACE));
223*6db26757Swiz 		} else {
224*6db26757Swiz 			do
225*6db26757Swiz 				gr->cx++;
226*6db26757Swiz 			while (grid_reader_handle_wrap(gr, &xx, &yy) &&
227*6db26757Swiz 			    !(grid_reader_in_set(gr, separators) ||
228*6db26757Swiz 			    grid_reader_in_set(gr, WHITESPACE)));
2299fb66d81Schristos 		}
230*6db26757Swiz 	}
231*6db26757Swiz 	while (grid_reader_handle_wrap(gr, &xx, &yy) &&
232*6db26757Swiz 	    grid_reader_in_set(gr, WHITESPACE))
233*6db26757Swiz 		gr->cx++;
2349fb66d81Schristos }
2359fb66d81Schristos 
2369fb66d81Schristos /* Move cursor to the end of the next word. */
2379fb66d81Schristos void
grid_reader_cursor_next_word_end(struct grid_reader * gr,const char * separators)2389fb66d81Schristos grid_reader_cursor_next_word_end(struct grid_reader *gr, const char *separators)
2399fb66d81Schristos {
2409fb66d81Schristos 	u_int	xx, yy;
2419fb66d81Schristos 
2429fb66d81Schristos 	/* Do not break up wrapped words. */
2439fb66d81Schristos 	if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
2449fb66d81Schristos 		xx = gr->gd->sx - 1;
2459fb66d81Schristos 	else
2469fb66d81Schristos 		xx = grid_reader_line_length(gr);
2479fb66d81Schristos 	yy = gr->gd->hsize + gr->gd->sy - 1;
2489fb66d81Schristos 
2499fb66d81Schristos 	/*
250*6db26757Swiz 	 * When navigating via spaces (for example with next-space), separators
251*6db26757Swiz 	 * should be empty in both modes.
2529fb66d81Schristos 	 *
253*6db26757Swiz 	 * If we started on a whitespace, move until reaching the first
254*6db26757Swiz 	 * non-whitespace character. If that character is a separator, treat
255*6db26757Swiz 	 * subsequent separators as a word, and continue moving until the first
256*6db26757Swiz 	 * non-separator. Otherwise, continue moving until the first separator
257*6db26757Swiz 	 * or whitespace.
2589fb66d81Schristos 	 */
2599fb66d81Schristos 
260*6db26757Swiz 	while (grid_reader_handle_wrap(gr, &xx, &yy)) {
261*6db26757Swiz 		if (grid_reader_in_set(gr, WHITESPACE))
2629fb66d81Schristos 			gr->cx++;
263*6db26757Swiz 		else if (grid_reader_in_set(gr, separators)) {
264*6db26757Swiz 			do
265*6db26757Swiz 				gr->cx++;
266*6db26757Swiz 			while (grid_reader_handle_wrap(gr, &xx, &yy) &&
267*6db26757Swiz 			    grid_reader_in_set(gr, separators) &&
268*6db26757Swiz 			    !grid_reader_in_set(gr, WHITESPACE));
269*6db26757Swiz 			return;
270*6db26757Swiz 		} else {
271*6db26757Swiz 			do
272*6db26757Swiz 				gr->cx++;
273*6db26757Swiz 			while (grid_reader_handle_wrap(gr, &xx, &yy) &&
274*6db26757Swiz 			    !(grid_reader_in_set(gr, WHITESPACE) ||
275*6db26757Swiz 			    grid_reader_in_set(gr, separators)));
276*6db26757Swiz 			return;
2779fb66d81Schristos 		}
278*6db26757Swiz 	}
2799fb66d81Schristos }
2809fb66d81Schristos 
2819fb66d81Schristos /* Move to the previous place where a word begins. */
2829fb66d81Schristos void
grid_reader_cursor_previous_word(struct grid_reader * gr,const char * separators,int already,int stop_at_eol)2839fb66d81Schristos grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators,
284*6db26757Swiz     int already, int stop_at_eol)
2859fb66d81Schristos {
286*6db26757Swiz 	int	oldx, oldy, at_eol, word_is_letters;
2879fb66d81Schristos 
2889fb66d81Schristos 	/* Move back to the previous word character. */
289*6db26757Swiz 	if (already || grid_reader_in_set(gr, WHITESPACE)) {
2909fb66d81Schristos 		for (;;) {
2919fb66d81Schristos 			if (gr->cx > 0) {
2929fb66d81Schristos 				gr->cx--;
293*6db26757Swiz 				if (!grid_reader_in_set(gr, WHITESPACE)) {
294*6db26757Swiz 					word_is_letters =
295*6db26757Swiz 					    !grid_reader_in_set(gr, separators);
2969fb66d81Schristos 					break;
297*6db26757Swiz 				}
2989fb66d81Schristos 			} else {
2999fb66d81Schristos 				if (gr->cy == 0)
3009fb66d81Schristos 					return;
3019fb66d81Schristos 				grid_reader_cursor_up(gr);
3029fb66d81Schristos 				grid_reader_cursor_end_of_line(gr, 0, 0);
3039fb66d81Schristos 
3049fb66d81Schristos 				/* Stop if separator at EOL. */
305*6db26757Swiz 				if (stop_at_eol && gr->cx > 0) {
3069fb66d81Schristos 					oldx = gr->cx;
3079fb66d81Schristos 					gr->cx--;
308*6db26757Swiz 					at_eol = grid_reader_in_set(gr,
309*6db26757Swiz 					    WHITESPACE);
3109fb66d81Schristos 					gr->cx = oldx;
311*6db26757Swiz 					if (at_eol) {
312*6db26757Swiz 						word_is_letters = 0;
3139fb66d81Schristos 						break;
3149fb66d81Schristos 					}
3159fb66d81Schristos 				}
3169fb66d81Schristos 			}
3179fb66d81Schristos 		}
318*6db26757Swiz 	} else
319*6db26757Swiz 		word_is_letters = !grid_reader_in_set(gr, separators);
3209fb66d81Schristos 
3219fb66d81Schristos 	/* Move back to the beginning of this word. */
3229fb66d81Schristos 	do {
3239fb66d81Schristos 		oldx = gr->cx;
3249fb66d81Schristos 		oldy = gr->cy;
3259fb66d81Schristos 		if (gr->cx == 0) {
3269fb66d81Schristos 			if (gr->cy == 0 ||
327*6db26757Swiz 			    (~grid_get_line(gr->gd, gr->cy - 1)->flags &
328*6db26757Swiz 			    GRID_LINE_WRAPPED))
3299fb66d81Schristos 				break;
3309fb66d81Schristos 			grid_reader_cursor_up(gr);
3319fb66d81Schristos 			grid_reader_cursor_end_of_line(gr, 0, 1);
3329fb66d81Schristos 		}
3339fb66d81Schristos 		if (gr->cx > 0)
3349fb66d81Schristos 			gr->cx--;
335*6db26757Swiz 	} while (!grid_reader_in_set(gr, WHITESPACE) &&
336*6db26757Swiz 	    word_is_letters != grid_reader_in_set(gr, separators));
3379fb66d81Schristos 	gr->cx = oldx;
3389fb66d81Schristos 	gr->cy = oldy;
3399fb66d81Schristos }
3409fb66d81Schristos 
3419fb66d81Schristos /* Jump forward to character. */
3429fb66d81Schristos int
grid_reader_cursor_jump(struct grid_reader * gr,const struct utf8_data * jc)3439fb66d81Schristos grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc)
3449fb66d81Schristos {
3459fb66d81Schristos 	struct grid_cell	gc;
3469fb66d81Schristos 	u_int			px, py, xx, yy;
3479fb66d81Schristos 
3489fb66d81Schristos 	px = gr->cx;
3499fb66d81Schristos 	yy = gr->gd->hsize + gr->gd->sy - 1;
3509fb66d81Schristos 
3519fb66d81Schristos 	for (py = gr->cy; py <= yy; py++) {
3529fb66d81Schristos 		xx = grid_line_length(gr->gd, py);
3539fb66d81Schristos 		while (px < xx) {
3549fb66d81Schristos 			grid_get_cell(gr->gd, px, py, &gc);
3559fb66d81Schristos 			if (!(gc.flags & GRID_FLAG_PADDING) &&
3569fb66d81Schristos 			    gc.data.size == jc->size &&
3579fb66d81Schristos 			    memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
3589fb66d81Schristos 				gr->cx = px;
3599fb66d81Schristos 				gr->cy = py;
360*6db26757Swiz 				return (1);
3619fb66d81Schristos 			}
3629fb66d81Schristos 			px++;
3639fb66d81Schristos 		}
3649fb66d81Schristos 
3659fb66d81Schristos 		if (py == yy ||
3669fb66d81Schristos 		    !(grid_get_line(gr->gd, py)->flags & GRID_LINE_WRAPPED))
367*6db26757Swiz 			return (0);
3689fb66d81Schristos 		px = 0;
3699fb66d81Schristos 	}
370*6db26757Swiz 	return (0);
3719fb66d81Schristos }
3729fb66d81Schristos 
3739fb66d81Schristos /* Jump back to character. */
3749fb66d81Schristos int
grid_reader_cursor_jump_back(struct grid_reader * gr,const struct utf8_data * jc)3759fb66d81Schristos grid_reader_cursor_jump_back(struct grid_reader *gr, const struct utf8_data *jc)
3769fb66d81Schristos {
3779fb66d81Schristos 	struct grid_cell	gc;
3789fb66d81Schristos 	u_int			px, py, xx;
3799fb66d81Schristos 
3809fb66d81Schristos 	xx = gr->cx + 1;
3819fb66d81Schristos 
3829fb66d81Schristos 	for (py = gr->cy + 1; py > 0; py--) {
3839fb66d81Schristos 		for (px = xx; px > 0; px--) {
3849fb66d81Schristos 			grid_get_cell(gr->gd, px - 1, py - 1, &gc);
3859fb66d81Schristos 			if (!(gc.flags & GRID_FLAG_PADDING) &&
3869fb66d81Schristos 			    gc.data.size == jc->size &&
3879fb66d81Schristos 			    memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
3889fb66d81Schristos 				gr->cx = px - 1;
3899fb66d81Schristos 				gr->cy = py - 1;
390*6db26757Swiz 				return (1);
3919fb66d81Schristos 			}
3929fb66d81Schristos 		}
3939fb66d81Schristos 
3949fb66d81Schristos 		if (py == 1 ||
3959fb66d81Schristos 		    !(grid_get_line(gr->gd, py - 2)->flags & GRID_LINE_WRAPPED))
396*6db26757Swiz 			return (0);
3979fb66d81Schristos 		xx = grid_line_length(gr->gd, py - 2);
3989fb66d81Schristos 	}
399*6db26757Swiz 	return (0);
4009fb66d81Schristos }
4019fb66d81Schristos 
4029fb66d81Schristos /* Jump back to the first non-blank character of the line. */
4039fb66d81Schristos void
grid_reader_cursor_back_to_indentation(struct grid_reader * gr)4049fb66d81Schristos grid_reader_cursor_back_to_indentation(struct grid_reader *gr)
4059fb66d81Schristos {
4069fb66d81Schristos 	struct grid_cell	gc;
407de7701e2Schristos 	u_int			px, py, xx, yy, oldx, oldy;
4089fb66d81Schristos 
4099fb66d81Schristos 	yy = gr->gd->hsize + gr->gd->sy - 1;
410de7701e2Schristos 	oldx = gr->cx;
411de7701e2Schristos 	oldy = gr->cy;
4129fb66d81Schristos 	grid_reader_cursor_start_of_line(gr, 1);
4139fb66d81Schristos 
4149fb66d81Schristos 	for (py = gr->cy; py <= yy; py++) {
4159fb66d81Schristos 		xx = grid_line_length(gr->gd, py);
4169fb66d81Schristos 		for (px = 0; px < xx; px++) {
4179fb66d81Schristos 			grid_get_cell(gr->gd, px, py, &gc);
418de7701e2Schristos 			if (gc.data.size != 1 || *gc.data.data != ' ') {
419de7701e2Schristos 				gr->cx = px;
420de7701e2Schristos 				gr->cy = py;
421de7701e2Schristos 				return;
422de7701e2Schristos 			}
4239fb66d81Schristos 		}
4249fb66d81Schristos 		if (~grid_get_line(gr->gd, py)->flags & GRID_LINE_WRAPPED)
4259fb66d81Schristos 			break;
4269fb66d81Schristos 	}
427de7701e2Schristos 	gr->cx = oldx;
428de7701e2Schristos 	gr->cy = oldy;
4299fb66d81Schristos }
430