diff --git a/src/App.tsx b/src/App.tsx index 788b6da..9e49145 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,4 @@ import { createSignal } from "solid-js"; -import { useRenderer } from "@opentui/solid"; import { Layout } from "./components/Layout"; import { Navigation } from "./components/Navigation"; import { TabNavigation } from "./components/TabNavigation"; diff --git a/src/context/ThemeContext.tsx b/src/context/ThemeContext.tsx index 1fdac56..3179506 100644 --- a/src/context/ThemeContext.tsx +++ b/src/context/ThemeContext.tsx @@ -9,7 +9,7 @@ import { generateSyntax, generateSubtleSyntax } from "../utils/syntax-highlighte import { resolveTerminalTheme, loadThemes } from "../utils/theme" import { createSimpleContext } from "./helper" 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 = { primary: RGBA @@ -121,44 +121,82 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ }) } - function resolveSystemTheme() { - renderer - .getPalette({ size: 16 }) - .then((colors) => { - if (!colors.palette[0]) { - // 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( - produce((draft) => { - draft.active = "opencode" - draft.ready = true - }) - ) - } - return + async function waitForCapabilities(timeoutMs = 300) { + if (renderer.capabilities) return + await new Promise((resolve) => { + let done = false + const onCaps = () => { + if (done) return + done = true + renderer.off("capabilities", onCaps) + clearTimeout(timer) + resolve() + } + const timer = setTimeout(() => { + if (done) return + done = true + renderer.off("capabilities", onCaps) + resolve() + }, 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( produce((draft) => { - draft.system = colors - if (store.active === "system") { - draft.ready = true - } + draft.active = "opencode" + draft.ready = true }) ) - }) - .catch(() => { - // On error, fall back to default theme if using system - if (store.active === "system") { - setStore( - produce((draft) => { - draft.active = "opencode" - draft.ready = true - }) - ) - } - }) + } + return + } + + if (colors) { + setStore( + produce((draft) => { + draft.system = colors + if (store.active === "system") { + draft.ready = true + } + }) + ) + } } onMount(init) diff --git a/src/index.tsx b/src/index.tsx index db0fc8a..654fe92 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -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 { ThemeProvider } from "./context/ThemeContext" import { ToastProvider, Toast } from "./ui/toast" @@ -6,17 +12,25 @@ import { KeybindProvider } from "./context/KeybindContext" import { DialogProvider } from "./ui/dialog" import { CommandProvider } from "./ui/command" +function RendererSetup(props: { children: unknown }) { + const renderer = useRenderer() + renderer.disableStdoutInterception() + return props.children +} + render(() => ( - - - - - - - - - - - - + + + + + + + + + + + + + + ))