-
-
Notifications
You must be signed in to change notification settings - Fork 1
✨ Add border-cell backgrounds #94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,20 @@ | ||
| import { close, grow, open, rgba, text } from "../ops.ts"; | ||
| import { close, fixed, grow, open, rgba, text } from "../ops.ts"; | ||
| import { createTerm } from "../term.ts"; | ||
| import { describe, expect, it } from "./suite.ts"; | ||
|
|
||
| const decode = (b: Uint8Array) => new TextDecoder().decode(b); | ||
|
|
||
| type TextBgColor = { | ||
| type BgColor = { | ||
| value: number; | ||
| sgr: string; | ||
| }; | ||
|
|
||
| function randomTextBgColor(): TextBgColor { | ||
| type Cell = { | ||
| ch: string; | ||
| bg?: string; | ||
| }; | ||
|
|
||
| function randomBgColor(): BgColor { | ||
| let r = 0; | ||
| let g = 0; | ||
| let b = 0; | ||
|
|
@@ -30,6 +35,41 @@ function randomTextBgColor(): TextBgColor { | |
| }; | ||
| } | ||
|
|
||
| function cells(ansi: string): Cell[] { | ||
| let result: Cell[] = []; | ||
| let bg: string | undefined; | ||
|
|
||
| for (let i = 0; i < ansi.length;) { | ||
| if (ansi[i] === "\x1b" && ansi[i + 1] === "[") { | ||
| let end = i + 2; | ||
| while (end < ansi.length && !/[A-Za-z]/.test(ansi[end])) { | ||
| end++; | ||
| } | ||
|
|
||
| let seq = ansi.slice(i, end + 1); | ||
| if (seq === "\x1b[0m") { | ||
| bg = undefined; | ||
| } else if (seq.startsWith("\x1b[48;2;") && seq.endsWith("m")) { | ||
| bg = seq.slice(0, -1); | ||
| } | ||
|
|
||
| i = end + 1; | ||
| continue; | ||
| } | ||
|
|
||
| result.push({ ch: ansi[i], bg }); | ||
| i++; | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| function firstCell(cells: Cell[], ch: string): Cell { | ||
| let cell = cells.find((c) => c.ch === ch); | ||
| expect(cell).toBeDefined(); | ||
| return cell!; | ||
| } | ||
|
|
||
| describe("foreground", () => { | ||
| it("emits uncolored text with no foreground", async () => { | ||
| let term = await createTerm({ width: 12, height: 1 }); | ||
|
|
@@ -41,9 +81,67 @@ describe("foreground", () => { | |
| }); | ||
|
|
||
| describe("background", () => { | ||
| it("fills border cells with the requested border-level bg", async () => { | ||
| let term = await createTerm({ width: 12, height: 4 }); | ||
| let bg = randomBgColor(); | ||
| let ansi = decode( | ||
| term.render([ | ||
| open("box", { | ||
| layout: { width: fixed(8), height: fixed(3), direction: "ttb" }, | ||
| border: { | ||
| color: rgba(255, 255, 255), | ||
| bg: bg.value, | ||
| left: 1, | ||
| right: 1, | ||
| top: 1, | ||
| bottom: 1, | ||
| }, | ||
| }), | ||
| text("Hi"), | ||
| close(), | ||
| ], { mode: "line" }).output, | ||
| ); | ||
|
|
||
| expect(ansi).toContain(`${bg.sgr}m┌`); | ||
|
|
||
| let rendered = cells(ansi); | ||
| expect(firstCell(rendered, "┌").bg).toBe(bg.sgr); | ||
| expect(firstCell(rendered, "─").bg).toBe(bg.sgr); | ||
| expect(firstCell(rendered, "┐").bg).toBe(bg.sgr); | ||
| expect(firstCell(rendered, "│").bg).toBe(bg.sgr); | ||
| }); | ||
|
|
||
| it("leaves existing border-cell bg unchanged when border bg is omitted", async () => { | ||
| let term = await createTerm({ width: 12, height: 4 }); | ||
| let bg = randomBgColor(); | ||
| let ansi = decode( | ||
| term.render([ | ||
| open("box", { | ||
| layout: { width: fixed(8), height: fixed(3), direction: "ttb" }, | ||
| bg: bg.value, | ||
| border: { | ||
| color: rgba(255, 255, 255), | ||
| left: 1, | ||
| right: 1, | ||
| top: 1, | ||
| bottom: 1, | ||
| }, | ||
| }), | ||
| text("Hi"), | ||
| close(), | ||
| ], { mode: "line" }).output, | ||
| ); | ||
|
|
||
| let rendered = cells(ansi); | ||
| expect(firstCell(rendered, "┌").bg).toBe(bg.sgr); | ||
| expect(firstCell(rendered, "─").bg).toBe(bg.sgr); | ||
| expect(firstCell(rendered, "┐").bg).toBe(bg.sgr); | ||
| expect(firstCell(rendered, "│").bg).toBe(bg.sgr); | ||
| }); | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i'm here thinking if we should tighten this test a bit more, from what i'm reading this is asserting the bg SGR appears somewhere in the |
||
| it("fills glyph cells with the requested text-level bg", async () => { | ||
| let term = await createTerm({ width: 20, height: 1 }); | ||
| let bg = randomTextBgColor(); | ||
| let bg = randomBgColor(); | ||
| let ansi = decode( | ||
| term.render([ | ||
| open("root", { layout: { width: grow(), height: grow() } }), | ||
|
|
@@ -56,9 +154,52 @@ describe("background", () => { | |
| expect(beforeH).toContain(bg.sgr); | ||
| }); | ||
|
|
||
| it("resets border bg on subsequent frames without border bg", async () => { | ||
| let term = await createTerm({ width: 12, height: 4 }); | ||
| let bg = randomBgColor(); | ||
|
|
||
| // Frame 1: border with bg | ||
| term.render([ | ||
| open("box", { | ||
| layout: { width: fixed(8), height: fixed(3), direction: "ttb" }, | ||
| border: { | ||
| color: rgba(255, 255, 255), | ||
| bg: bg.value, | ||
| left: 1, | ||
| right: 1, | ||
| top: 1, | ||
| bottom: 1, | ||
| }, | ||
| }), | ||
| text("Hi"), | ||
| close(), | ||
| ]); | ||
|
|
||
| // Frame 2: same border, no bg | ||
| let ansi = decode( | ||
| term.render([ | ||
| open("box", { | ||
| layout: { width: fixed(8), height: fixed(3), direction: "ttb" }, | ||
| border: { | ||
| color: rgba(255, 255, 255), | ||
| left: 1, | ||
| right: 1, | ||
| top: 1, | ||
| bottom: 1, | ||
| }, | ||
| }), | ||
| text("Hi"), | ||
| close(), | ||
| ]).output, | ||
| ); | ||
|
|
||
| expect(ansi).not.toContain(bg.sgr); | ||
| expect(firstCell(cells(ansi), "┌").bg).toBeUndefined(); | ||
| }); | ||
|
|
||
| it("resets the background before writing trailing cells", async () => { | ||
| let term = await createTerm({ width: 20, height: 1 }); | ||
| let bg = randomTextBgColor(); | ||
| let bg = randomBgColor(); | ||
| let ansi = decode( | ||
| term.render([ | ||
| open("root", { layout: { width: grow(), height: grow() } }), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should leave a comment on top of this, something like "userData is currently exclusively the border-bg word"