xref: /openbsd-src/usr.bin/tmux/screen-write.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /* $OpenBSD: screen-write.c,v 1.93 2016/09/02 20:57:20 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@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 static void	screen_write_initctx(struct screen_write_ctx *,
27 		    struct tty_ctx *);
28 static void	screen_write_save_last(struct screen_write_ctx *,
29 		    struct tty_ctx *);
30 static void	screen_write_flush(struct screen_write_ctx *);
31 
32 static int	screen_write_overwrite(struct screen_write_ctx *,
33 		    struct grid_cell *, u_int);
34 static int	screen_write_combine(struct screen_write_ctx *,
35 		    const struct utf8_data *);
36 
37 static const struct grid_cell screen_write_pad_cell = {
38 	GRID_FLAG_PADDING, 0, 8, 8, { { 0 }, 0, 0, 0 }
39 };
40 
41 #define screen_dirty_bit(s, x, y) (((y) * screen_size_x(s)) + (x))
42 #define screen_dirty_clear(s, sx, sy, ex, ey)			\
43 	do {							\
44 		if (s->dirty != NULL) {				\
45 			bit_nclear(s->dirty,			\
46 			    screen_dirty_bit(s, sx, sy),	\
47 			    screen_dirty_bit(s, ex, ey));	\
48 		}						\
49 	} while (0)
50 
51 /* Initialize writing with a window. */
52 void
53 screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp,
54     struct screen *s)
55 {
56 	u_int		 size;
57 	char		 tmp[16];
58 	const char	*cp = tmp;
59 
60 	ctx->wp = wp;
61 	if (wp != NULL && s == NULL)
62 		ctx->s = wp->screen;
63 	else
64 		ctx->s = s;
65 
66 	size = screen_size_x(ctx->s) * screen_size_y(ctx->s);
67 	if (ctx->s->dirtysize != size) {
68 		free(ctx->s->dirty);
69 		ctx->s->dirty = NULL;
70 		ctx->s->dirtysize = size;
71 	}
72 	ctx->dirty = 0;
73 
74 	ctx->cells = ctx->written = ctx->skipped = 0;
75 
76 	if (wp == NULL)
77 		cp = "no pane";
78 	else
79 		snprintf(tmp, sizeof tmp, "pane %%%u", wp->id);
80 	log_debug("%s: size %ux%u, %s", __func__, screen_size_x(ctx->s),
81 	    screen_size_y(ctx->s), cp);
82 }
83 
84 /* Finish writing. */
85 void
86 screen_write_stop(struct screen_write_ctx *ctx)
87 {
88 	screen_write_flush(ctx);
89 
90 	log_debug("%s: %u of %u written (dirty %u, skipped %u)", __func__,
91 	    ctx->written, ctx->cells, ctx->cells - ctx->written, ctx->skipped);
92 }
93 
94 /* Flush outstanding cell writes. */
95 static void
96 screen_write_flush(struct screen_write_ctx *ctx)
97 {
98 	struct screen	*s = ctx->s;
99 	struct tty_ctx	 ttyctx;
100 	u_int		 x, y, offset, cx, cy, dirty;
101 	struct grid_cell gc;
102 
103 	if (ctx->dirty == 0)
104 		return;
105 	dirty = 0;
106 
107 	cx = s->cx;
108 	cy = s->cy;
109 
110 	offset = 0;
111 	for (y = 0; y < screen_size_y(s); y++) {
112 		for (x = 0; x < screen_size_x(s); x++) {
113 			offset++;
114 			if (!bit_test(s->dirty, offset - 1))
115 				continue;
116 			bit_clear(s->dirty, offset - 1);
117 
118 			screen_write_cursormove(ctx, x, y);
119 			grid_view_get_cell(s->grid, x, y, &gc);
120 
121 			screen_write_initctx(ctx, &ttyctx);
122 			ttyctx.cell = &gc;
123 			tty_write(tty_cmd_cell, &ttyctx);
124 			ctx->written++;
125 
126 			if (++dirty == ctx->dirty)
127 				break;
128 		}
129 		if (dirty == ctx->dirty)
130 			break;
131 	}
132 
133 	s->cx = cx;
134 	s->cy = cy;
135 }
136 
137 /* Reset screen state. */
138 void
139 screen_write_reset(struct screen_write_ctx *ctx)
140 {
141 	struct screen	*s = ctx->s;
142 
143 	screen_reset_tabs(s);
144 	screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1);
145 
146 	s->mode &= ~(MODE_INSERT|MODE_KCURSOR|MODE_KKEYPAD|MODE_FOCUSON);
147 	s->mode &= ~(ALL_MOUSE_MODES|MODE_MOUSE_UTF8|MODE_MOUSE_SGR);
148 
149 	screen_write_clearscreen(ctx);
150 	screen_write_cursormove(ctx, 0, 0);
151 }
152 
153 /* Write character. */
154 void
155 screen_write_putc(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
156     u_char ch)
157 {
158 	struct grid_cell	gc;
159 
160 	memcpy(&gc, gcp, sizeof gc);
161 
162 	utf8_set(&gc.data, ch);
163 	screen_write_cell(ctx, &gc);
164 }
165 
166 /* Calculate string length, with embedded formatting. */
167 size_t
168 screen_write_cstrlen(const char *fmt, ...)
169 {
170 	va_list	ap;
171 	char   *msg, *msg2, *ptr, *ptr2;
172 	size_t	size;
173 
174 	va_start(ap, fmt);
175 	xvasprintf(&msg, fmt, ap);
176 	va_end(ap);
177 	msg2 = xmalloc(strlen(msg) + 1);
178 
179 	ptr = msg;
180 	ptr2 = msg2;
181 	while (*ptr != '\0') {
182 		if (ptr[0] == '#' && ptr[1] == '[') {
183 			while (*ptr != ']' && *ptr != '\0')
184 				ptr++;
185 			if (*ptr == ']')
186 				ptr++;
187 			continue;
188 		}
189 		*ptr2++ = *ptr++;
190 	}
191 	*ptr2 = '\0';
192 
193 	size = screen_write_strlen("%s", msg2);
194 
195 	free(msg);
196 	free(msg2);
197 
198 	return (size);
199 }
200 
201 /* Calculate string length. */
202 size_t
203 screen_write_strlen(const char *fmt, ...)
204 {
205 	va_list			ap;
206 	char   	       	       *msg;
207 	struct utf8_data	ud;
208 	u_char 	      	       *ptr;
209 	size_t			left, size = 0;
210 	enum utf8_state		more;
211 
212 	va_start(ap, fmt);
213 	xvasprintf(&msg, fmt, ap);
214 	va_end(ap);
215 
216 	ptr = msg;
217 	while (*ptr != '\0') {
218 		if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) {
219 			ptr++;
220 
221 			left = strlen(ptr);
222 			if (left < (size_t)ud.size - 1)
223 				break;
224 			while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE)
225 				ptr++;
226 			ptr++;
227 
228 			if (more == UTF8_DONE)
229 				size += ud.width;
230 		} else {
231 			if (*ptr > 0x1f && *ptr < 0x7f)
232 				size++;
233 			ptr++;
234 		}
235 	}
236 
237 	free(msg);
238 	return (size);
239 }
240 
241 /* Write simple string (no UTF-8 or maximum length). */
242 void
243 screen_write_puts(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
244     const char *fmt, ...)
245 {
246 	va_list	ap;
247 
248 	va_start(ap, fmt);
249 	screen_write_vnputs(ctx, -1, gcp, fmt, ap);
250 	va_end(ap);
251 }
252 
253 /* Write string with length limit (-1 for unlimited). */
254 void
255 screen_write_nputs(struct screen_write_ctx *ctx, ssize_t maxlen,
256     const struct grid_cell *gcp, const char *fmt, ...)
257 {
258 	va_list	ap;
259 
260 	va_start(ap, fmt);
261 	screen_write_vnputs(ctx, maxlen, gcp, fmt, ap);
262 	va_end(ap);
263 }
264 
265 void
266 screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
267     const struct grid_cell *gcp, const char *fmt, va_list ap)
268 {
269 	struct grid_cell	gc;
270 	struct utf8_data       *ud = &gc.data;
271 	char   		       *msg;
272 	u_char 		       *ptr;
273 	size_t		 	left, size = 0;
274 	enum utf8_state		more;
275 
276 	memcpy(&gc, gcp, sizeof gc);
277 	xvasprintf(&msg, fmt, ap);
278 
279 	ptr = msg;
280 	while (*ptr != '\0') {
281 		if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
282 			ptr++;
283 
284 			left = strlen(ptr);
285 			if (left < (size_t)ud->size - 1)
286 				break;
287 			while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
288 				ptr++;
289 			ptr++;
290 
291 			if (more != UTF8_DONE)
292 				continue;
293 			if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
294 				while (size < (size_t)maxlen) {
295 					screen_write_putc(ctx, &gc, ' ');
296 					size++;
297 				}
298 				break;
299 			}
300 			size += ud->width;
301 			screen_write_cell(ctx, &gc);
302 		} else {
303 			if (maxlen > 0 && size + 1 > (size_t)maxlen)
304 				break;
305 
306 			if (*ptr == '\001')
307 				gc.attr ^= GRID_ATTR_CHARSET;
308 			else if (*ptr > 0x1f && *ptr < 0x7f) {
309 				size++;
310 				screen_write_putc(ctx, &gc, *ptr);
311 			}
312 			ptr++;
313 		}
314 	}
315 
316 	free(msg);
317 }
318 
319 /* Write string, similar to nputs, but with embedded formatting (#[]). */
320 void
321 screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
322     const struct grid_cell *gcp, const char *fmt, ...)
323 {
324 	struct grid_cell	 gc;
325 	struct utf8_data	*ud = &gc.data;
326 	va_list			 ap;
327 	char			*msg;
328 	u_char 			*ptr, *last;
329 	size_t			 left, size = 0;
330 	enum utf8_state		 more;
331 
332 	memcpy(&gc, gcp, sizeof gc);
333 
334 	va_start(ap, fmt);
335 	xvasprintf(&msg, fmt, ap);
336 	va_end(ap);
337 
338 	ptr = msg;
339 	while (*ptr != '\0') {
340 		if (ptr[0] == '#' && ptr[1] == '[') {
341 			ptr += 2;
342 			last = ptr + strcspn(ptr, "]");
343 			if (*last == '\0') {
344 				/* No ]. Not much point in doing anything. */
345 				break;
346 			}
347 			*last = '\0';
348 
349 			style_parse(gcp, &gc, ptr);
350 			ptr = last + 1;
351 			continue;
352 		}
353 
354 		if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
355 			ptr++;
356 
357 			left = strlen(ptr);
358 			if (left < (size_t)ud->size - 1)
359 				break;
360 			while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
361 				ptr++;
362 			ptr++;
363 
364 			if (more != UTF8_DONE)
365 				continue;
366 			if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
367 				while (size < (size_t)maxlen) {
368 					screen_write_putc(ctx, &gc, ' ');
369 					size++;
370 				}
371 				break;
372 			}
373 			size += ud->width;
374 			screen_write_cell(ctx, &gc);
375 		} else {
376 			if (maxlen > 0 && size + 1 > (size_t)maxlen)
377 				break;
378 
379 			if (*ptr > 0x1f && *ptr < 0x7f) {
380 				size++;
381 				screen_write_putc(ctx, &gc, *ptr);
382 			}
383 			ptr++;
384 		}
385 	}
386 
387 	free(msg);
388 }
389 
390 /* Copy from another screen. */
391 void
392 screen_write_copy(struct screen_write_ctx *ctx,
393     struct screen *src, u_int px, u_int py, u_int nx, u_int ny)
394 {
395 	struct screen		*s = ctx->s;
396 	struct grid		*gd = src->grid;
397 	struct grid_line	*gl;
398 	struct grid_cell	 gc;
399 	u_int		 	 xx, yy, cx, cy, ax, bx;
400 
401 	cx = s->cx;
402 	cy = s->cy;
403 	for (yy = py; yy < py + ny; yy++) {
404 		gl = &gd->linedata[yy];
405 		if (yy < gd->hsize + gd->sy) {
406 			/*
407 			 * Find start and end position and copy between
408 			 * them. Limit to the real end of the line then use a
409 			 * clear EOL only if copying to the end, otherwise
410 			 * could overwrite whatever is there already.
411 			 */
412 			if (px > gl->cellsize)
413 				ax = gl->cellsize;
414 			else
415 				ax = px;
416 			if (px + nx == gd->sx && px + nx > gl->cellsize)
417 				bx = gl->cellsize;
418 			else
419 				bx = px + nx;
420 
421 			for (xx = ax; xx < bx; xx++) {
422 				grid_get_cell(gd, xx, yy, &gc);
423 				screen_write_cell(ctx, &gc);
424 			}
425 			if (px + nx == gd->sx && px + nx > gl->cellsize)
426 				screen_write_clearendofline(ctx);
427 		} else
428 			screen_write_clearline(ctx);
429 		cy++;
430 		screen_write_cursormove(ctx, cx, cy);
431 	}
432 }
433 
434 /* Set up context for TTY command. */
435 static void
436 screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
437 {
438 	struct screen	*s = ctx->s;
439 
440 	ttyctx->wp = ctx->wp;
441 
442 	ttyctx->ocx = s->cx;
443 	ttyctx->ocy = s->cy;
444 
445 	ttyctx->orlower = s->rlower;
446 	ttyctx->orupper = s->rupper;
447 }
448 
449 /* Save last cell on screen. */
450 static void
451 screen_write_save_last(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
452 {
453 	struct screen		*s = ctx->s;
454 	struct grid		*gd = s->grid;
455 	struct grid_cell	 gc;
456 	u_int			 xx;
457 
458 	memcpy(&gc, &grid_default_cell, sizeof gc);
459 	for (xx = 1; xx <= screen_size_x(s); xx++) {
460 		grid_view_get_cell(gd, screen_size_x(s) - xx, s->cy, &gc);
461 		if (~gc.flags & GRID_FLAG_PADDING)
462 			break;
463 	}
464 	memcpy(&ttyctx->last_cell, &gc, sizeof ttyctx->last_cell);
465 }
466 
467 /* Set a mode. */
468 void
469 screen_write_mode_set(struct screen_write_ctx *ctx, int mode)
470 {
471 	struct screen	*s = ctx->s;
472 
473 	s->mode |= mode;
474 }
475 
476 /* Clear a mode. */
477 void
478 screen_write_mode_clear(struct screen_write_ctx *ctx, int mode)
479 {
480 	struct screen	*s = ctx->s;
481 
482 	s->mode &= ~mode;
483 }
484 
485 /* Cursor up by ny. */
486 void
487 screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny)
488 {
489 	struct screen	*s = ctx->s;
490 
491 	if (ny == 0)
492 		ny = 1;
493 
494 	if (s->cy < s->rupper) {
495 		/* Above region. */
496 		if (ny > s->cy)
497 			ny = s->cy;
498 	} else {
499 		/* Below region. */
500 		if (ny > s->cy - s->rupper)
501 			ny = s->cy - s->rupper;
502 	}
503 	if (s->cx == screen_size_x(s))
504 	    s->cx--;
505 	if (ny == 0)
506 		return;
507 
508 	s->cy -= ny;
509 }
510 
511 /* Cursor down by ny. */
512 void
513 screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny)
514 {
515 	struct screen	*s = ctx->s;
516 
517 	if (ny == 0)
518 		ny = 1;
519 
520 	if (s->cy > s->rlower) {
521 		/* Below region. */
522 		if (ny > screen_size_y(s) - 1 - s->cy)
523 			ny = screen_size_y(s) - 1 - s->cy;
524 	} else {
525 		/* Above region. */
526 		if (ny > s->rlower - s->cy)
527 			ny = s->rlower - s->cy;
528 	}
529 	if (s->cx == screen_size_x(s))
530 	    s->cx--;
531 	if (ny == 0)
532 		return;
533 
534 	s->cy += ny;
535 }
536 
537 /* Cursor right by nx.  */
538 void
539 screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx)
540 {
541 	struct screen	*s = ctx->s;
542 
543 	if (nx == 0)
544 		nx = 1;
545 
546 	if (nx > screen_size_x(s) - 1 - s->cx)
547 		nx = screen_size_x(s) - 1 - s->cx;
548 	if (nx == 0)
549 		return;
550 
551 	s->cx += nx;
552 }
553 
554 /* Cursor left by nx. */
555 void
556 screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx)
557 {
558 	struct screen	*s = ctx->s;
559 
560 	if (nx == 0)
561 		nx = 1;
562 
563 	if (nx > s->cx)
564 		nx = s->cx;
565 	if (nx == 0)
566 		return;
567 
568 	s->cx -= nx;
569 }
570 
571 /* Backspace; cursor left unless at start of wrapped line when can move up. */
572 void
573 screen_write_backspace(struct screen_write_ctx *ctx)
574 {
575 	struct screen		*s = ctx->s;
576 	struct grid_line	*gl;
577 
578 	if (s->cx == 0) {
579 		if (s->cy == 0)
580 			return;
581 		gl = &s->grid->linedata[s->grid->hsize + s->cy - 1];
582 		if (gl->flags & GRID_LINE_WRAPPED) {
583 			s->cy--;
584 			s->cx = screen_size_x(s) - 1;
585 		}
586 	} else
587 		s->cx--;
588 }
589 
590 /* VT100 alignment test. */
591 void
592 screen_write_alignmenttest(struct screen_write_ctx *ctx)
593 {
594 	struct screen		*s = ctx->s;
595 	struct tty_ctx	 	 ttyctx;
596 	struct grid_cell       	 gc;
597 	u_int			 xx, yy;
598 	u_int		 	 sx = screen_size_x(s), sy = screen_size_y(s);
599 
600 	screen_write_initctx(ctx, &ttyctx);
601 
602 	screen_dirty_clear(s, 0, 0, sx - 1, sy  - 1);
603 
604 	memcpy(&gc, &grid_default_cell, sizeof gc);
605 	utf8_set(&gc.data, 'E');
606 
607 	for (yy = 0; yy < screen_size_y(s); yy++) {
608 		for (xx = 0; xx < screen_size_x(s); xx++)
609 			grid_view_set_cell(s->grid, xx, yy, &gc);
610 	}
611 
612 	s->cx = 0;
613 	s->cy = 0;
614 
615 	s->rupper = 0;
616 	s->rlower = screen_size_y(s) - 1;
617 
618 	tty_write(tty_cmd_alignmenttest, &ttyctx);
619 }
620 
621 /* Insert nx characters. */
622 void
623 screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx)
624 {
625 	struct screen	*s = ctx->s;
626 	struct tty_ctx	 ttyctx;
627 
628 	if (nx == 0)
629 		nx = 1;
630 
631 	if (nx > screen_size_x(s) - s->cx)
632 		nx = screen_size_x(s) - s->cx;
633 	if (nx == 0)
634 		return;
635 
636 	screen_write_flush(ctx);
637 	screen_write_initctx(ctx, &ttyctx);
638 
639 	if (s->cx <= screen_size_x(s) - 1)
640 		grid_view_insert_cells(s->grid, s->cx, s->cy, nx);
641 
642 	ttyctx.num = nx;
643 	tty_write(tty_cmd_insertcharacter, &ttyctx);
644 }
645 
646 /* Delete nx characters. */
647 void
648 screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx)
649 {
650 	struct screen	*s = ctx->s;
651 	struct tty_ctx	 ttyctx;
652 
653 	if (nx == 0)
654 		nx = 1;
655 
656 	if (nx > screen_size_x(s) - s->cx)
657 		nx = screen_size_x(s) - s->cx;
658 	if (nx == 0)
659 		return;
660 
661 	screen_write_flush(ctx);
662 	screen_write_initctx(ctx, &ttyctx);
663 
664 	if (s->cx <= screen_size_x(s) - 1)
665 		grid_view_delete_cells(s->grid, s->cx, s->cy, nx);
666 
667 	ttyctx.num = nx;
668 	tty_write(tty_cmd_deletecharacter, &ttyctx);
669 }
670 
671 /* Clear nx characters. */
672 void
673 screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx)
674 {
675 	struct screen	*s = ctx->s;
676 	struct tty_ctx	 ttyctx;
677 
678 	if (nx == 0)
679 		nx = 1;
680 
681 	if (nx > screen_size_x(s) - s->cx)
682 		nx = screen_size_x(s) - s->cx;
683 	if (nx == 0)
684 		return;
685 
686 	screen_write_initctx(ctx, &ttyctx);
687 
688 	if (s->cx <= screen_size_x(s) - 1) {
689 		screen_dirty_clear(s, s->cx, s->cy, s->cx + nx - 1, s->cy);
690 		grid_view_clear(s->grid, s->cx, s->cy, nx, 1);
691 	} else
692 		return;
693 
694 	ttyctx.num = nx;
695 	tty_write(tty_cmd_clearcharacter, &ttyctx);
696 }
697 
698 /* Insert ny lines. */
699 void
700 screen_write_insertline(struct screen_write_ctx *ctx, u_int ny)
701 {
702 	struct screen	*s = ctx->s;
703 	struct tty_ctx	 ttyctx;
704 
705 	if (ny == 0)
706 		ny = 1;
707 
708 	if (s->cy < s->rupper || s->cy > s->rlower) {
709 		if (ny > screen_size_y(s) - s->cy)
710 			ny = screen_size_y(s) - s->cy;
711 		if (ny == 0)
712 			return;
713 
714 		screen_write_flush(ctx);
715 		screen_write_initctx(ctx, &ttyctx);
716 
717 		grid_view_insert_lines(s->grid, s->cy, ny);
718 
719 		ttyctx.num = ny;
720 		tty_write(tty_cmd_insertline, &ttyctx);
721 		return;
722 	}
723 
724 	if (ny > s->rlower + 1 - s->cy)
725 		ny = s->rlower + 1 - s->cy;
726 	if (ny == 0)
727 		return;
728 
729 	screen_write_flush(ctx);
730 	screen_write_initctx(ctx, &ttyctx);
731 
732 	if (s->cy < s->rupper || s->cy > s->rlower)
733 		grid_view_insert_lines(s->grid, s->cy, ny);
734 	else
735 		grid_view_insert_lines_region(s->grid, s->rlower, s->cy, ny);
736 
737 	ttyctx.num = ny;
738 	tty_write(tty_cmd_insertline, &ttyctx);
739 }
740 
741 /* Delete ny lines. */
742 void
743 screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny)
744 {
745 	struct screen	*s = ctx->s;
746 	struct tty_ctx	 ttyctx;
747 
748 	if (ny == 0)
749 		ny = 1;
750 
751 	if (s->cy < s->rupper || s->cy > s->rlower) {
752 		if (ny > screen_size_y(s) - s->cy)
753 			ny = screen_size_y(s) - s->cy;
754 		if (ny == 0)
755 			return;
756 
757 		screen_write_flush(ctx);
758 		screen_write_initctx(ctx, &ttyctx);
759 
760 		grid_view_delete_lines(s->grid, s->cy, ny);
761 
762 		ttyctx.num = ny;
763 		tty_write(tty_cmd_deleteline, &ttyctx);
764 		return;
765 	}
766 
767 	if (ny > s->rlower + 1 - s->cy)
768 		ny = s->rlower + 1 - s->cy;
769 	if (ny == 0)
770 		return;
771 
772 	screen_write_flush(ctx);
773 	screen_write_initctx(ctx, &ttyctx);
774 
775 	if (s->cy < s->rupper || s->cy > s->rlower)
776 		grid_view_delete_lines(s->grid, s->cy, ny);
777 	else
778 		grid_view_delete_lines_region(s->grid, s->rlower, s->cy, ny);
779 
780 	ttyctx.num = ny;
781 	tty_write(tty_cmd_deleteline, &ttyctx);
782 }
783 
784 /* Clear line at cursor. */
785 void
786 screen_write_clearline(struct screen_write_ctx *ctx)
787 {
788 	struct screen		*s = ctx->s;
789 	struct grid_line	*gl;
790 	struct tty_ctx		 ttyctx;
791 	u_int			 sx = screen_size_x(s);
792 
793 	screen_write_initctx(ctx, &ttyctx);
794 
795 	gl = &s->grid->linedata[s->grid->hsize + s->cy];
796 	if (gl->cellsize != 0) {
797 		screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
798 		grid_view_clear(s->grid, 0, s->cy, sx, 1);
799 	} else
800 		return;
801 
802 	tty_write(tty_cmd_clearline, &ttyctx);
803 }
804 
805 /* Clear to end of line from cursor. */
806 void
807 screen_write_clearendofline(struct screen_write_ctx *ctx)
808 {
809 	struct screen		*s = ctx->s;
810 	struct grid_line	*gl;
811 	struct tty_ctx		 ttyctx;
812 	u_int			 sx = screen_size_x(s);
813 
814 	screen_write_initctx(ctx, &ttyctx);
815 
816 	gl = &s->grid->linedata[s->grid->hsize + s->cy];
817 	if (s->cx <= sx - 1 && s->cx < gl->cellsize) {
818 		screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy);
819 		grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
820 	} else
821 		return;
822 
823 	tty_write(tty_cmd_clearendofline, &ttyctx);
824 }
825 
826 /* Clear to start of line from cursor. */
827 void
828 screen_write_clearstartofline(struct screen_write_ctx *ctx)
829 {
830 	struct screen	*s = ctx->s;
831 	struct tty_ctx	 ttyctx;
832 	u_int		 sx = screen_size_x(s);
833 
834 	screen_write_initctx(ctx, &ttyctx);
835 
836 	if (s->cx > sx - 1) {
837 		screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
838 		grid_view_clear(s->grid, 0, s->cy, sx, 1);
839 	} else {
840 		screen_dirty_clear(s, 0, s->cy, s->cx, s->cy);
841 		grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1);
842 	}
843 
844 	tty_write(tty_cmd_clearstartofline, &ttyctx);
845 }
846 
847 /* Move cursor to px,py.  */
848 void
849 screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py)
850 {
851 	struct screen	*s = ctx->s;
852 
853 	if (px > screen_size_x(s) - 1)
854 		px = screen_size_x(s) - 1;
855 	if (py > screen_size_y(s) - 1)
856 		py = screen_size_y(s) - 1;
857 
858 	s->cx = px;
859 	s->cy = py;
860 }
861 
862 /* Reverse index (up with scroll).  */
863 void
864 screen_write_reverseindex(struct screen_write_ctx *ctx)
865 {
866 	struct screen	*s = ctx->s;
867 	struct tty_ctx	 ttyctx;
868 
869 	screen_write_initctx(ctx, &ttyctx);
870 
871 	if (s->cy == s->rupper) {
872 		screen_write_flush(ctx);
873 		grid_view_scroll_region_down(s->grid, s->rupper, s->rlower);
874 	} else if (s->cy > 0)
875 		s->cy--;
876 
877 	tty_write(tty_cmd_reverseindex, &ttyctx);
878 }
879 
880 /* Set scroll region. */
881 void
882 screen_write_scrollregion(struct screen_write_ctx *ctx, u_int rupper,
883     u_int rlower)
884 {
885 	struct screen	*s = ctx->s;
886 
887 	if (rupper > screen_size_y(s) - 1)
888 		rupper = screen_size_y(s) - 1;
889 	if (rlower > screen_size_y(s) - 1)
890 		rlower = screen_size_y(s) - 1;
891 	if (rupper >= rlower)	/* cannot be one line */
892 		return;
893 
894 	/* Cursor moves to top-left. */
895 	s->cx = 0;
896 	s->cy = 0;
897 
898 	s->rupper = rupper;
899 	s->rlower = rlower;
900 }
901 
902 /* Line feed. */
903 void
904 screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped)
905 {
906 	struct screen		*s = ctx->s;
907 	struct grid_line	*gl;
908 	struct tty_ctx	 	 ttyctx;
909 	u_int			 sx = screen_size_x(s), sy = screen_size_y(s);
910 
911 	screen_write_initctx(ctx, &ttyctx);
912 
913 	gl = &s->grid->linedata[s->grid->hsize + s->cy];
914 	if (wrapped)
915 		gl->flags |= GRID_LINE_WRAPPED;
916 	else
917 		gl->flags &= ~GRID_LINE_WRAPPED;
918 
919 	if (s->cy == s->rlower) {
920 		screen_dirty_clear(s, 0, s->rupper, sx - 1, s->rupper);
921 		screen_write_flush(ctx);
922 		grid_view_scroll_region_up(s->grid, s->rupper, s->rlower);
923 	} else if (s->cy < sy - 1)
924 		s->cy++;
925 
926 	ttyctx.num = wrapped;
927 	tty_write(tty_cmd_linefeed, &ttyctx);
928 }
929 
930 /* Carriage return (cursor to start of line). */
931 void
932 screen_write_carriagereturn(struct screen_write_ctx *ctx)
933 {
934 	struct screen	*s = ctx->s;
935 
936 	s->cx = 0;
937 }
938 
939 /* Clear to end of screen from cursor. */
940 void
941 screen_write_clearendofscreen(struct screen_write_ctx *ctx)
942 {
943 	struct screen	*s = ctx->s;
944 	struct tty_ctx	 ttyctx;
945 	u_int		 sx = screen_size_x(s), sy = screen_size_y(s);
946 
947 	screen_write_initctx(ctx, &ttyctx);
948 
949 	/* Scroll into history if it is enabled and clearing entire screen. */
950 	if (s->cy == 0 && s->grid->flags & GRID_HISTORY) {
951 		screen_dirty_clear(s, 0, 0, sx - 1, sy  - 1);
952 		grid_view_clear_history(s->grid);
953 	} else {
954 		if (s->cx <= sx - 1) {
955 			screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy);
956 			grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
957 		}
958 		screen_dirty_clear(s, 0, s->cy + 1, sx - 1, sy - 1);
959 		grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1));
960 	}
961 
962 	tty_write(tty_cmd_clearendofscreen, &ttyctx);
963 }
964 
965 /* Clear to start of screen. */
966 void
967 screen_write_clearstartofscreen(struct screen_write_ctx *ctx)
968 {
969 	struct screen	*s = ctx->s;
970 	struct tty_ctx	 ttyctx;
971 	u_int		 sx = screen_size_x(s);
972 
973 	screen_write_initctx(ctx, &ttyctx);
974 
975 	if (s->cy > 0) {
976 		screen_dirty_clear(s, 0, 0, sx - 1, s->cy);
977 		grid_view_clear(s->grid, 0, 0, sx, s->cy);
978 	}
979 	if (s->cx > sx - 1) {
980 		screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
981 		grid_view_clear(s->grid, 0, s->cy, sx, 1);
982 	} else {
983 		screen_dirty_clear(s, 0, s->cy, s->cx, s->cy);
984 		grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1);
985 	}
986 
987 	tty_write(tty_cmd_clearstartofscreen, &ttyctx);
988 }
989 
990 /* Clear entire screen. */
991 void
992 screen_write_clearscreen(struct screen_write_ctx *ctx)
993 {
994 	struct screen	*s = ctx->s;
995 	struct tty_ctx	 ttyctx;
996 	u_int		 sx = screen_size_x(s), sy = screen_size_y(s);
997 
998 	screen_write_initctx(ctx, &ttyctx);
999 
1000 	screen_dirty_clear(s, 0, 0, sx - 1, sy  - 1);
1001 
1002 	/* Scroll into history if it is enabled. */
1003 	if (s->grid->flags & GRID_HISTORY)
1004 		grid_view_clear_history(s->grid);
1005 	else
1006 		grid_view_clear(s->grid, 0, 0, sx, sy);
1007 
1008 	tty_write(tty_cmd_clearscreen, &ttyctx);
1009 }
1010 
1011 /* Clear entire history. */
1012 void
1013 screen_write_clearhistory(struct screen_write_ctx *ctx)
1014 {
1015 	struct screen	*s = ctx->s;
1016 	struct grid	*gd = s->grid;
1017 
1018 	grid_move_lines(gd, 0, gd->hsize, gd->sy);
1019 	gd->hscrolled = gd->hsize = 0;
1020 }
1021 
1022 /* Write cell data. */
1023 void
1024 screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
1025 {
1026 	struct screen		*s = ctx->s;
1027 	struct grid		*gd = s->grid;
1028 	struct tty_ctx		 ttyctx;
1029 	u_int		 	 width, xx, last;
1030 	u_int			 sx = screen_size_x(s), sy = screen_size_y(s);
1031 	struct grid_line	*gl;
1032 	struct grid_cell 	 tmp_gc, now_gc;
1033 	struct grid_cell_entry	*gce;
1034 	int			 insert, skip, selected, wrapped = 0;
1035 
1036 	ctx->cells++;
1037 
1038 	/* Ignore padding. */
1039 	if (gc->flags & GRID_FLAG_PADDING)
1040 		return;
1041 	width = gc->data.width;
1042 
1043 	/*
1044 	 * If this is a wide character and there is no room on the screen, for
1045 	 * the entire character, don't print it.
1046 	 */
1047 	if (!(s->mode & MODE_WRAP) && (width > 1 &&
1048 	    (width > sx || (s->cx != sx && s->cx > sx - width))))
1049 		return;
1050 
1051 	/*
1052 	 * If the width is zero, combine onto the previous character, if
1053 	 * there is space.
1054 	 */
1055 	if (width == 0) {
1056 		if (screen_write_combine(ctx, &gc->data) == 0) {
1057 			screen_write_initctx(ctx, &ttyctx);
1058 			tty_write(tty_cmd_utf8character, &ttyctx);
1059 		}
1060 		return;
1061 	}
1062 
1063 	/* Initialise the redraw context. */
1064 	screen_write_initctx(ctx, &ttyctx);
1065 
1066 	/* If in insert mode, make space for the cells. */
1067 	if ((s->mode & MODE_INSERT) && s->cx <= sx - width) {
1068 		xx = sx - s->cx - width;
1069 		grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx);
1070 		insert = 1;
1071 	} else
1072 		insert = 0;
1073 	skip = !insert;
1074 
1075 	/* Check this will fit on the current line and wrap if not. */
1076 	if ((s->mode & MODE_WRAP) && s->cx > sx - width) {
1077 		screen_write_flush(ctx);
1078 		screen_write_save_last(ctx, &ttyctx);
1079 		screen_write_linefeed(ctx, 1);
1080 		s->cx = 0;	/* carriage return */
1081 		skip = 0;
1082 		wrapped = 1;
1083 	}
1084 
1085 	/* Sanity check cursor position. */
1086 	if (s->cx > sx - width || s->cy > sy - 1)
1087 		return;
1088 
1089 	/* Handle overwriting of UTF-8 characters. */
1090 	gl = &s->grid->linedata[s->grid->hsize + s->cy];
1091 	if (gl->flags & GRID_LINE_EXTENDED) {
1092 		grid_view_get_cell(gd, s->cx, s->cy, &now_gc);
1093 		if (screen_write_overwrite(ctx, &now_gc, width))
1094 			skip = 0;
1095 	}
1096 
1097 	/*
1098 	 * If the new character is UTF-8 wide, fill in padding cells. Have
1099 	 * already ensured there is enough room.
1100 	 */
1101 	for (xx = s->cx + 1; xx < s->cx + width; xx++) {
1102 		grid_view_set_cell(gd, xx, s->cy, &screen_write_pad_cell);
1103 		skip = 0;
1104 	}
1105 
1106 	/* If no change, do not draw. */
1107 	if (skip) {
1108 		if (s->cx >= gl->cellsize)
1109 			skip = grid_cells_equal(gc, &grid_default_cell);
1110 		else {
1111 			gce = &gl->celldata[s->cx];
1112 			if (gce->flags & GRID_FLAG_EXTENDED)
1113 				skip = 0;
1114 			else if (gc->flags != (gce->flags & ~GRID_FLAG_EXTENDED))
1115 				skip = 0;
1116 			else if (gc->attr != gce->data.attr)
1117 				skip = 0;
1118 			else if (gc->fg != gce->data.fg)
1119 				skip = 0;
1120 			else if (gc->bg != gce->data.bg)
1121 				skip = 0;
1122 			else if (gc->data.width != 1 || gce->data.data != gc->data.data[0])
1123 				skip = 0;
1124 		}
1125 	}
1126 
1127 	/* Update the selection the flag and set the cell. */
1128 	selected = screen_check_selection(s, s->cx, s->cy);
1129 	if (selected && ~gc->flags & GRID_FLAG_SELECTED) {
1130 		skip = 0;
1131 		memcpy(&tmp_gc, gc, sizeof tmp_gc);
1132 		tmp_gc.flags |= GRID_FLAG_SELECTED;
1133 		grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc);
1134 	} else if (!selected && gc->flags & GRID_FLAG_SELECTED) {
1135 		skip = 0;
1136 		memcpy(&tmp_gc, gc, sizeof tmp_gc);
1137 		tmp_gc.flags &= ~GRID_FLAG_SELECTED;
1138 		grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc);
1139 	} else if (!skip)
1140 		grid_view_set_cell(gd, s->cx, s->cy, gc);
1141 
1142 	/*
1143 	 * Move the cursor. If not wrapping, stick at the last character and
1144 	 * replace it.
1145 	 */
1146 	last = !(s->mode & MODE_WRAP);
1147 	if (s->cx <= sx - last - width)
1148 		s->cx += width;
1149 	else
1150 		s->cx = sx - last;
1151 
1152 	/* Create space for character in insert mode. */
1153 	if (insert) {
1154 		if (!wrapped)
1155 			screen_write_flush(ctx);
1156 		ttyctx.num = width;
1157 		tty_write(tty_cmd_insertcharacter, &ttyctx);
1158 	}
1159 
1160 	/* Write to the screen. */
1161 	if (selected) {
1162 		memcpy(&tmp_gc, &s->sel.cell, sizeof tmp_gc);
1163 		utf8_copy(&tmp_gc.data, &gc->data);
1164 		tmp_gc.attr = tmp_gc.attr & ~GRID_ATTR_CHARSET;
1165 		tmp_gc.attr |= gc->attr & GRID_ATTR_CHARSET;
1166 		tmp_gc.flags = gc->flags;
1167 		screen_write_flush(ctx);
1168 		ttyctx.cell = &tmp_gc;
1169 		tty_write(tty_cmd_cell, &ttyctx);
1170 		ctx->written++;
1171 	} else if (!skip) {
1172 		if (wrapped) {
1173 			ttyctx.cell = gc;
1174 			tty_write(tty_cmd_cell, &ttyctx);
1175 			ctx->written++;
1176 		} else {
1177 			/*
1178 			 * If wp is NULL, we are not updating the terminal and
1179 			 * don't care about actually writing the cells
1180 			 * (tty_write will just return). So don't even bother
1181 			 * allocating the dirty array.
1182 			 */
1183 			if (ctx->wp != NULL && s->dirty == NULL) {
1184 				log_debug("%s: allocating %u bits", __func__,
1185 				    s->dirtysize);
1186 				s->dirty = bit_alloc(s->dirtysize);
1187 			}
1188 			if (s->dirty != NULL) {
1189 				bit_set(s->dirty, screen_dirty_bit(s,
1190 				    ttyctx.ocx, ttyctx.ocy));
1191 				ctx->dirty++;
1192 			}
1193 		}
1194 	} else
1195 		ctx->skipped++;
1196 }
1197 
1198 /* Combine a UTF-8 zero-width character onto the previous. */
1199 static int
1200 screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud)
1201 {
1202 	struct screen		*s = ctx->s;
1203 	struct grid		*gd = s->grid;
1204 	struct grid_cell	 gc;
1205 
1206 	/* Can't combine if at 0. */
1207 	if (s->cx == 0)
1208 		return (-1);
1209 
1210 	/* Empty data is out. */
1211 	if (ud->size == 0)
1212 		fatalx("UTF-8 data empty");
1213 
1214 	/* Retrieve the previous cell. */
1215 	grid_view_get_cell(gd, s->cx - 1, s->cy, &gc);
1216 
1217 	/* Check there is enough space. */
1218 	if (gc.data.size + ud->size > sizeof gc.data.data)
1219 		return (-1);
1220 
1221 	/* Append the data. */
1222 	memcpy(gc.data.data + gc.data.size, ud->data, ud->size);
1223 	gc.data.size += ud->size;
1224 
1225 	/* Set the new cell. */
1226 	grid_view_set_cell(gd, s->cx - 1, s->cy, &gc);
1227 
1228 	return (0);
1229 }
1230 
1231 /*
1232  * UTF-8 wide characters are a bit of an annoyance. They take up more than one
1233  * cell on the screen, so following cells must not be drawn by marking them as
1234  * padding.
1235  *
1236  * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8
1237  * character, it is necessary to also overwrite any other cells which covered
1238  * by the same character.
1239  */
1240 static int
1241 screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc,
1242     u_int width)
1243 {
1244 	struct screen		*s = ctx->s;
1245 	struct grid		*gd = s->grid;
1246 	struct grid_cell	 tmp_gc;
1247 	u_int			 xx;
1248 	int			 done = 0;
1249 
1250 	if (gc->flags & GRID_FLAG_PADDING) {
1251 		/*
1252 		 * A padding cell, so clear any following and leading padding
1253 		 * cells back to the character. Don't overwrite the current
1254 		 * cell as that happens later anyway.
1255 		 */
1256 		xx = s->cx + 1;
1257 		while (--xx > 0) {
1258 			grid_view_get_cell(gd, xx, s->cy, &tmp_gc);
1259 			if (~tmp_gc.flags & GRID_FLAG_PADDING)
1260 				break;
1261 			grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1262 		}
1263 
1264 		/* Overwrite the character at the start of this padding. */
1265 		grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1266 		done = 1;
1267 	}
1268 
1269 	/*
1270 	 * Overwrite any padding cells that belong to a UTF-8 character
1271 	 * we'll be overwriting with the current character.
1272 	 */
1273 	if (gc->data.width != 1 || gc->flags & GRID_FLAG_PADDING) {
1274 		xx = s->cx + width - 1;
1275 		while (++xx < screen_size_x(s)) {
1276 			grid_view_get_cell(gd, xx, s->cy, &tmp_gc);
1277 			if (~tmp_gc.flags & GRID_FLAG_PADDING)
1278 				break;
1279 			grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1280 			done = 1;
1281 		}
1282 	}
1283 
1284 	return (done);
1285 }
1286 
1287 void
1288 screen_write_setselection(struct screen_write_ctx *ctx, u_char *str, u_int len)
1289 {
1290 	struct tty_ctx	ttyctx;
1291 
1292 	screen_write_initctx(ctx, &ttyctx);
1293 	ttyctx.ptr = str;
1294 	ttyctx.num = len;
1295 
1296 	tty_write(tty_cmd_setselection, &ttyctx);
1297 }
1298 
1299 void
1300 screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len)
1301 {
1302 	struct tty_ctx	ttyctx;
1303 
1304 	screen_write_initctx(ctx, &ttyctx);
1305 	ttyctx.ptr = str;
1306 	ttyctx.num = len;
1307 
1308 	tty_write(tty_cmd_rawstring, &ttyctx);
1309 }
1310