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