diff --git a/packages/cli/src/mini/footer.ts b/packages/cli/src/mini/footer.ts index 0a2510f167..fd758caf29 100644 --- a/packages/cli/src/mini/footer.ts +++ b/packages/cli/src/mini/footer.ts @@ -627,7 +627,6 @@ export class RunFooter implements FooterApi { this.themes.splice(index, 1) theme.block.syntax?.destroy() - theme.block.subtleSyntax?.destroy() } public close(): void { @@ -1023,7 +1022,6 @@ export class RunFooter implements FooterApi { void resolveRunTheme(this.renderer).then((theme) => { if (this.isGone) { theme.block.syntax?.destroy() - theme.block.subtleSyntax?.destroy() return } diff --git a/packages/cli/src/mini/scrollback.shared.ts b/packages/cli/src/mini/scrollback.shared.ts index fc040536e9..447d260c09 100644 --- a/packages/cli/src/mini/scrollback.shared.ts +++ b/packages/cli/src/mini/scrollback.shared.ts @@ -6,11 +6,7 @@ function syntax(style?: SyntaxStyle): SyntaxStyle { return style ?? SyntaxStyle.fromTheme([]) } -export function entrySyntax(commit: StreamCommit, theme: RunTheme): SyntaxStyle { - if (commit.kind === "reasoning") { - return syntax(theme.block.subtleSyntax ?? theme.block.syntax) - } - +export function entrySyntax(theme: RunTheme): SyntaxStyle { return syntax(theme.block.syntax) } diff --git a/packages/cli/src/mini/scrollback.surface.ts b/packages/cli/src/mini/scrollback.surface.ts index c5e5c6dd7d..d9182219d2 100644 --- a/packages/cli/src/mini/scrollback.surface.ts +++ b/packages/cli/src/mini/scrollback.surface.ts @@ -143,7 +143,7 @@ export class RunScrollbackStream { } active.renderable.fg = entryColor(active.commit, theme) - active.renderable.syntaxStyle = entrySyntax(active.commit, theme) + active.renderable.syntaxStyle = entrySyntax(theme) } private createEntry(commit: StreamCommit, body: ActiveBody): ActiveEntry { @@ -165,7 +165,7 @@ export class RunScrollbackStream { ? new CodeRenderable(surface.renderContext, { content: "", filetype: body.filetype, - syntaxStyle: entrySyntax(commit, this.theme), + syntaxStyle: entrySyntax(this.theme), width: "100%", wrapMode: "word", drawUnstyledText: false, @@ -175,7 +175,7 @@ export class RunScrollbackStream { }) : new MarkdownRenderable(surface.renderContext, { content: "", - syntaxStyle: entrySyntax(commit, this.theme), + syntaxStyle: entrySyntax(this.theme), width: "100%", streaming: true, internalBlockMode: "top-level", diff --git a/packages/cli/src/mini/scrollback.writer.tsx b/packages/cli/src/mini/scrollback.writer.tsx index 74f4a97adf..e6ab9bb408 100644 --- a/packages/cli/src/mini/scrollback.writer.tsx +++ b/packages/cli/src/mini/scrollback.writer.tsx @@ -84,7 +84,7 @@ export function RunEntryContent(props: { const theme = createMemo(() => props.theme ?? RUN_THEME_FALLBACK) const body = createMemo(() => props.body ?? entryBody(props.commit)) const style = createMemo(() => entryLook(props.commit, theme().entry)) - const syntax = createMemo(() => entrySyntax(props.commit, theme())) + const syntax = createMemo(() => entrySyntax(theme())) const color = createMemo(() => entryColor(props.commit, theme())) const suppressBackgrounds = createMemo(() => props.opts?.suppressBackgrounds === true) const diffBg = (color: ColorInput) => (suppressBackgrounds() ? transparent : color) diff --git a/packages/cli/src/mini/theme.ts b/packages/cli/src/mini/theme.ts index e4fb315426..6fe36883d1 100644 --- a/packages/cli/src/mini/theme.ts +++ b/packages/cli/src/mini/theme.ts @@ -47,7 +47,6 @@ export type RunBlockTheme = { text: ColorInput muted: ColorInput syntax?: SyntaxStyle - subtleSyntax?: SyntaxStyle diffAdded: ColorInput diffRemoved: ColorInput diffAddedBg: ColorInput @@ -172,42 +171,10 @@ function tint(base: RGBA, overlay: RGBA, value: number): RGBA { ) } -function blend(color: RGBA, bg: RGBA): RGBA { - if (color.a >= 1) { - return color - } - - return RGBA.fromValues( - bg.r + (color.r - bg.r) * color.a, - bg.g + (color.g - bg.g) * color.a, - bg.b + (color.b - bg.b) * color.a, - 1, - ) -} - function chroma(color: RGBA) { return Math.max(color.r, color.g, color.b) - Math.min(color.r, color.g, color.b) } -function opaqueSyntaxStyle(style: SyntaxStyle | undefined, bg: RGBA): SyntaxStyle | undefined { - if (!style) { - return undefined - } - - return SyntaxStyle.fromStyles( - Object.fromEntries( - [...style.getAllStyles()].map(([name, value]) => [ - name, - { - ...value, - fg: value.fg ? blend(value.fg, bg) : value.fg, - bg: value.bg ? blend(value.bg, bg) : value.bg, - }, - ]), - ), - ) -} - function indexedPalette(colors: TerminalColors, size: number = Math.max(colors.palette.length, 16)): RGBA[] { return Array.from({ length: size }, (_, index) => { const value = colors.palette[index] @@ -502,10 +469,7 @@ function map( scrollbackTheme: TuiThemeCurrent, splash: RunSplashTheme, syntax?: SyntaxStyle, - subtleSyntax?: SyntaxStyle, ): RunTheme { - const opaqueSubtleSyntax = opaqueSyntaxStyle(subtleSyntax, scrollbackTheme.background) - subtleSyntax?.destroy() const footerBackground = alpha(footerTheme.background, 1) const footerMode = mode(footerBackground) const shade = fade(footerTheme.backgroundMenu, footerTheme.background, 0.12, 0.56, 0.72) @@ -566,7 +530,6 @@ function map( text: scrollbackTheme.text, muted: scrollbackTheme.textMuted, syntax, - subtleSyntax: opaqueSubtleSyntax, diffAdded: scrollbackTheme.diffAdded, diffRemoved: scrollbackTheme.diffRemoved, diffAddedBg: transparent, @@ -677,13 +640,7 @@ export async function resolveRunTheme(renderer: CliRenderer): Promise _hasSelectedListItemText: true, } const syntax = shared.generateSyntax(syntaxTheme) - return map( - footerTheme, - scrollbackTheme, - splashTheme(scrollbackTheme, indexed), - syntax, - shared.generateSubtleSyntax(syntaxTheme), - ) + return map(footerTheme, scrollbackTheme, splashTheme(scrollbackTheme, indexed), syntax) } catch { return RUN_THEME_FALLBACK } diff --git a/packages/opencode/test/cli/run/scrollback.surface.test.ts b/packages/opencode/test/cli/run/scrollback.surface.test.ts index 039ab156fd..a4923bd0b3 100644 --- a/packages/opencode/test/cli/run/scrollback.surface.test.ts +++ b/packages/opencode/test/cli/run/scrollback.surface.test.ts @@ -136,14 +136,14 @@ test("theme swaps restyle active reasoning without resetting the stream", async ...RUN_THEME_FALLBACK, block: { ...RUN_THEME_FALLBACK.block, - subtleSyntax: previousSyntax, + syntax: previousSyntax, }, } const next = { ...RUN_THEME_FALLBACK, block: { ...RUN_THEME_FALLBACK.block, - subtleSyntax: nextSyntax, + syntax: nextSyntax, }, } const out = await setup({ theme: previous, onThemeRelease: (theme) => released.push(theme) }) diff --git a/packages/opencode/test/cli/run/theme.test.ts b/packages/opencode/test/cli/run/theme.test.ts index 52b8fc6439..d62a6e9f7f 100644 --- a/packages/opencode/test/cli/run/theme.test.ts +++ b/packages/opencode/test/cli/run/theme.test.ts @@ -67,9 +67,7 @@ test("returns syntax styles and indexed splash colors", async () => { try { expect(theme.block.syntax).toBeDefined() - expect(theme.block.subtleSyntax).toBeDefined() expect([...theme.block.syntax!.getAllStyles()].length).toBeGreaterThan(0) - expect([...theme.block.subtleSyntax!.getAllStyles()].length).toBeGreaterThan(0) expectIndexed(theme.splash.left) expectIndexed(theme.splash.right) expectIndexed(theme.splash.leftShadow) @@ -82,7 +80,6 @@ test("returns syntax styles and indexed splash colors", async () => { expect(expectRgba(theme.footer.statusAccent).toInts()).not.toEqual(expectRgba(theme.footer.status).toInts()) } finally { theme.block.syntax?.destroy() - theme.block.subtleSyntax?.destroy() } }) @@ -103,7 +100,6 @@ test("keeps footer surfaces exact while scrollback stays palette matched", async expectIndexed(theme.block.warning) } finally { theme.block.syntax?.destroy() - theme.block.subtleSyntax?.destroy() } }) @@ -119,9 +115,7 @@ test("uses refreshed background brightness when cached renderer mode is stale", expect(expectRgba(stale.footer.surface).toInts()).toEqual(expectRgba(light.footer.surface).toInts()) } finally { stale.block.syntax?.destroy() - stale.block.subtleSyntax?.destroy() light.block.syntax?.destroy() - light.block.subtleSyntax?.destroy() } }) @@ -138,9 +132,7 @@ test("keeps renderer mode when refreshed default background is unavailable", asy expect(expectRgba(light.footer.surface).toInts()).not.toEqual(expectRgba(dark.footer.surface).toInts()) } finally { light.block.syntax?.destroy() - light.block.subtleSyntax?.destroy() dark.block.syntax?.destroy() - dark.block.subtleSyntax?.destroy() } }) diff --git a/packages/tui/src/context/theme.tsx b/packages/tui/src/context/theme.tsx index 8c4ab4de9f..62ab31792e 100644 --- a/packages/tui/src/context/theme.tsx +++ b/packages/tui/src/context/theme.tsx @@ -4,7 +4,6 @@ import { DEFAULT_THEMES, addTheme, allThemes, - generateSubtleSyntax, generateSyntax, generateSystem, hasTheme, @@ -63,7 +62,6 @@ export { DEFAULT_THEMES, addTheme, allThemes, - generateSubtleSyntax, generateSyntax, generateSystem, hasTheme, @@ -75,7 +73,6 @@ export { upsertTheme, type Theme, type ThemeJson, - type SyntaxStyleOverrides, } from "../theme" const THEME_REFRESH_DELAYS = [250, 1000] as const @@ -277,7 +274,6 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ createEffect(() => renderer.setBackgroundColor(values().background)) const syntax = createSyntaxStyleMemo(() => generateSyntax(values())) - const subtleSyntax = createSyntaxStyleMemo(() => generateSubtleSyntax(values())) return { theme: new Proxy(values(), { @@ -292,7 +288,6 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ all: allThemes, has: hasTheme, syntax, - subtleSyntax, mode: () => store.mode, locked: () => store.lock !== undefined, lock: () => pin(store.mode), diff --git a/packages/tui/src/routes/session/index.tsx b/packages/tui/src/routes/session/index.tsx index 45fdded0ad..788bbbe8e1 100644 --- a/packages/tui/src/routes/session/index.tsx +++ b/packages/tui/src/routes/session/index.tsx @@ -23,7 +23,7 @@ import { useData } from "../../context/data" import { SplitBorder } from "../../ui/border" import { useTuiPaths, useTuiTerminalEnvironment } from "../../context/runtime" import { Spinner, SPINNER_FRAMES } from "../../component/spinner" -import { createSyntaxStyleMemo, generateSubtleSyntax, useTheme } from "../../context/theme" +import { useTheme } from "../../context/theme" import { BoxRenderable, ScrollBoxRenderable, addDefaultParsers, TextAttributes, RGBA } from "@opentui/core" import { Prompt, type PromptRef } from "../../component/prompt" import type { @@ -1716,7 +1716,7 @@ function ReasoningPart(props: { part: SessionMessageAssistantReasoning message: SessionMessageAssistant }) { - const { theme } = useTheme() + const { theme, syntax } = useTheme() const ctx = use() // Collapsed by default in hide mode: a single line throughout, so the // layout never shifts. Click to open the full markdown block, click to close. @@ -1736,8 +1736,6 @@ function ReasoningPart(props: { return end === undefined ? 0 : Math.max(0, end - start) }) const summary = createMemo(() => reasoningSummary(content())) - const syntax = createSyntaxStyleMemo(() => generateSubtleSyntax(theme)) - const toggle = () => { if (!inMinimal()) return setExpanded((prev) => !prev) diff --git a/packages/tui/src/theme/index.ts b/packages/tui/src/theme/index.ts index efdf02357a..27ac47bf0b 100644 --- a/packages/tui/src/theme/index.ts +++ b/packages/tui/src/theme/index.ts @@ -90,7 +90,6 @@ export type Theme = { _hasSelectedListItemText: boolean } type ThemeColor = Exclude -export type SyntaxStyleOverrides = Record export function selectedForeground(theme: Theme, bg?: RGBA): RGBA { // If theme explicitly defines selectedListItemText, use it @@ -557,32 +556,6 @@ export function generateSyntax(theme: Theme) { return SyntaxStyle.fromTheme(getSyntaxRules(theme)) } -export function generateSubtleSyntax(theme: Theme, overrides?: SyntaxStyleOverrides) { - const rules = getSyntaxRules(theme) - return SyntaxStyle.fromTheme( - rules.map((rule) => { - const override = rule.scope.reduce((acc, scope) => ({ ...acc, ...overrides?.[scope] }), {}) - if (rule.style.foreground) { - const fg = rule.style.foreground - return { - ...rule, - style: { - ...rule.style, - ...override, - foreground: RGBA.fromInts( - Math.round(fg.r * 255), - Math.round(fg.g * 255), - Math.round(fg.b * 255), - Math.round(theme.thinkingOpacity * 255), - ), - }, - } - } - return rule - }), - ) -} - function getSyntaxRules(theme: Theme) { return [ {