1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
/* Canonical-screen projection into independently sized client views. */
#include "slosh.h"
#include <stdio.h>
#include <string.h>
static int fails;
static void ok(const char *name, bool cond) {
if (!cond) fails++;
printf("%s %s\n", cond ? "ok " : "FAIL", name);
}
static char at(screen_t *s, uint16_t x, uint16_t y) {
cell_t *c = screen_at(s, x, y);
return c && c->len ? c->text[0] : ' ';
}
int main(void) {
screen_t src, view;
screen_init(&src, 6, 4);
for (uint16_t y = 0; y < src.rows; y++)
for (uint16_t x = 0; x < src.cols; x++) {
char ch = (char)('A' + y * src.cols + x);
screen_put_utf8(&src, x, y, &ch, 1, (color_t){0}, (color_t){0}, 0);
}
src.cursor_visible = true;
src.cursor_x = 4;
src.cursor_y = 2;
uint16_t link = screen_link_id(&src, "https://example.test", 20);
screen_set_link(&src, 3, 2, link);
screen_at(&src, 3, 2)->attrs = ATTR_BOLD;
screen_init(&view, 8, 5);
screen_project(&view, &src, 0, 0);
ok("a larger client gets the canonical top-left", at(&view, 5, 3) == 'X');
ok("columns beyond the canonical screen are filler", at(&view, 6, 0) == ' ');
ok("rows beyond the canonical screen are filler", at(&view, 0, 4) == ' ');
ok("the cursor is translated into the client",
view.cursor_visible && view.cursor_x == 4 && view.cursor_y == 2);
screen_resize(&view, 3, 2);
screen_project(&view, &src, 2, 1);
ok("a smaller client receives the selected crop",
at(&view, 0, 0) == 'I' && at(&view, 2, 1) == 'Q');
ok("styles survive projection", (screen_at(&view, 1, 1)->attrs & ATTR_BOLD));
ok("hyperlinks survive projection",
view.cur_link[4] != 0 &&
strcmp(view.links[view.cur_link[4] - 1], "https://example.test") == 0);
ok("a cursor in the crop uses local coordinates",
view.cursor_visible && view.cursor_x == 2 && view.cursor_y == 1);
uint16_t vx = 0, vy = 0;
screen_follow_cursor(&src, 3, 2, &vx, &vy);
ok("a small viewport follows the cursor minimally", vx == 2 && vy == 1);
src.cursor_x = 1;
src.cursor_y = 0;
screen_follow_cursor(&src, 3, 2, &vx, &vy);
ok("the viewport follows the cursor back toward the origin",
vx == 1 && vy == 0);
src.cursor_visible = false;
vx = 99;
vy = 99;
screen_follow_cursor(&src, 3, 2, &vx, &vy);
ok("a hidden cursor retains and clamps the viewport", vx == 3 && vy == 2);
screen_put_utf8(&src, 4, 0, "日", strlen("日"), (color_t){0}, (color_t){0},
0);
screen_resize(&view, 5, 1);
screen_project(&view, &src, 0, 0);
ok("a wide glyph cut at the right edge is blank", at(&view, 4, 0) == ' ');
screen_project(&view, &src, 5, 0);
ok("a wide-glyph tail cut at the left edge is blank", at(&view, 0, 0) == ' ');
/* The diff must not trust a wide glyph's tail column. Rule, then a wide
* glyph over it, then rule again: overwriting the head makes the terminal
* blank the tail cell, so the third frame has to repaint that column even
* though its content matches what the diff last painted there. Skipping it
* is a one-cell hole in a border, where a wide title glyph used to be. */
screen_t d;
screen_init(&d, 6, 1);
for (uint16_t x = 0; x < 6; x++)
screen_put_utf8(&d, x, 0, "-", 1, (color_t){0}, (color_t){0}, 0);
screen_render(&d); /* frame 1: the rule */
screen_put_utf8(&d, 2, 0, "\xe6\x97\xa5", 3, (color_t){0}, (color_t){0},
0); /* frame 2: 日 over columns 2-3 */
screen_render(&d);
screen_put_utf8(&d, 2, 0, "-", 1, (color_t){0}, (color_t){0}, 0);
screen_put_utf8(&d, 3, 0, "-", 1, (color_t){0}, (color_t){0}, 0);
screen_render(&d); /* frame 3: the rule again */
/* Both rule cells must go out: an explicit CUP to column 4, or the run
* that starts at the head's CUP simply carrying on into it. Counting the
* plain '-' bytes in the frame answers both shapes at once. */
size_t dashes = 0;
for (size_t i = 0; i < d.out_len; i++)
if (d.out[i] == '-') dashes++;
ok("an overwritten wide glyph's tail column is repainted", dashes == 2);
screen_free(&d);
screen_free(&view);
screen_free(&src);
printf("\n%s (%d failures)\n", fails ? "FAILED" : "all green", fails);
return fails ? 1 : 0;
}
|