Skip to content

Commit 49b8854

Browse files
committed
🔧 return Uint8Array from render, fix duplicate element IDs
- Change Term.render() to return Uint8Array instead of string, avoiding unnecessary TextDecoder overhead on every frame - Fix Clay element ID collisions by adding a monotonic index to the hash - Remove cursor hide/show from the C render path (caller responsibility) - Update README example and tests to match new return type
1 parent d070a25 commit 49b8854

5 files changed

Lines changed: 17 additions & 19 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ WebAssembly does: Deno, Node, Bun, browsers, or any other runtime.
2525
| -> diff against (front) |
2626
| -> escape bytes |
2727
+---------------+ | |
28-
| | ANSI string | |
28+
| | ANSI byte array| |
2929
| stdout.write | <============= | |
3030
| | | |
3131
+---------------+ +---------------------------+
@@ -55,7 +55,7 @@ const ansi = term.render([
5555
close(),
5656
]);
5757

58-
Deno.stdout.writeSync(new TextEncoder().encode(ansi));
58+
Deno.stdout.writeSync(ansi);
5959
```
6060

6161
## Development

src/clayterm.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -347,17 +347,11 @@ void render(struct Clayterm *ct, Clay_RenderCommandArray cmds) {
347347

348348
cells_clear(ct->back, ct->w, ct->h);
349349

350-
/* hide cursor */
351-
buf_str(&ct->out, "\x1b[?25l");
352-
353350
/* walk Clay render commands into back buffer */
354351
walk(ct, cmds);
355352

356353
/* diff front vs back, emit escape sequences */
357354
present(ct);
358-
359-
/* show cursor */
360-
buf_str(&ct->out, "\x1b[?25h");
361355
}
362356

363357
char *output(struct Clayterm *ct) { return ct->out.data; }

src/ops.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ static Clay_SizingAxis decode_axis(uint32_t *buf, int len, int *i) {
6161

6262
void reduce(struct Clayterm *ct, uint32_t *buf, int len) {
6363
int i = 0;
64+
uint32_t idx = 0;
6465

6566
Clay_BeginLayout();
6667

@@ -77,7 +78,7 @@ void reduce(struct Clayterm *ct, uint32_t *buf, int len) {
7778

7879
if (id_len > 0) {
7980
Clay_String str = {.length = (int32_t)id_len, .chars = id_chars};
80-
Clay_ElementId eid = Clay__HashString(str, 0);
81+
Clay_ElementId eid = Clay__HashString(str, idx++);
8182
Clay__OpenElementWithId(eid);
8283
} else {
8384
Clay__OpenElement();

term.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ export interface TermOptions {
77
}
88

99
export interface Term {
10-
render(ops: Op[]): string;
10+
render(ops: Op[]): Uint8Array;
1111
}
1212

13-
const decoder = new TextDecoder();
14-
1513
export async function createTerm(options: TermOptions): Promise<Term> {
1614
const { width, height } = options;
1715
const { memory, statePtr, opsBuf, reduce, output, length } = await load(
@@ -20,11 +18,13 @@ export async function createTerm(options: TermOptions): Promise<Term> {
2018
);
2119

2220
return {
23-
render(ops: Op[]): string {
21+
render(ops: Op[]): Uint8Array {
2422
const len = pack(ops, memory.buffer, opsBuf);
2523
reduce(statePtr, opsBuf, len);
26-
return decoder.decode(
27-
new Uint8Array(memory.buffer, output(statePtr), length(statePtr)),
24+
return new Uint8Array(
25+
memory.buffer,
26+
output(statePtr),
27+
length(statePtr),
2828
);
2929
},
3030
};

test/term.test.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { createTerm, type Term } from "../term.ts";
33
import { close, grow, open, rgba, text } from "../ops.ts";
44
import { print } from "./print.ts";
55

6+
const decode = (bytes: Uint8Array) => new TextDecoder().decode(bytes);
7+
68
describe("term", () => {
79
let term: Term;
810

@@ -11,19 +13,19 @@ describe("term", () => {
1113
});
1214

1315
it("renders hello world", () => {
14-
const out = print(term.render([
16+
const out = print(decode(term.render([
1517
open("root", {
1618
layout: { width: grow(), height: grow(), direction: "ttb" },
1719
}),
1820
text("Hello, World!"),
1921
close(),
20-
]), 40, 10);
22+
])), 40, 10);
2123

2224
expect(out).toContain("Hello, World!");
2325
});
2426

2527
it("renders borders and padding", () => {
26-
const out = print(term.render([
28+
const out = print(decode(term.render([
2729
open("box", {
2830
layout: {
2931
width: grow(),
@@ -42,7 +44,7 @@ describe("term", () => {
4244
}),
4345
text("padded"),
4446
close(),
45-
]), 40, 10);
47+
])), 40, 10);
4648

4749
expect(out).toEqual(`
4850
╭──────────────────────────────────────╮
@@ -56,4 +58,5 @@ describe("term", () => {
5658
│ │
5759
╰──────────────────────────────────────╯`.trim());
5860
});
61+
5962
});

0 commit comments

Comments
 (0)