fixed tmux system theme loading
This commit is contained in:
@@ -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";
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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>
|
||||||
))
|
))
|
||||||
|
|||||||
Reference in New Issue
Block a user