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