fixed tmux system theme loading

This commit is contained in:
2026-02-05 14:20:51 -05:00
parent e239b33042
commit 3d156403c7
3 changed files with 99 additions and 48 deletions

View File

@@ -1,5 +1,4 @@
import { createSignal } from "solid-js"; import { createSignal } from "solid-js";
import { useRenderer } from "@opentui/solid";
import { Layout } from "./components/Layout"; import { Layout } from "./components/Layout";
import { Navigation } from "./components/Navigation"; import { Navigation } from "./components/Navigation";
import { TabNavigation } from "./components/TabNavigation"; import { TabNavigation } from "./components/TabNavigation";

View File

@@ -9,7 +9,7 @@ import { generateSyntax, generateSubtleSyntax } from "../utils/syntax-highlighte
import { resolveTerminalTheme, loadThemes } from "../utils/theme" import { resolveTerminalTheme, loadThemes } from "../utils/theme"
import { createSimpleContext } from "./helper" import { createSimpleContext } from "./helper"
import { setupThemeSignalHandler, emitThemeChanged, emitThemeModeChanged } from "../utils/theme-observer" import { setupThemeSignalHandler, emitThemeChanged, emitThemeModeChanged } from "../utils/theme-observer"
import type { RGBA, TerminalColors } from "@opentui/core" import { createTerminalPalette, type RGBA, type TerminalColors } from "@opentui/core"
type ThemeResolved = { type ThemeResolved = {
primary: RGBA primary: RGBA
@@ -121,44 +121,82 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
}) })
} }
function resolveSystemTheme() { async function waitForCapabilities(timeoutMs = 300) {
renderer if (renderer.capabilities) return
.getPalette({ size: 16 }) await new Promise<void>((resolve) => {
.then((colors) => { let done = false
if (!colors.palette[0]) { const onCaps = () => {
// No system colors available, fall back to default if (done) return
// This happens when the terminal doesn't support OSC palette queries done = true
// (e.g., running inside tmux, or on unsupported terminals) renderer.off("capabilities", onCaps)
if (store.active === "system") { clearTimeout(timer)
setStore( resolve()
produce((draft) => { }
draft.active = "opencode" const timer = setTimeout(() => {
draft.ready = true if (done) return
}) done = true
) renderer.off("capabilities", onCaps)
} resolve()
return }, timeoutMs)
renderer.on("capabilities", onCaps)
})
}
async function resolveSystemTheme() {
if (process.env.TMUX) {
await waitForCapabilities()
}
let colors: TerminalColors | null = null
try {
colors = await renderer.getPalette({ size: 16 })
} catch {
colors = null
}
if (!colors?.palette?.[0] && process.env.TMUX) {
const writeOut = (renderer as unknown as { writeOut?: (data: string | Buffer) => boolean }).writeOut
const writeFn = typeof writeOut === "function" ? writeOut.bind(renderer) : process.stdout.write.bind(process.stdout)
const detector = createTerminalPalette(process.stdin, process.stdout, writeFn, true)
try {
const tmuxColors = await detector.detect({ size: 16, timeout: 1200 })
if (tmuxColors?.palette?.[0]) {
colors = tmuxColors
} }
} finally {
detector.cleanup()
}
}
const hasPalette = Boolean(colors?.palette?.some((value) => Boolean(value)))
const hasDefaultColors = Boolean(colors?.defaultBackground || colors?.defaultForeground)
if (!hasPalette && !hasDefaultColors) {
// No system colors available, fall back to default
// This happens when the terminal doesn't support OSC palette queries
// (e.g., running inside tmux, or on unsupported terminals)
if (store.active === "system") {
setStore( setStore(
produce((draft) => { produce((draft) => {
draft.system = colors draft.active = "opencode"
if (store.active === "system") { draft.ready = true
draft.ready = true
}
}) })
) )
}) }
.catch(() => { return
// On error, fall back to default theme if using system }
if (store.active === "system") {
setStore( if (colors) {
produce((draft) => { setStore(
draft.active = "opencode" produce((draft) => {
draft.ready = true draft.system = colors
}) if (store.active === "system") {
) draft.ready = true
} }
}) })
)
}
} }
onMount(init) onMount(init)

View File

@@ -1,4 +1,10 @@
import { render } from "@opentui/solid" // Hack: Force TERM to tmux-256color when running in tmux to enable
// correct palette detection in @opentui/core
if (process.env.TMUX && !process.env.TERM?.includes("tmux")) {
process.env.TERM = "tmux-256color"
}
import { render, useRenderer } from "@opentui/solid"
import { App } from "./App" import { App } from "./App"
import { ThemeProvider } from "./context/ThemeContext" import { ThemeProvider } from "./context/ThemeContext"
import { ToastProvider, Toast } from "./ui/toast" import { ToastProvider, Toast } from "./ui/toast"
@@ -6,17 +12,25 @@ import { KeybindProvider } from "./context/KeybindContext"
import { DialogProvider } from "./ui/dialog" import { DialogProvider } from "./ui/dialog"
import { CommandProvider } from "./ui/command" import { CommandProvider } from "./ui/command"
function RendererSetup(props: { children: unknown }) {
const renderer = useRenderer()
renderer.disableStdoutInterception()
return props.children
}
render(() => ( render(() => (
<ToastProvider> <RendererSetup>
<ThemeProvider mode="dark"> <ToastProvider>
<KeybindProvider> <ThemeProvider mode="dark">
<DialogProvider> <KeybindProvider>
<CommandProvider> <DialogProvider>
<App /> <CommandProvider>
<Toast /> <App />
</CommandProvider> <Toast />
</DialogProvider> </CommandProvider>
</KeybindProvider> </DialogProvider>
</ThemeProvider> </KeybindProvider>
</ToastProvider> </ThemeProvider>
</ToastProvider>
</RendererSetup>
)) ))