Home | History | Annotate | Line # | Download | only in dist
      1 /* $OpenBSD$ */
      2 
      3 /*
      4  * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott (at) gmail.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 <sys/types.h>
     20 
     21 #include <stdlib.h>
     22 #include <string.h>
     23 
     24 #include "tmux.h"
     25 
     26 /*
     27  * Grid data. This is the basic data structure that represents what is shown on
     28  * screen.
     29  *
     30  * A grid is a grid of cells (struct grid_cell). Lines are not allocated until
     31  * cells in that line are written to. The grid is split into history and
     32  * viewable data with the history starting at row (line) 0 and extending to
     33  * (hsize - 1); from hsize to hsize + (sy - 1) is the viewable data. All
     34  * functions in this file work on absolute coordinates, grid-view.c has
     35  * functions which work on the screen data.
     36  */
     37 
     38 /* Default grid cell data. */
     39 const struct grid_cell grid_default_cell = {
     40 	{ { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 8, 0
     41 };
     42 
     43 /*
     44  * Padding grid cell data. Padding cells are the only zero width cell that
     45  * appears in the grid - because of this, they are always extended cells.
     46  */
     47 static const struct grid_cell grid_padding_cell = {
     48 	{ { '!' }, 0, 0, 0 }, 0, GRID_FLAG_PADDING, 8, 8, 8, 0
     49 };
     50 
     51 /* Cleared grid cell data. */
     52 static const struct grid_cell grid_cleared_cell = {
     53 	{ { ' ' }, 0, 1, 1 }, 0, GRID_FLAG_CLEARED, 8, 8, 8, 0
     54 };
     55 static const struct grid_cell_entry grid_cleared_entry = {
     56 	{ .data = { 0, 8, 8, ' ' } }, GRID_FLAG_CLEARED
     57 };
     58 
     59 /* Store cell in entry. */
     60 static void
     61 grid_store_cell(struct grid_cell_entry *gce, const struct grid_cell *gc,
     62     u_char c)
     63 {
     64 	gce->flags = (gc->flags & ~GRID_FLAG_CLEARED);
     65 
     66 	gce->data.fg = gc->fg & 0xff;
     67 	if (gc->fg & COLOUR_FLAG_256)
     68 		gce->flags |= GRID_FLAG_FG256;
     69 
     70 	gce->data.bg = gc->bg & 0xff;
     71 	if (gc->bg & COLOUR_FLAG_256)
     72 		gce->flags |= GRID_FLAG_BG256;
     73 
     74 	gce->data.attr = gc->attr;
     75 	gce->data.data = c;
     76 }
     77 
     78 /* Check if a cell should be an extended cell. */
     79 static int
     80 grid_need_extended_cell(const struct grid_cell_entry *gce,
     81     const struct grid_cell *gc)
     82 {
     83 	if (gce->flags & GRID_FLAG_EXTENDED)
     84 		return (1);
     85 	if (gc->attr > 0xff)
     86 		return (1);
     87 	if (gc->data.size > 1 || gc->data.width > 1)
     88 		return (1);
     89 	if ((gc->fg & COLOUR_FLAG_RGB) || (gc->bg & COLOUR_FLAG_RGB))
     90 		return (1);
     91 	if (gc->us != 8) /* only supports 256 or RGB */
     92 		return (1);
     93 	if (gc->link != 0)
     94 		return (1);
     95 	if (gc->flags & GRID_FLAG_TAB)
     96 		return (1);
     97 	return (0);
     98 }
     99 
    100 /* Get an extended cell. */
    101 static void
    102 grid_get_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
    103     int flags)
    104 {
    105 	u_int at = gl->extdsize + 1;
    106 
    107 	gl->extddata = xreallocarray(gl->extddata, at, sizeof *gl->extddata);
    108 	gl->extdsize = at;
    109 
    110 	gce->offset = at - 1;
    111 	gce->flags = (flags | GRID_FLAG_EXTENDED);
    112 }
    113 
    114 /* Set cell as extended. */
    115 static struct grid_extd_entry *
    116 grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
    117     const struct grid_cell *gc)
    118 {
    119 	struct grid_extd_entry	*gee;
    120 	int			 flags = (gc->flags & ~GRID_FLAG_CLEARED);
    121 	utf8_char		 uc;
    122 
    123 	if (~gce->flags & GRID_FLAG_EXTENDED)
    124 		grid_get_extended_cell(gl, gce, flags);
    125 	else if (gce->offset >= gl->extdsize)
    126 		fatalx("offset too big");
    127 	gl->flags |= GRID_LINE_EXTENDED;
    128 
    129 	if (gc->flags & GRID_FLAG_TAB)
    130 		uc = gc->data.width;
    131 	else
    132 		utf8_from_data(&gc->data, &uc);
    133 
    134 	gee = &gl->extddata[gce->offset];
    135 	gee->data = uc;
    136 	gee->attr = gc->attr;
    137 	gee->flags = flags;
    138 	gee->fg = gc->fg;
    139 	gee->bg = gc->bg;
    140 	gee->us = gc->us;
    141 	gee->link = gc->link;
    142 	return (gee);
    143 }
    144 
    145 /* Free up unused extended cells. */
    146 static void
    147 grid_compact_line(struct grid_line *gl)
    148 {
    149 	int			 new_extdsize = 0;
    150 	struct grid_extd_entry	*new_extddata;
    151 	struct grid_cell_entry	*gce;
    152 	struct grid_extd_entry	*gee;
    153 	u_int			 px, idx;
    154 
    155 	if (gl->extdsize == 0)
    156 		return;
    157 
    158 	for (px = 0; px < gl->cellsize; px++) {
    159 		gce = &gl->celldata[px];
    160 		if (gce->flags & GRID_FLAG_EXTENDED)
    161 			new_extdsize++;
    162 	}
    163 
    164 	if (new_extdsize == 0) {
    165 		free(gl->extddata);
    166 		gl->extddata = NULL;
    167 		gl->extdsize = 0;
    168 		return;
    169 	}
    170 	new_extddata = xreallocarray(NULL, new_extdsize, sizeof *gl->extddata);
    171 
    172 	idx = 0;
    173 	for (px = 0; px < gl->cellsize; px++) {
    174 		gce = &gl->celldata[px];
    175 		if (gce->flags & GRID_FLAG_EXTENDED) {
    176 			gee = &gl->extddata[gce->offset];
    177 			memcpy(&new_extddata[idx], gee, sizeof *gee);
    178 			gce->offset = idx++;
    179 		}
    180 	}
    181 
    182 	free(gl->extddata);
    183 	gl->extddata = new_extddata;
    184 	gl->extdsize = new_extdsize;
    185 }
    186 
    187 /* Get line data. */
    188 struct grid_line *
    189 grid_get_line(struct grid *gd, u_int line)
    190 {
    191 	return (&gd->linedata[line]);
    192 }
    193 
    194 /* Adjust number of lines. */
    195 void
    196 grid_adjust_lines(struct grid *gd, u_int lines)
    197 {
    198 	gd->linedata = xreallocarray(gd->linedata, lines, sizeof *gd->linedata);
    199 }
    200 
    201 /* Copy default into a cell. */
    202 static void
    203 grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg)
    204 {
    205 	struct grid_line	*gl = &gd->linedata[py];
    206 	struct grid_cell_entry	*gce = &gl->celldata[px];
    207 	struct grid_extd_entry	*gee;
    208 
    209 	memcpy(gce, &grid_cleared_entry, sizeof *gce);
    210 	if (bg != 8) {
    211 		if (bg & COLOUR_FLAG_RGB) {
    212 			grid_get_extended_cell(gl, gce, gce->flags);
    213 			gee = grid_extended_cell(gl, gce, &grid_cleared_cell);
    214 			gee->bg = bg;
    215 		} else {
    216 			if (bg & COLOUR_FLAG_256)
    217 				gce->flags |= GRID_FLAG_BG256;
    218 			gce->data.bg = bg;
    219 		}
    220 	}
    221 }
    222 
    223 /* Check grid y position. */
    224 static int
    225 grid_check_y(struct grid *gd, const char *from, u_int py)
    226 {
    227 	if (py >= gd->hsize + gd->sy) {
    228 		log_debug("%s: y out of range: %u", from, py);
    229 		return (-1);
    230 	}
    231 	return (0);
    232 }
    233 
    234 /* Check if two styles are (visibly) the same. */
    235 int
    236 grid_cells_look_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
    237 {
    238 	int flags1 = gc1->flags, flags2 = gc2->flags;;
    239 
    240 	if (gc1->fg != gc2->fg || gc1->bg != gc2->bg)
    241 		return (0);
    242 	if (gc1->attr != gc2->attr)
    243 		return (0);
    244 	if ((flags1 & ~GRID_FLAG_CLEARED) != (flags2 & ~GRID_FLAG_CLEARED))
    245 		return (0);
    246 	if (gc1->link != gc2->link)
    247 		return (0);
    248 	return (1);
    249 }
    250 
    251 /* Compare grid cells. Return 1 if equal, 0 if not. */
    252 int
    253 grid_cells_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
    254 {
    255 	if (!grid_cells_look_equal(gc1, gc2))
    256 		return (0);
    257 	if (gc1->data.width != gc2->data.width)
    258 		return (0);
    259 	if (gc1->data.size != gc2->data.size)
    260 		return (0);
    261 	return (memcmp(gc1->data.data, gc2->data.data, gc1->data.size) == 0);
    262 }
    263 
    264 /* Set grid cell to a tab. */
    265 void
    266 grid_set_tab(struct grid_cell *gc, u_int width)
    267 {
    268 	memset(gc->data.data, 0, sizeof gc->data.data);
    269 	gc->flags |= GRID_FLAG_TAB;
    270 	gc->flags &= ~GRID_FLAG_PADDING;
    271 	gc->data.width = gc->data.size = gc->data.have = width;
    272 	memset(gc->data.data, ' ', gc->data.size);
    273 }
    274 
    275 /* Free one line. */
    276 static void
    277 grid_free_line(struct grid *gd, u_int py)
    278 {
    279 	free(gd->linedata[py].celldata);
    280 	gd->linedata[py].celldata = NULL;
    281 	free(gd->linedata[py].extddata);
    282 	gd->linedata[py].extddata = NULL;
    283 }
    284 
    285 /* Free several lines. */
    286 static void
    287 grid_free_lines(struct grid *gd, u_int py, u_int ny)
    288 {
    289 	u_int	yy;
    290 
    291 	for (yy = py; yy < py + ny; yy++)
    292 		grid_free_line(gd, yy);
    293 }
    294 
    295 /* Create a new grid. */
    296 struct grid *
    297 grid_create(u_int sx, u_int sy, u_int hlimit)
    298 {
    299 	struct grid	*gd;
    300 
    301 	gd = xmalloc(sizeof *gd);
    302 	gd->sx = sx;
    303 	gd->sy = sy;
    304 
    305 	if (hlimit != 0)
    306 		gd->flags = GRID_HISTORY;
    307 	else
    308 		gd->flags = 0;
    309 
    310 	gd->hscrolled = 0;
    311 	gd->hsize = 0;
    312 	gd->hlimit = hlimit;
    313 
    314 	if (gd->sy != 0)
    315 		gd->linedata = xcalloc(gd->sy, sizeof *gd->linedata);
    316 	else
    317 		gd->linedata = NULL;
    318 
    319 	return (gd);
    320 }
    321 
    322 /* Destroy grid. */
    323 void
    324 grid_destroy(struct grid *gd)
    325 {
    326 	grid_free_lines(gd, 0, gd->hsize + gd->sy);
    327 
    328 	free(gd->linedata);
    329 
    330 	free(gd);
    331 }
    332 
    333 /* Compare grids. */
    334 int
    335 grid_compare(struct grid *ga, struct grid *gb)
    336 {
    337 	struct grid_line	*gla, *glb;
    338 	struct grid_cell	 gca, gcb;
    339 	u_int			 xx, yy;
    340 
    341 	if (ga->sx != gb->sx || ga->sy != gb->sy)
    342 		return (1);
    343 
    344 	for (yy = 0; yy < ga->sy; yy++) {
    345 		gla = &ga->linedata[yy];
    346 		glb = &gb->linedata[yy];
    347 		if (gla->cellsize != glb->cellsize)
    348 			return (1);
    349 		for (xx = 0; xx < gla->cellsize; xx++) {
    350 			grid_get_cell(ga, xx, yy, &gca);
    351 			grid_get_cell(gb, xx, yy, &gcb);
    352 			if (!grid_cells_equal(&gca, &gcb))
    353 				return (1);
    354 		}
    355 	}
    356 
    357 	return (0);
    358 }
    359 
    360 /* Trim lines from the history. */
    361 static void
    362 grid_trim_history(struct grid *gd, u_int ny)
    363 {
    364 	grid_free_lines(gd, 0, ny);
    365 	memmove(&gd->linedata[0], &gd->linedata[ny],
    366 	    (gd->hsize + gd->sy - ny) * (sizeof *gd->linedata));
    367 }
    368 
    369 /*
    370  * Collect lines from the history if at the limit. Free the top (oldest) 10%
    371  * and shift up.
    372  */
    373 void
    374 grid_collect_history(struct grid *gd)
    375 {
    376 	u_int	ny;
    377 
    378 	if (gd->hsize == 0 || gd->hsize < gd->hlimit)
    379 		return;
    380 
    381 	ny = gd->hlimit / 10;
    382 	if (ny < 1)
    383 		ny = 1;
    384 	if (ny > gd->hsize)
    385 		ny = gd->hsize;
    386 
    387 	/*
    388 	 * Free the lines from 0 to ny then move the remaining lines over
    389 	 * them.
    390 	 */
    391 	grid_trim_history(gd, ny);
    392 
    393 	gd->hsize -= ny;
    394 	if (gd->hscrolled > gd->hsize)
    395 		gd->hscrolled = gd->hsize;
    396 }
    397 
    398 /* Remove lines from the bottom of the history. */
    399 void
    400 grid_remove_history(struct grid *gd, u_int ny)
    401 {
    402 	u_int	yy;
    403 
    404 	if (ny > gd->hsize)
    405 		return;
    406 	for (yy = 0; yy < ny; yy++)
    407 		grid_free_line(gd, gd->hsize + gd->sy - 1 - yy);
    408 	gd->hsize -= ny;
    409 }
    410 
    411 /*
    412  * Scroll the entire visible screen, moving one line into the history. Just
    413  * allocate a new line at the bottom and move the history size indicator.
    414  */
    415 void
    416 grid_scroll_history(struct grid *gd, u_int bg)
    417 {
    418 	u_int	yy;
    419 
    420 	yy = gd->hsize + gd->sy;
    421 	gd->linedata = xreallocarray(gd->linedata, yy + 1,
    422 	    sizeof *gd->linedata);
    423 	grid_empty_line(gd, yy, bg);
    424 
    425 	gd->hscrolled++;
    426 	grid_compact_line(&gd->linedata[gd->hsize]);
    427 	gd->linedata[gd->hsize].time = current_time;
    428 	gd->hsize++;
    429 }
    430 
    431 /* Clear the history. */
    432 void
    433 grid_clear_history(struct grid *gd)
    434 {
    435 	grid_trim_history(gd, gd->hsize);
    436 
    437 	gd->hscrolled = 0;
    438 	gd->hsize = 0;
    439 
    440 	gd->linedata = xreallocarray(gd->linedata, gd->sy,
    441 	    sizeof *gd->linedata);
    442 }
    443 
    444 /* Scroll a region up, moving the top line into the history. */
    445 void
    446 grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower, u_int bg)
    447 {
    448 	struct grid_line	*gl_history, *gl_upper;
    449 	u_int			 yy;
    450 
    451 	/* Create a space for a new line. */
    452 	yy = gd->hsize + gd->sy;
    453 	gd->linedata = xreallocarray(gd->linedata, yy + 1,
    454 	    sizeof *gd->linedata);
    455 
    456 	/* Move the entire screen down to free a space for this line. */
    457 	gl_history = &gd->linedata[gd->hsize];
    458 	memmove(gl_history + 1, gl_history, gd->sy * sizeof *gl_history);
    459 
    460 	/* Adjust the region and find its start and end. */
    461 	upper++;
    462 	gl_upper = &gd->linedata[upper];
    463 	lower++;
    464 
    465 	/* Move the line into the history. */
    466 	memcpy(gl_history, gl_upper, sizeof *gl_history);
    467 	gl_history->time = current_time;
    468 
    469 	/* Then move the region up and clear the bottom line. */
    470 	memmove(gl_upper, gl_upper + 1, (lower - upper) * sizeof *gl_upper);
    471 	grid_empty_line(gd, lower, bg);
    472 
    473 	/* Move the history offset down over the line. */
    474 	gd->hscrolled++;
    475 	gd->hsize++;
    476 }
    477 
    478 /* Expand line to fit to cell. */
    479 static void
    480 grid_expand_line(struct grid *gd, u_int py, u_int sx, u_int bg)
    481 {
    482 	struct grid_line	*gl;
    483 	u_int			 xx;
    484 
    485 	gl = &gd->linedata[py];
    486 	if (sx <= gl->cellsize)
    487 		return;
    488 
    489 	if (sx < gd->sx / 4)
    490 		sx = gd->sx / 4;
    491 	else if (sx < gd->sx / 2)
    492 		sx = gd->sx / 2;
    493 	else if (gd->sx > sx)
    494 		sx = gd->sx;
    495 
    496 	gl->celldata = xreallocarray(gl->celldata, sx, sizeof *gl->celldata);
    497 	for (xx = gl->cellsize; xx < sx; xx++)
    498 		grid_clear_cell(gd, xx, py, bg);
    499 	gl->cellsize = sx;
    500 }
    501 
    502 /* Empty a line and set background colour if needed. */
    503 void
    504 grid_empty_line(struct grid *gd, u_int py, u_int bg)
    505 {
    506 	memset(&gd->linedata[py], 0, sizeof gd->linedata[py]);
    507 	if (!COLOUR_DEFAULT(bg))
    508 		grid_expand_line(gd, py, gd->sx, bg);
    509 }
    510 
    511 /* Peek at grid line. */
    512 const struct grid_line *
    513 grid_peek_line(struct grid *gd, u_int py)
    514 {
    515 	if (grid_check_y(gd, __func__, py) != 0)
    516 		return (NULL);
    517 	return (&gd->linedata[py]);
    518 }
    519 
    520 /* Get cell from line. */
    521 static void
    522 grid_get_cell1(struct grid_line *gl, u_int px, struct grid_cell *gc)
    523 {
    524 	struct grid_cell_entry	*gce = &gl->celldata[px];
    525 	struct grid_extd_entry	*gee;
    526 
    527 	if (gce->flags & GRID_FLAG_EXTENDED) {
    528 		if (gce->offset >= gl->extdsize)
    529 			memcpy(gc, &grid_default_cell, sizeof *gc);
    530 		else {
    531 			gee = &gl->extddata[gce->offset];
    532 			gc->flags = gee->flags;
    533 			gc->attr = gee->attr;
    534 			gc->fg = gee->fg;
    535 			gc->bg = gee->bg;
    536 			gc->us = gee->us;
    537 			gc->link = gee->link;
    538 
    539 			if (gc->flags & GRID_FLAG_TAB)
    540 				grid_set_tab(gc, gee->data);
    541 			else
    542 				utf8_to_data(gee->data, &gc->data);
    543 		}
    544 		return;
    545 	}
    546 
    547 	gc->flags = gce->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256);
    548 	gc->attr = gce->data.attr;
    549 	gc->fg = gce->data.fg;
    550 	if (gce->flags & GRID_FLAG_FG256)
    551 		gc->fg |= COLOUR_FLAG_256;
    552 	gc->bg = gce->data.bg;
    553 	if (gce->flags & GRID_FLAG_BG256)
    554 		gc->bg |= COLOUR_FLAG_256;
    555 	gc->us = 8;
    556 	utf8_set(&gc->data, gce->data.data);
    557 	gc->link = 0;
    558 }
    559 
    560 /* Get cell for reading. */
    561 void
    562 grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc)
    563 {
    564 	if (grid_check_y(gd, __func__, py) != 0 ||
    565 	    px >= gd->linedata[py].cellsize)
    566 		memcpy(gc, &grid_default_cell, sizeof *gc);
    567 	else
    568 		grid_get_cell1(&gd->linedata[py], px, gc);
    569 }
    570 
    571 /* Set cell at position. */
    572 void
    573 grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
    574 {
    575 	struct grid_line	*gl;
    576 	struct grid_cell_entry	*gce;
    577 
    578 	if (grid_check_y(gd, __func__, py) != 0)
    579 		return;
    580 
    581 	grid_expand_line(gd, py, px + 1, 8);
    582 
    583 	gl = &gd->linedata[py];
    584 	if (px + 1 > gl->cellused)
    585 		gl->cellused = px + 1;
    586 
    587 	gce = &gl->celldata[px];
    588 	if (grid_need_extended_cell(gce, gc))
    589 		grid_extended_cell(gl, gce, gc);
    590 	else
    591 		grid_store_cell(gce, gc, gc->data.data[0]);
    592 }
    593 
    594 /* Set padding at position. */
    595 void
    596 grid_set_padding(struct grid *gd, u_int px, u_int py)
    597 {
    598 	grid_set_cell(gd, px, py, &grid_padding_cell);
    599 }
    600 
    601 /* Set cells at position. */
    602 void
    603 grid_set_cells(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc,
    604     const char *s, size_t slen)
    605 {
    606 	struct grid_line	*gl;
    607 	struct grid_cell_entry	*gce;
    608 	struct grid_extd_entry	*gee;
    609 	u_int			 i;
    610 
    611 	if (grid_check_y(gd, __func__, py) != 0)
    612 		return;
    613 
    614 	grid_expand_line(gd, py, px + slen, 8);
    615 
    616 	gl = &gd->linedata[py];
    617 	if (px + slen > gl->cellused)
    618 		gl->cellused = px + slen;
    619 
    620 	for (i = 0; i < slen; i++) {
    621 		gce = &gl->celldata[px + i];
    622 		if (grid_need_extended_cell(gce, gc)) {
    623 			gee = grid_extended_cell(gl, gce, gc);
    624 			gee->data = utf8_build_one(s[i]);
    625 		} else
    626 			grid_store_cell(gce, gc, s[i]);
    627 	}
    628 }
    629 
    630 /* Clear area. */
    631 void
    632 grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny, u_int bg)
    633 {
    634 	struct grid_line	*gl;
    635 	u_int			 xx, yy, ox, sx;
    636 
    637 	if (nx == 0 || ny == 0)
    638 		return;
    639 
    640 	if (px == 0 && nx == gd->sx) {
    641 		grid_clear_lines(gd, py, ny, bg);
    642 		return;
    643 	}
    644 
    645 	if (grid_check_y(gd, __func__, py) != 0)
    646 		return;
    647 	if (grid_check_y(gd, __func__, py + ny - 1) != 0)
    648 		return;
    649 
    650 	for (yy = py; yy < py + ny; yy++) {
    651 		gl = &gd->linedata[yy];
    652 
    653 		sx = gd->sx;
    654 		if (sx > gl->cellsize)
    655 			sx = gl->cellsize;
    656 		ox = nx;
    657 		if (COLOUR_DEFAULT(bg)) {
    658 			if (px > sx)
    659 				continue;
    660 			if (px + nx > sx)
    661 				ox = sx - px;
    662 		}
    663 
    664 		grid_expand_line(gd, yy, px + ox, 8); /* default bg first */
    665 		for (xx = px; xx < px + ox; xx++)
    666 			grid_clear_cell(gd, xx, yy, bg);
    667 	}
    668 }
    669 
    670 /* Clear lines. This just frees and truncates the lines. */
    671 void
    672 grid_clear_lines(struct grid *gd, u_int py, u_int ny, u_int bg)
    673 {
    674 	u_int	yy;
    675 
    676 	if (ny == 0)
    677 		return;
    678 
    679 	if (grid_check_y(gd, __func__, py) != 0)
    680 		return;
    681 	if (grid_check_y(gd, __func__, py + ny - 1) != 0)
    682 		return;
    683 
    684 	for (yy = py; yy < py + ny; yy++) {
    685 		grid_free_line(gd, yy);
    686 		grid_empty_line(gd, yy, bg);
    687 	}
    688 	if (py != 0)
    689 		gd->linedata[py - 1].flags &= ~GRID_LINE_WRAPPED;
    690 }
    691 
    692 /* Move a group of lines. */
    693 void
    694 grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny, u_int bg)
    695 {
    696 	u_int	yy;
    697 
    698 	if (ny == 0 || py == dy)
    699 		return;
    700 
    701 	if (grid_check_y(gd, __func__, py) != 0)
    702 		return;
    703 	if (grid_check_y(gd, __func__, py + ny - 1) != 0)
    704 		return;
    705 	if (grid_check_y(gd, __func__, dy) != 0)
    706 		return;
    707 	if (grid_check_y(gd, __func__, dy + ny - 1) != 0)
    708 		return;
    709 
    710 	/* Free any lines which are being replaced. */
    711 	for (yy = dy; yy < dy + ny; yy++) {
    712 		if (yy >= py && yy < py + ny)
    713 			continue;
    714 		grid_free_line(gd, yy);
    715 	}
    716 	if (dy != 0)
    717 		gd->linedata[dy - 1].flags &= ~GRID_LINE_WRAPPED;
    718 
    719 	memmove(&gd->linedata[dy], &gd->linedata[py],
    720 	    ny * (sizeof *gd->linedata));
    721 
    722 	/*
    723 	 * Wipe any lines that have been moved (without freeing them - they are
    724 	 * still present).
    725 	 */
    726 	for (yy = py; yy < py + ny; yy++) {
    727 		if (yy < dy || yy >= dy + ny)
    728 			grid_empty_line(gd, yy, bg);
    729 	}
    730 	if (py != 0 && (py < dy || py >= dy + ny))
    731 		gd->linedata[py - 1].flags &= ~GRID_LINE_WRAPPED;
    732 }
    733 
    734 /* Move a group of cells. */
    735 void
    736 grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx,
    737     u_int bg)
    738 {
    739 	struct grid_line	*gl;
    740 	u_int			 xx;
    741 
    742 	if (nx == 0 || px == dx)
    743 		return;
    744 
    745 	if (grid_check_y(gd, __func__, py) != 0)
    746 		return;
    747 	gl = &gd->linedata[py];
    748 
    749 	grid_expand_line(gd, py, px + nx, 8);
    750 	grid_expand_line(gd, py, dx + nx, 8);
    751 	memmove(&gl->celldata[dx], &gl->celldata[px],
    752 	    nx * sizeof *gl->celldata);
    753 	if (dx + nx > gl->cellused)
    754 		gl->cellused = dx + nx;
    755 
    756 	/* Wipe any cells that have been moved. */
    757 	for (xx = px; xx < px + nx; xx++) {
    758 		if (xx >= dx && xx < dx + nx)
    759 			continue;
    760 		grid_clear_cell(gd, xx, py, bg);
    761 	}
    762 }
    763 
    764 /* Get ANSI foreground sequence. */
    765 static size_t
    766 grid_string_cells_fg(const struct grid_cell *gc, int *values)
    767 {
    768 	size_t	n;
    769 	u_char	r, g, b;
    770 
    771 	n = 0;
    772 	if (gc->fg & COLOUR_FLAG_256) {
    773 		values[n++] = 38;
    774 		values[n++] = 5;
    775 		values[n++] = gc->fg & 0xff;
    776 	} else if (gc->fg & COLOUR_FLAG_RGB) {
    777 		values[n++] = 38;
    778 		values[n++] = 2;
    779 		colour_split_rgb(gc->fg, &r, &g, &b);
    780 		values[n++] = r;
    781 		values[n++] = g;
    782 		values[n++] = b;
    783 	} else {
    784 		switch (gc->fg) {
    785 		case 0:
    786 		case 1:
    787 		case 2:
    788 		case 3:
    789 		case 4:
    790 		case 5:
    791 		case 6:
    792 		case 7:
    793 			values[n++] = gc->fg + 30;
    794 			break;
    795 		case 8:
    796 			values[n++] = 39;
    797 			break;
    798 		case 90:
    799 		case 91:
    800 		case 92:
    801 		case 93:
    802 		case 94:
    803 		case 95:
    804 		case 96:
    805 		case 97:
    806 			values[n++] = gc->fg;
    807 			break;
    808 		}
    809 	}
    810 	return (n);
    811 }
    812 
    813 /* Get ANSI background sequence. */
    814 static size_t
    815 grid_string_cells_bg(const struct grid_cell *gc, int *values)
    816 {
    817 	size_t	n;
    818 	u_char	r, g, b;
    819 
    820 	n = 0;
    821 	if (gc->bg & COLOUR_FLAG_256) {
    822 		values[n++] = 48;
    823 		values[n++] = 5;
    824 		values[n++] = gc->bg & 0xff;
    825 	} else if (gc->bg & COLOUR_FLAG_RGB) {
    826 		values[n++] = 48;
    827 		values[n++] = 2;
    828 		colour_split_rgb(gc->bg, &r, &g, &b);
    829 		values[n++] = r;
    830 		values[n++] = g;
    831 		values[n++] = b;
    832 	} else {
    833 		switch (gc->bg) {
    834 		case 0:
    835 		case 1:
    836 		case 2:
    837 		case 3:
    838 		case 4:
    839 		case 5:
    840 		case 6:
    841 		case 7:
    842 			values[n++] = gc->bg + 40;
    843 			break;
    844 		case 8:
    845 			values[n++] = 49;
    846 			break;
    847 		case 90:
    848 		case 91:
    849 		case 92:
    850 		case 93:
    851 		case 94:
    852 		case 95:
    853 		case 96:
    854 		case 97:
    855 			values[n++] = gc->bg + 10;
    856 			break;
    857 		}
    858 	}
    859 	return (n);
    860 }
    861 
    862 /* Get underscore colour sequence. */
    863 static size_t
    864 grid_string_cells_us(const struct grid_cell *gc, int *values)
    865 {
    866 	size_t	n;
    867 	u_char	r, g, b;
    868 
    869 	n = 0;
    870 	if (gc->us & COLOUR_FLAG_256) {
    871 		values[n++] = 58;
    872 		values[n++] = 5;
    873 		values[n++] = gc->us & 0xff;
    874 	} else if (gc->us & COLOUR_FLAG_RGB) {
    875 		values[n++] = 58;
    876 		values[n++] = 2;
    877 		colour_split_rgb(gc->us, &r, &g, &b);
    878 		values[n++] = r;
    879 		values[n++] = g;
    880 		values[n++] = b;
    881 	}
    882 	return (n);
    883 }
    884 
    885 /* Add on SGR code. */
    886 static void
    887 grid_string_cells_add_code(char *buf, size_t len, u_int n, int *s, int *newc,
    888     int *oldc, size_t nnewc, size_t noldc, int flags)
    889 {
    890 	u_int	i;
    891 	char	tmp[64];
    892 	int	reset = (n != 0 && s[0] == 0);
    893 
    894 	if (nnewc == 0)
    895 		return; /* no code to add */
    896 	if (!reset &&
    897 	    nnewc == noldc &&
    898 	    memcmp(newc, oldc, nnewc * sizeof newc[0]) == 0)
    899 		return; /* no reset and colour unchanged */
    900 	if (reset && (newc[0] == 49 || newc[0] == 39))
    901 		return; /* reset and colour default */
    902 
    903 	if (flags & GRID_STRING_ESCAPE_SEQUENCES)
    904 		strlcat(buf, "\\033[", len);
    905 	else
    906 		strlcat(buf, "\033[", len);
    907 	for (i = 0; i < nnewc; i++) {
    908 		if (i + 1 < nnewc)
    909 			xsnprintf(tmp, sizeof tmp, "%d;", newc[i]);
    910 		else
    911 			xsnprintf(tmp, sizeof tmp, "%d", newc[i]);
    912 		strlcat(buf, tmp, len);
    913 	}
    914 	strlcat(buf, "m", len);
    915 }
    916 
    917 static int
    918 grid_string_cells_add_hyperlink(char *buf, size_t len, const char *id,
    919     const char *uri, int flags)
    920 {
    921 	char	*tmp;
    922 
    923 	if (strlen(uri) + strlen(id) + 17 >= len)
    924 		return (0);
    925 
    926 	if (flags & GRID_STRING_ESCAPE_SEQUENCES)
    927 		strlcat(buf, "\\033]8;", len);
    928 	else
    929 		strlcat(buf, "\033]8;", len);
    930 	if (*id != '\0') {
    931 		xasprintf(&tmp, "id=%s;", id);
    932 		strlcat(buf, tmp, len);
    933 		free(tmp);
    934 	} else
    935 		strlcat(buf, ";", len);
    936 	strlcat(buf, uri, len);
    937 	if (flags & GRID_STRING_ESCAPE_SEQUENCES)
    938 		strlcat(buf, "\\033\\\\", len);
    939 	else
    940 		strlcat(buf, "\033\\", len);
    941 	return (1);
    942 }
    943 
    944 /*
    945  * Returns ANSI code to set particular attributes (colour, bold and so on)
    946  * given a current state.
    947  */
    948 static void
    949 grid_string_cells_code(const struct grid_cell *lastgc,
    950     const struct grid_cell *gc, char *buf, size_t len, int flags,
    951     struct screen *sc, int *has_link)
    952 {
    953 	int			 oldc[64], newc[64], s[128];
    954 	size_t			 noldc, nnewc, n, i;
    955 	u_int			 attr = gc->attr, lastattr = lastgc->attr;
    956 	char			 tmp[64];
    957 	const char		*uri, *id;
    958 
    959 	static const struct {
    960 		u_int	mask;
    961 		u_int	code;
    962 	} attrs[] = {
    963 		{ GRID_ATTR_BRIGHT, 1 },
    964 		{ GRID_ATTR_DIM, 2 },
    965 		{ GRID_ATTR_ITALICS, 3 },
    966 		{ GRID_ATTR_UNDERSCORE, 4 },
    967 		{ GRID_ATTR_BLINK, 5 },
    968 		{ GRID_ATTR_REVERSE, 7 },
    969 		{ GRID_ATTR_HIDDEN, 8 },
    970 		{ GRID_ATTR_STRIKETHROUGH, 9 },
    971 		{ GRID_ATTR_UNDERSCORE_2, 42 },
    972 		{ GRID_ATTR_UNDERSCORE_3, 43 },
    973 		{ GRID_ATTR_UNDERSCORE_4, 44 },
    974 		{ GRID_ATTR_UNDERSCORE_5, 45 },
    975 		{ GRID_ATTR_OVERLINE, 53 },
    976 	};
    977 	n = 0;
    978 
    979 	/* If any attribute is removed, begin with 0. */
    980 	for (i = 0; i < nitems(attrs); i++) {
    981 		if (((~attr & attrs[i].mask) &&
    982 		    (lastattr & attrs[i].mask)) ||
    983 		    (lastgc->us != 8 && gc->us == 8)) {
    984 			s[n++] = 0;
    985 			lastattr &= GRID_ATTR_CHARSET;
    986 			break;
    987 		}
    988 	}
    989 	/* For each attribute that is newly set, add its code. */
    990 	for (i = 0; i < nitems(attrs); i++) {
    991 		if ((attr & attrs[i].mask) && !(lastattr & attrs[i].mask))
    992 			s[n++] = attrs[i].code;
    993 	}
    994 
    995 	/* Write the attributes. */
    996 	*buf = '\0';
    997 	if (n > 0) {
    998 		if (flags & GRID_STRING_ESCAPE_SEQUENCES)
    999 			strlcat(buf, "\\033[", len);
   1000 		else
   1001 			strlcat(buf, "\033[", len);
   1002 		for (i = 0; i < n; i++) {
   1003 			if (s[i] < 10)
   1004 				xsnprintf(tmp, sizeof tmp, "%d", s[i]);
   1005 			else {
   1006 				xsnprintf(tmp, sizeof tmp, "%d:%d", s[i] / 10,
   1007 				    s[i] % 10);
   1008 			}
   1009 			strlcat(buf, tmp, len);
   1010 			if (i + 1 < n)
   1011 				strlcat(buf, ";", len);
   1012 		}
   1013 		strlcat(buf, "m", len);
   1014 	}
   1015 
   1016 	/* If the foreground colour changed, write its parameters. */
   1017 	nnewc = grid_string_cells_fg(gc, newc);
   1018 	noldc = grid_string_cells_fg(lastgc, oldc);
   1019 	grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc,
   1020 	    flags);
   1021 
   1022 	/* If the background colour changed, append its parameters. */
   1023 	nnewc = grid_string_cells_bg(gc, newc);
   1024 	noldc = grid_string_cells_bg(lastgc, oldc);
   1025 	grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc,
   1026 	    flags);
   1027 
   1028 	/* If the underscore colour changed, append its parameters. */
   1029 	nnewc = grid_string_cells_us(gc, newc);
   1030 	noldc = grid_string_cells_us(lastgc, oldc);
   1031 	grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc,
   1032 	    flags);
   1033 
   1034 	/* Append shift in/shift out if needed. */
   1035 	if ((attr & GRID_ATTR_CHARSET) && !(lastattr & GRID_ATTR_CHARSET)) {
   1036 		if (flags & GRID_STRING_ESCAPE_SEQUENCES)
   1037 			strlcat(buf, "\\016", len); /* SO */
   1038 		else
   1039 			strlcat(buf, "\016", len);  /* SO */
   1040 	}
   1041 	if (!(attr & GRID_ATTR_CHARSET) && (lastattr & GRID_ATTR_CHARSET)) {
   1042 		if (flags & GRID_STRING_ESCAPE_SEQUENCES)
   1043 			strlcat(buf, "\\017", len); /* SI */
   1044 		else
   1045 			strlcat(buf, "\017", len);  /* SI */
   1046 	}
   1047 
   1048 	/* Add hyperlink if changed. */
   1049 	if (sc != NULL && sc->hyperlinks != NULL && lastgc->link != gc->link) {
   1050 		if (hyperlinks_get(sc->hyperlinks, gc->link, &uri, &id, NULL)) {
   1051 			*has_link = grid_string_cells_add_hyperlink(buf, len,
   1052 			    id, uri, flags);
   1053 		} else if (*has_link) {
   1054 			grid_string_cells_add_hyperlink(buf, len, "", "",
   1055 			    flags);
   1056 			*has_link = 0;
   1057 		}
   1058 	}
   1059 }
   1060 
   1061 /* Convert cells into a string. */
   1062 char *
   1063 grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
   1064     struct grid_cell **lastgc, int flags, struct screen *s)
   1065 {
   1066 	struct grid_cell	 gc;
   1067 	static struct grid_cell	 lastgc1;
   1068 	const char		*data;
   1069 	char			*buf, code[8192];
   1070 	size_t			 len, off, size, codelen;
   1071 	u_int			 xx, end;
   1072 	int			 has_link = 0;
   1073 	const struct grid_line	*gl;
   1074 
   1075 	if (lastgc != NULL && *lastgc == NULL) {
   1076 		memcpy(&lastgc1, &grid_default_cell, sizeof lastgc1);
   1077 		*lastgc = &lastgc1;
   1078 	}
   1079 
   1080 	len = 128;
   1081 	buf = xmalloc(len);
   1082 	off = 0;
   1083 
   1084 	gl = grid_peek_line(gd, py);
   1085 	if (flags & GRID_STRING_EMPTY_CELLS)
   1086 		end = gl->cellsize;
   1087 	else
   1088 		end = gl->cellused;
   1089 	for (xx = px; xx < px + nx; xx++) {
   1090 		if (gl == NULL || xx >= end)
   1091 			break;
   1092 		grid_get_cell(gd, xx, py, &gc);
   1093 		if (gc.flags & GRID_FLAG_PADDING)
   1094 			continue;
   1095 
   1096 		if (flags & GRID_STRING_WITH_SEQUENCES) {
   1097 			grid_string_cells_code(*lastgc, &gc, code, sizeof code,
   1098 			    flags, s, &has_link);
   1099 			codelen = strlen(code);
   1100 			memcpy(*lastgc, &gc, sizeof **lastgc);
   1101 		} else
   1102 			codelen = 0;
   1103 
   1104 		if (gc.flags & GRID_FLAG_TAB) {
   1105 			data = "\t";
   1106 			size = 1;
   1107 		} else {
   1108 			data = (void *)gc.data.data;
   1109 			size = gc.data.size;
   1110 			if ((flags & GRID_STRING_ESCAPE_SEQUENCES) &&
   1111 			    size == 1 &&
   1112 			    *data == '\\') {
   1113 				data = "\\\\";
   1114 				size = 2;
   1115 			}
   1116 		}
   1117 
   1118 		while (len < off + size + codelen + 1) {
   1119 			buf = xreallocarray(buf, 2, len);
   1120 			len *= 2;
   1121 		}
   1122 
   1123 		if (codelen != 0) {
   1124 			memcpy(buf + off, code, codelen);
   1125 			off += codelen;
   1126 		}
   1127 		memcpy(buf + off, data, size);
   1128 		off += size;
   1129 	}
   1130 
   1131 	if (has_link) {
   1132 		grid_string_cells_add_hyperlink(code, sizeof code, "", "",
   1133 		    flags);
   1134 		codelen = strlen(code);
   1135 		while (len < off + size + codelen + 1) {
   1136 			buf = xreallocarray(buf, 2, len);
   1137 			len *= 2;
   1138 		}
   1139 		memcpy(buf + off, code, codelen);
   1140 		off += codelen;
   1141 	}
   1142 
   1143 	if (flags & GRID_STRING_TRIM_SPACES) {
   1144 		while (off > 0 && buf[off - 1] == ' ')
   1145 			off--;
   1146 	}
   1147 	buf[off] = '\0';
   1148 
   1149 	return (buf);
   1150 }
   1151 
   1152 /*
   1153  * Duplicate a set of lines between two grids. Both source and destination
   1154  * should be big enough.
   1155  */
   1156 void
   1157 grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy,
   1158     u_int ny)
   1159 {
   1160 	struct grid_line	*dstl, *srcl;
   1161 	u_int			 yy;
   1162 
   1163 	if (dy + ny > dst->hsize + dst->sy)
   1164 		ny = dst->hsize + dst->sy - dy;
   1165 	if (sy + ny > src->hsize + src->sy)
   1166 		ny = src->hsize + src->sy - sy;
   1167 	grid_free_lines(dst, dy, ny);
   1168 
   1169 	for (yy = 0; yy < ny; yy++) {
   1170 		srcl = &src->linedata[sy];
   1171 		dstl = &dst->linedata[dy];
   1172 
   1173 		memcpy(dstl, srcl, sizeof *dstl);
   1174 		if (srcl->cellsize != 0) {
   1175 			dstl->celldata = xreallocarray(NULL,
   1176 			    srcl->cellsize, sizeof *dstl->celldata);
   1177 			memcpy(dstl->celldata, srcl->celldata,
   1178 			    srcl->cellsize * sizeof *dstl->celldata);
   1179 		} else
   1180 			dstl->celldata = NULL;
   1181 		if (srcl->extdsize != 0) {
   1182 			dstl->extdsize = srcl->extdsize;
   1183 			dstl->extddata = xreallocarray(NULL, dstl->extdsize,
   1184 			    sizeof *dstl->extddata);
   1185 			memcpy(dstl->extddata, srcl->extddata, dstl->extdsize *
   1186 			    sizeof *dstl->extddata);
   1187 		} else
   1188 			dstl->extddata = NULL;
   1189 
   1190 		sy++;
   1191 		dy++;
   1192 	}
   1193 }
   1194 
   1195 /* Mark line as dead. */
   1196 static void
   1197 grid_reflow_dead(struct grid_line *gl)
   1198 {
   1199 	memset(gl, 0, sizeof *gl);
   1200 	gl->flags = GRID_LINE_DEAD;
   1201 }
   1202 
   1203 /* Add lines, return the first new one. */
   1204 static struct grid_line *
   1205 grid_reflow_add(struct grid *gd, u_int n)
   1206 {
   1207 	struct grid_line	*gl;
   1208 	u_int			 sy = gd->sy + n;
   1209 
   1210 	gd->linedata = xreallocarray(gd->linedata, sy, sizeof *gd->linedata);
   1211 	gl = &gd->linedata[gd->sy];
   1212 	memset(gl, 0, n * (sizeof *gl));
   1213 	gd->sy = sy;
   1214 	return (gl);
   1215 }
   1216 
   1217 /* Move a line across. */
   1218 static struct grid_line *
   1219 grid_reflow_move(struct grid *gd, struct grid_line *from)
   1220 {
   1221 	struct grid_line	*to;
   1222 
   1223 	to = grid_reflow_add(gd, 1);
   1224 	memcpy(to, from, sizeof *to);
   1225 	grid_reflow_dead(from);
   1226 	return (to);
   1227 }
   1228 
   1229 /* Join line below onto this one. */
   1230 static void
   1231 grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy,
   1232     u_int width, int already)
   1233 {
   1234 	struct grid_line	*gl, *from = NULL;
   1235 	struct grid_cell	 gc;
   1236 	u_int			 lines, left, i, to, line, want = 0;
   1237 	u_int			 at;
   1238 	int			 wrapped = 1;
   1239 
   1240 	/*
   1241 	 * Add a new target line.
   1242 	 */
   1243 	if (!already) {
   1244 		to = target->sy;
   1245 		gl = grid_reflow_move(target, &gd->linedata[yy]);
   1246 	} else {
   1247 		to = target->sy - 1;
   1248 		gl = &target->linedata[to];
   1249 	}
   1250 	at = gl->cellused;
   1251 
   1252 	/*
   1253 	 * Loop until no more to consume or the target line is full.
   1254 	 */
   1255 	lines = 0;
   1256 	for (;;) {
   1257 		/*
   1258 		 * If this is now the last line, there is nothing more to be
   1259 		 * done.
   1260 		 */
   1261 		if (yy + 1 + lines == gd->hsize + gd->sy)
   1262 			break;
   1263 		line = yy + 1 + lines;
   1264 
   1265 		/* If the next line is empty, skip it. */
   1266 		if (~gd->linedata[line].flags & GRID_LINE_WRAPPED)
   1267 			wrapped = 0;
   1268 		if (gd->linedata[line].cellused == 0) {
   1269 			if (!wrapped)
   1270 				break;
   1271 			lines++;
   1272 			continue;
   1273 		}
   1274 
   1275 		/*
   1276 		 * Is the destination line now full? Copy the first character
   1277 		 * separately because we need to leave "from" set to the last
   1278 		 * line if this line is full.
   1279 		 */
   1280 		grid_get_cell1(&gd->linedata[line], 0, &gc);
   1281 		if (width + gc.data.width > sx)
   1282 			break;
   1283 		width += gc.data.width;
   1284 		grid_set_cell(target, at, to, &gc);
   1285 		at++;
   1286 
   1287 		/* Join as much more as possible onto the current line. */
   1288 		from = &gd->linedata[line];
   1289 		for (want = 1; want < from->cellused; want++) {
   1290 			grid_get_cell1(from, want, &gc);
   1291 			if (width + gc.data.width > sx)
   1292 				break;
   1293 			width += gc.data.width;
   1294 
   1295 			grid_set_cell(target, at, to, &gc);
   1296 			at++;
   1297 		}
   1298 		lines++;
   1299 
   1300 		/*
   1301 		 * If this line wasn't wrapped or we didn't consume the entire
   1302 		 * line, don't try to join any further lines.
   1303 		 */
   1304 		if (!wrapped || want != from->cellused || width == sx)
   1305 			break;
   1306 	}
   1307 	if (lines == 0 || from == NULL)
   1308 		return;
   1309 
   1310 	/*
   1311 	 * If we didn't consume the entire final line, then remove what we did
   1312 	 * consume. If we consumed the entire line and it wasn't wrapped,
   1313 	 * remove the wrap flag from this line.
   1314 	 */
   1315 	left = from->cellused - want;
   1316 	if (left != 0) {
   1317 		grid_move_cells(gd, 0, want, yy + lines, left, 8);
   1318 		from->cellsize = from->cellused = left;
   1319 		lines--;
   1320 	} else if (!wrapped)
   1321 		gl->flags &= ~GRID_LINE_WRAPPED;
   1322 
   1323 	/* Remove the lines that were completely consumed. */
   1324 	for (i = yy + 1; i < yy + 1 + lines; i++) {
   1325 		free(gd->linedata[i].celldata);
   1326 		free(gd->linedata[i].extddata);
   1327 		grid_reflow_dead(&gd->linedata[i]);
   1328 	}
   1329 
   1330 	/* Adjust scroll position. */
   1331 	if (gd->hscrolled > to + lines)
   1332 		gd->hscrolled -= lines;
   1333 	else if (gd->hscrolled > to)
   1334 		gd->hscrolled = to;
   1335 }
   1336 
   1337 /* Split this line into several new ones */
   1338 static void
   1339 grid_reflow_split(struct grid *target, struct grid *gd, u_int sx, u_int yy,
   1340     u_int at)
   1341 {
   1342 	struct grid_line	*gl = &gd->linedata[yy], *first;
   1343 	struct grid_cell	 gc;
   1344 	u_int			 line, lines, width, i, xx;
   1345 	u_int			 used = gl->cellused;
   1346 	int			 flags = gl->flags;
   1347 
   1348 	/* How many lines do we need to insert? We know we need at least two. */
   1349 	if (~gl->flags & GRID_LINE_EXTENDED)
   1350 		lines = 1 + (gl->cellused - 1) / sx;
   1351 	else {
   1352 		lines = 2;
   1353 		width = 0;
   1354 		for (i = at; i < used; i++) {
   1355 			grid_get_cell1(gl, i, &gc);
   1356 			if (width + gc.data.width > sx) {
   1357 				lines++;
   1358 				width = 0;
   1359 			}
   1360 			width += gc.data.width;
   1361 		}
   1362 	}
   1363 
   1364 	/* Insert new lines. */
   1365 	line = target->sy + 1;
   1366 	first = grid_reflow_add(target, lines);
   1367 
   1368 	/* Copy sections from the original line. */
   1369 	width = 0;
   1370 	xx = 0;
   1371 	for (i = at; i < used; i++) {
   1372 		grid_get_cell1(gl, i, &gc);
   1373 		if (width + gc.data.width > sx) {
   1374 			target->linedata[line].flags |= GRID_LINE_WRAPPED;
   1375 
   1376 			line++;
   1377 			width = 0;
   1378 			xx = 0;
   1379 		}
   1380 		width += gc.data.width;
   1381 		grid_set_cell(target, xx, line, &gc);
   1382 		xx++;
   1383 	}
   1384 	if (flags & GRID_LINE_WRAPPED)
   1385 		target->linedata[line].flags |= GRID_LINE_WRAPPED;
   1386 
   1387 	/* Move the remainder of the original line. */
   1388 	gl->cellsize = gl->cellused = at;
   1389 	gl->flags |= GRID_LINE_WRAPPED;
   1390 	memcpy(first, gl, sizeof *first);
   1391 	grid_reflow_dead(gl);
   1392 
   1393 	/* Adjust the scroll position. */
   1394 	if (yy <= gd->hscrolled)
   1395 		gd->hscrolled += lines - 1;
   1396 
   1397 	/*
   1398 	 * If the original line had the wrapped flag and there is still space
   1399 	 * in the last new line, try to join with the next lines.
   1400 	 */
   1401 	if (width < sx && (flags & GRID_LINE_WRAPPED))
   1402 		grid_reflow_join(target, gd, sx, yy, width, 1);
   1403 }
   1404 
   1405 /* Reflow lines on grid to new width. */
   1406 void
   1407 grid_reflow(struct grid *gd, u_int sx)
   1408 {
   1409 	struct grid		*target;
   1410 	struct grid_line	*gl;
   1411 	struct grid_cell	 gc;
   1412 	u_int			 yy, width, i, at;
   1413 
   1414 	/*
   1415 	 * Create a destination grid. This is just used as a container for the
   1416 	 * line data and may not be fully valid.
   1417 	 */
   1418 	target = grid_create(gd->sx, 0, 0);
   1419 
   1420 	/*
   1421 	 * Loop over each source line.
   1422 	 */
   1423 	for (yy = 0; yy < gd->hsize + gd->sy; yy++) {
   1424 		gl = &gd->linedata[yy];
   1425 		if (gl->flags & GRID_LINE_DEAD)
   1426 			continue;
   1427 
   1428 		/*
   1429 		 * Work out the width of this line. at is the point at which
   1430 		 * the available width is hit, and width is the full line
   1431 		 * width.
   1432 		 */
   1433 		at = width = 0;
   1434 		if (~gl->flags & GRID_LINE_EXTENDED) {
   1435 			width = gl->cellused;
   1436 			if (width > sx)
   1437 				at = sx;
   1438 			else
   1439 				at = width;
   1440 		} else {
   1441 			for (i = 0; i < gl->cellused; i++) {
   1442 				grid_get_cell1(gl, i, &gc);
   1443 				if (at == 0 && width + gc.data.width > sx)
   1444 					at = i;
   1445 				width += gc.data.width;
   1446 			}
   1447 		}
   1448 
   1449 		/*
   1450 		 * If the line is exactly right, just move it across
   1451 		 * unchanged.
   1452 		 */
   1453 		if (width == sx) {
   1454 			grid_reflow_move(target, gl);
   1455 			continue;
   1456 		}
   1457 
   1458 		/*
   1459 		 * If the line is too big, it needs to be split, whether or not
   1460 		 * it was previously wrapped.
   1461 		 */
   1462 		if (width > sx) {
   1463 			grid_reflow_split(target, gd, sx, yy, at);
   1464 			continue;
   1465 		}
   1466 
   1467 		/*
   1468 		 * If the line was previously wrapped, join as much as possible
   1469 		 * of the next line.
   1470 		 */
   1471 		if (gl->flags & GRID_LINE_WRAPPED)
   1472 			grid_reflow_join(target, gd, sx, yy, width, 0);
   1473 		else
   1474 			grid_reflow_move(target, gl);
   1475 	}
   1476 
   1477 	/*
   1478 	 * Replace the old grid with the new.
   1479 	 */
   1480 	if (target->sy < gd->sy)
   1481 		grid_reflow_add(target, gd->sy - target->sy);
   1482 	gd->hsize = target->sy - gd->sy;
   1483 	if (gd->hscrolled > gd->hsize)
   1484 		gd->hscrolled = gd->hsize;
   1485 	free(gd->linedata);
   1486 	gd->linedata = target->linedata;
   1487 	free(target);
   1488 }
   1489 
   1490 /* Convert to position based on wrapped lines. */
   1491 void
   1492 grid_wrap_position(struct grid *gd, u_int px, u_int py, u_int *wx, u_int *wy)
   1493 {
   1494 	u_int	ax = 0, ay = 0, yy;
   1495 
   1496 	for (yy = 0; yy < py; yy++) {
   1497 		if (gd->linedata[yy].flags & GRID_LINE_WRAPPED)
   1498 			ax += gd->linedata[yy].cellused;
   1499 		else {
   1500 			ax = 0;
   1501 			ay++;
   1502 		}
   1503 	}
   1504 	if (px >= gd->linedata[yy].cellused)
   1505 		ax = UINT_MAX;
   1506 	else
   1507 		ax += px;
   1508 	*wx = ax;
   1509 	*wy = ay;
   1510 }
   1511 
   1512 /* Convert position based on wrapped lines back. */
   1513 void
   1514 grid_unwrap_position(struct grid *gd, u_int *px, u_int *py, u_int wx, u_int wy)
   1515 {
   1516 	u_int	yy, ay = 0;
   1517 
   1518 	for (yy = 0; yy < gd->hsize + gd->sy - 1; yy++) {
   1519 		if (ay == wy)
   1520 			break;
   1521 		if (~gd->linedata[yy].flags & GRID_LINE_WRAPPED)
   1522 			ay++;
   1523 	}
   1524 
   1525 	/*
   1526 	 * yy is now 0 on the unwrapped line which contains wx. Walk forwards
   1527 	 * until we find the end or the line now containing wx.
   1528 	 */
   1529 	if (wx == UINT_MAX) {
   1530 		while (gd->linedata[yy].flags & GRID_LINE_WRAPPED)
   1531 			yy++;
   1532 		wx = gd->linedata[yy].cellused;
   1533 	} else {
   1534 		while (gd->linedata[yy].flags & GRID_LINE_WRAPPED) {
   1535 			if (wx < gd->linedata[yy].cellused)
   1536 				break;
   1537 			wx -= gd->linedata[yy].cellused;
   1538 			yy++;
   1539 		}
   1540 	}
   1541 	*px = wx;
   1542 	*py = yy;
   1543 }
   1544 
   1545 /* Get length of line. */
   1546 u_int
   1547 grid_line_length(struct grid *gd, u_int py)
   1548 {
   1549 	struct grid_cell	gc;
   1550 	u_int			px;
   1551 
   1552 	px = grid_get_line(gd, py)->cellsize;
   1553 	if (px > gd->sx)
   1554 		px = gd->sx;
   1555 	while (px > 0) {
   1556 		grid_get_cell(gd, px - 1, py, &gc);
   1557 		if ((gc.flags & GRID_FLAG_PADDING) ||
   1558 		    gc.data.size != 1 ||
   1559 		    *gc.data.data != ' ')
   1560 			break;
   1561 		px--;
   1562 	}
   1563 	return (px);
   1564 }
   1565 
   1566 /* Check if character is in set. */
   1567 int
   1568 grid_in_set(struct grid *gd, u_int px, u_int py, const char *set)
   1569 {
   1570 	struct grid_cell	gc, tmp_gc;
   1571 	u_int			pxx;
   1572 
   1573 	grid_get_cell(gd, px, py, &gc);
   1574 	if (strchr(set, '\t')) {
   1575 		if (gc.flags & GRID_FLAG_PADDING) {
   1576 			pxx = px;
   1577 			do
   1578 				grid_get_cell(gd, --pxx, py, &tmp_gc);
   1579 			while (pxx > 0 && tmp_gc.flags & GRID_FLAG_PADDING);
   1580 			if (tmp_gc.flags & GRID_FLAG_TAB)
   1581 				return (tmp_gc.data.width - (px - pxx));
   1582 		} else if (gc.flags & GRID_FLAG_TAB)
   1583 			return (gc.data.width);
   1584 	}
   1585 	if (gc.flags & GRID_FLAG_PADDING)
   1586 		return (0);
   1587 	return (utf8_cstrhas(set, &gc.data));
   1588 }
   1589