Skip to content

Code blocks use hardcoded white foreground, making text invisible on light terminal backgrounds #18353

@yykamei

Description

@yykamei

Bug Description

When using a custom light theme on a terminal with a white/light background, text inside code blocks (especially those without a language annotation) is rendered as white text on a white background, making it completely invisible. This cannot be fixed through the theme JSON — the white color is hardcoded in the rendering layer.

Steps to Reproduce

  1. Use a terminal with a white/light background
  2. Create a custom theme with all dark foreground colors:
    {
      "theme": {
        "text": "#383A42",
        "markdownCodeBlock": "#383A42",
        "syntaxComment": "#5F6169",
        "syntaxKeyword": "#A626A4",
        ...
      }
    }
  3. Have the assistant generate a response containing a code block without a language annotation (bare ``` or indented text)
  4. The text inside the code block is rendered in white — invisible on the light background

Root Cause Analysis

After investigating the source code, we identified three contributing factors:

1. Hardcoded white default foreground in TextBufferRenderable

The default foreground color is hardcoded to white:

// TextBufferRenderable.ts
protected _defaultOptions = {
    fg: RGBA.fromValues(1, 1, 1, 1),  // WHITE
    bg: RGBA.fromValues(0, 0, 0, 0),  // transparent
    ...
}

2. createCodeRenderable() does not pass fg from the theme

When MarkdownRenderable creates a CodeRenderable for fenced code blocks, it passes syntaxStyle but not fg:

// Markdown.ts
private createCodeRenderable(token: Tokens.Code, id: string, marginBottom: number = 0): Renderable {
    return new CodeRenderable(this.ctx, {
      id,
      content: token.text,
      filetype: token.lang || undefined,
      syntaxStyle: this._syntaxStyle,  // syntax style IS passed
      conceal: this._concealCode,
      // ... NO fg prop!
    })
}

This means the code block falls back to the hardcoded white default for any text not covered by syntax highlighting.

3. markdownCodeBlock theme property is unused

The markdownCodeBlock property is accepted in the theme JSON schema but is never mapped to any tree-sitter scope in getSyntaxRules() in theme.tsx. Setting it has no effect on rendering.

Combined effect

  • For code blocks with a recognized language: the "default" syntax scope (mapped to theme.text) colors unrecognized tokens correctly, but there may be a flash of white before highlighting completes
  • For code blocks without a language annotation: the entire block renders in the hardcoded white default, with no way to override it via the theme

Suggested Fix

  1. Pass fg to CodeRenderable: In createCodeRenderable(), pass fg from the theme's text color (or from the resolved "default" syntax rule)
  2. Map markdownCodeBlock: Either use markdownCodeBlock as the fg for code block containers, or map it to the markup.raw.block scope in getSyntaxRules()
  3. Make the default foreground theme-aware: Consider changing TextBufferRenderable's default fg from hardcoded white to theme.text

Environment

  • OpenCode version: latest
  • Terminal: white/light background
  • OS: macOS
  • Theme: custom light theme (One Light based)

Metadata

Metadata

Assignees

Labels

coreAnything pertaining to core functionality of the application (opencode server stuff)

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions