GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/tmux/screen-write.c Lines: 0 606 0.0 %
Date: 2016-12-06 Branches: 0 420 0.0 %

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