fix(tui): inherit markdown foreground colors

Pass the active transcript foreground into retained Markdown renderables so unhighlighted fenced code remains visible on light terminal backgrounds. Update existing renderables during theme changes and cover the history hydration path that exposed the regression.
This commit is contained in:
Xubin Ren
2026-09-03 17:02:40 +08:00
parent 54e5c63b7e
commit 61b2f169a8
2 changed files with 43 additions and 2 deletions
+38 -1
View File
@@ -2102,6 +2102,42 @@ describe("NanobotTui layout", () => {
))).toBeTrue() ))).toBeTrue()
}) })
test("renders fenced plain text from light-theme history", async () => {
setup = await createRenderer({ width: 100, height: 30, screenMode: "alternate-screen" })
const app = NanobotTui.mount(
setup.renderer,
{ ...options, theme: "light" },
client(),
new MockTreeSitterClient({ autoResolveTimeout: 0 }),
)
const response = [
"Commit types:",
"",
"```text",
"feat:",
"fix:",
"perf:",
"docs:",
"test:",
"refactor:",
"chore:",
"```",
"",
"Include the reason in the body.",
].join("\n")
const transcript = (app as unknown as { transcript: Transcript }).transcript
transcript.history([{ role: "assistant", content: response }])
await setup.flush()
const code = setup.captureSpans().lines
.flatMap((line) => line.spans)
.find((span) => span.text.includes("feat:"))
expect(setup.captureCharFrame()).toContain("feat:")
expect(code?.fg.toInts().slice(0, 3)).toEqual([24, 24, 27])
})
test("renders assistant LaTeX as Unicode text without changing code", async () => { test("renders assistant LaTeX as Unicode text without changing code", async () => {
setup = await createRenderer({ width: 96, height: 24, screenMode: "alternate-screen" }) setup = await createRenderer({ width: 96, height: 24, screenMode: "alternate-screen" })
const app = mount(setup) const app = mount(setup)
@@ -2152,7 +2188,7 @@ describe("NanobotTui layout", () => {
syntaxStyle: { getStyle(name: string): { fg?: { toInts(): number[] } } | undefined } | null syntaxStyle: { getStyle(name: string): { fg?: { toInts(): number[] } } | undefined } | null
} }
transcript: { transcript: {
markdown: Set<{ syntaxStyle: object }> markdown: Set<{ fg?: { toInts(): number[] }; syntaxStyle: object }>
frames: Set<{ borderColor: { toInts(): number[] } }> frames: Set<{ borderColor: { toInts(): number[] } }>
userRows: Set<{ backgroundColor: { intent: string; toInts(): number[] } }> userRows: Set<{ backgroundColor: { intent: string; toInts(): number[] } }>
userMessages: Set<{ renderable: TextRenderable }> userMessages: Set<{ renderable: TextRenderable }>
@@ -2186,6 +2222,7 @@ describe("NanobotTui layout", () => {
expect(internals.composer.textColor.toInts().slice(0, 3)).toEqual([24, 24, 27]) expect(internals.composer.textColor.toInts().slice(0, 3)).toEqual([24, 24, 27])
expect(sessionFrame?.borderColor.toInts().slice(0, 3)).toEqual([212, 212, 216]) expect(sessionFrame?.borderColor.toInts().slice(0, 3)).toEqual([212, 212, 216])
expect(userRow?.backgroundColor.toInts().slice(0, 3)).toEqual([240, 240, 240]) expect(userRow?.backgroundColor.toInts().slice(0, 3)).toEqual([240, 240, 240])
expect(markdown?.fg?.toInts().slice(0, 3)).toEqual([24, 24, 27])
expect(markdown?.syntaxStyle).not.toBe(darkSyntax) expect(markdown?.syntaxStyle).not.toBe(darkSyntax)
expect(internals.composer.syntaxStyle).not.toBe(darkComposerSyntax) expect(internals.composer.syntaxStyle).not.toBe(darkComposerSyntax)
expect(internals.composer.syntaxStyle?.getStyle("image.placeholder")?.fg?.toInts().slice(0, 3)) expect(internals.composer.syntaxStyle?.getStyle("image.placeholder")?.fg?.toInts().slice(0, 3))
+5 -1
View File
@@ -183,7 +183,10 @@ export class Transcript {
message.displayContent, message.displayContent,
) )
} }
for (const renderable of this.markdown) renderable.syntaxStyle = theme.syntax for (const renderable of this.markdown) {
renderable.fg = theme.text
renderable.syntaxStyle = theme.syntax
}
for (const frame of this.frames) frame.borderColor = theme.border for (const frame of this.frames) frame.borderColor = theme.border
for (const row of this.userRows) { for (const row of this.userRows) {
row.backgroundColor = theme.userBackground row.backgroundColor = theme.userBackground
@@ -664,6 +667,7 @@ export class Transcript {
minWidth: 0, minWidth: 0,
flexGrow: 1, flexGrow: 1,
flexShrink: 1, flexShrink: 1,
fg: this.theme.text,
syntaxStyle: this.theme.syntax, syntaxStyle: this.theme.syntax,
streaming, streaming,
internalBlockMode: "top-level", internalBlockMode: "top-level",