[PR #5240] feat: add theme support for thinking text opacity #11307

Closed
opened 2026-02-16 18:16:07 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/anomalyco/opencode/pull/5240

State: closed
Merged: Yes


Fixes #5213

Adds a configurable thinkingOpacity setting to theme JSON files, allowing users to customize the opacity of thinking/reasoning text instead of using the hardcoded 0.6 value.

Changes

  • Added thinkingOpacity?: number to ThemeJson.theme type
  • Added thinkingOpacity: number to resolved Theme type
  • Handle thinkingOpacity in resolveTheme() with default of 0.6 for backward compatibility
  • Updated generateSubtleSyntax() to use theme.thinkingOpacity

Usage

{
  "theme": {
    "thinkingOpacity": 0.4,
    ...
  }
}

Testing performed

Unit tests (not committed)
import { describe, expect, test } from "bun:test"
import { RGBA } from "@opentui/core"
import opencode from "@/cli/cmd/tui/context/theme/opencode.json"

describe("theme thinkingOpacity", () => {
  test("default theme does not specify thinkingOpacity (defaults to 0.6)", () => {
    expect(opencode.theme).not.toHaveProperty("thinkingOpacity")
  })

  test("thinkingOpacity applies to alpha channel correctly", () => {
    const testCases = [
      { opacity: 0.3, expectedAlpha: Math.round(0.3 * 255) },
      { opacity: 0.6, expectedAlpha: Math.round(0.6 * 255) },
      { opacity: 0.9, expectedAlpha: Math.round(0.9 * 255) },
      { opacity: 1.0, expectedAlpha: 255 },
      { opacity: 0.0, expectedAlpha: 0 },
    ]

    for (const { opacity, expectedAlpha } of testCases) {
      const fg = RGBA.fromInts(255, 128, 64)
      const subtleFg = RGBA.fromInts(
        Math.round(fg.r * 255),
        Math.round(fg.g * 255),
        Math.round(fg.b * 255),
        Math.round(opacity * 255),
      )
      expect(Math.round(subtleFg.a * 255)).toBe(expectedAlpha)
    }
  })

  test("thinkingOpacity preserves RGB values", () => {
    const opacity = 0.5
    const fg = RGBA.fromInts(200, 150, 100)
    const subtleFg = RGBA.fromInts(
      Math.round(fg.r * 255),
      Math.round(fg.g * 255),
      Math.round(fg.b * 255),
      Math.round(opacity * 255),
    )
    
    expect(Math.round(subtleFg.r * 255)).toBe(200)
    expect(Math.round(subtleFg.g * 255)).toBe(150)
    expect(Math.round(subtleFg.b * 255)).toBe(100)
  })

  test("boundary values for thinkingOpacity", () => {
    const testCases = [
      { opacity: 0, desc: "fully transparent" },
      { opacity: 0.3, desc: "low opacity" },
      { opacity: 0.6, desc: "default opacity" },
      { opacity: 0.9, desc: "high opacity" },
      { opacity: 1, desc: "fully opaque" },
    ]

    for (const { opacity } of testCases) {
      const alpha = Math.round(opacity * 255)
      expect(alpha).toBeGreaterThanOrEqual(0)
      expect(alpha).toBeLessThanOrEqual(255)
    }
  })
})

All 5 tests passed.

  • Typecheck passes
  • All 255 existing tests pass
**Original Pull Request:** https://github.com/anomalyco/opencode/pull/5240 **State:** closed **Merged:** Yes --- Fixes #5213 Adds a configurable `thinkingOpacity` setting to theme JSON files, allowing users to customize the opacity of thinking/reasoning text instead of using the hardcoded 0.6 value. ## Changes - Added `thinkingOpacity?: number` to `ThemeJson.theme` type - Added `thinkingOpacity: number` to resolved `Theme` type - Handle `thinkingOpacity` in `resolveTheme()` with default of `0.6` for backward compatibility - Updated `generateSubtleSyntax()` to use `theme.thinkingOpacity` ## Usage ```json { "theme": { "thinkingOpacity": 0.4, ... } } ``` ## Testing performed <details> <summary>Unit tests (not committed)</summary> ```typescript import { describe, expect, test } from "bun:test" import { RGBA } from "@opentui/core" import opencode from "@/cli/cmd/tui/context/theme/opencode.json" describe("theme thinkingOpacity", () => { test("default theme does not specify thinkingOpacity (defaults to 0.6)", () => { expect(opencode.theme).not.toHaveProperty("thinkingOpacity") }) test("thinkingOpacity applies to alpha channel correctly", () => { const testCases = [ { opacity: 0.3, expectedAlpha: Math.round(0.3 * 255) }, { opacity: 0.6, expectedAlpha: Math.round(0.6 * 255) }, { opacity: 0.9, expectedAlpha: Math.round(0.9 * 255) }, { opacity: 1.0, expectedAlpha: 255 }, { opacity: 0.0, expectedAlpha: 0 }, ] for (const { opacity, expectedAlpha } of testCases) { const fg = RGBA.fromInts(255, 128, 64) const subtleFg = RGBA.fromInts( Math.round(fg.r * 255), Math.round(fg.g * 255), Math.round(fg.b * 255), Math.round(opacity * 255), ) expect(Math.round(subtleFg.a * 255)).toBe(expectedAlpha) } }) test("thinkingOpacity preserves RGB values", () => { const opacity = 0.5 const fg = RGBA.fromInts(200, 150, 100) const subtleFg = RGBA.fromInts( Math.round(fg.r * 255), Math.round(fg.g * 255), Math.round(fg.b * 255), Math.round(opacity * 255), ) expect(Math.round(subtleFg.r * 255)).toBe(200) expect(Math.round(subtleFg.g * 255)).toBe(150) expect(Math.round(subtleFg.b * 255)).toBe(100) }) test("boundary values for thinkingOpacity", () => { const testCases = [ { opacity: 0, desc: "fully transparent" }, { opacity: 0.3, desc: "low opacity" }, { opacity: 0.6, desc: "default opacity" }, { opacity: 0.9, desc: "high opacity" }, { opacity: 1, desc: "fully opaque" }, ] for (const { opacity } of testCases) { const alpha = Math.round(opacity * 255) expect(alpha).toBeGreaterThanOrEqual(0) expect(alpha).toBeLessThanOrEqual(255) } }) }) ``` All 5 tests passed. </details> - Typecheck passes - All 255 existing tests pass
yindo added the pull-request label 2026-02-16 18:16:07 -05:00
yindo closed this issue 2026-02-16 18:16:07 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#11307