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