diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-theme-list.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-theme-list.tsx index 6cf3539ad947..89db62373a47 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-theme-list.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-theme-list.tsx @@ -17,7 +17,7 @@ export function DialogThemeList() { const initial = theme.selected onCleanup(() => { - if (!confirmed) theme.set(initial) + if (!confirmed) theme.preview(initial) }) return ( @@ -26,7 +26,7 @@ export function DialogThemeList() { options={options} current={initial} onMove={(opt) => { - theme.set(opt.value) + theme.preview(opt.value) }} onSelect={(opt) => { theme.set(opt.value) @@ -38,12 +38,12 @@ export function DialogThemeList() { }} onFilter={(query) => { if (query.length === 0) { - theme.set(initial) + theme.preview(initial) return } const first = ref.filtered[0] - if (first) theme.set(first.value) + if (first) theme.preview(first.value) }} /> ) diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx index 33dfd3056db6..63546e1a1fb9 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx @@ -478,6 +478,11 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ kv.set("theme", theme) return true }, + preview(theme: string) { + if (!hasTheme(theme)) return false + setStore("active", theme) + return true + }, get ready() { return store.ready }, diff --git a/packages/opencode/test/fixture/tui-plugin.ts b/packages/opencode/test/fixture/tui-plugin.ts index ef18801571f0..b4d46c7b7bc6 100644 --- a/packages/opencode/test/fixture/tui-plugin.ts +++ b/packages/opencode/test/fixture/tui-plugin.ts @@ -109,6 +109,7 @@ type Opts = { selected?: string has?: HostPluginApi["theme"]["has"] set?: HostPluginApi["theme"]["set"] + preview?: HostPluginApi["theme"]["preview"] install?: HostPluginApi["theme"]["install"] mode?: HostPluginApi["theme"]["mode"] ready?: boolean @@ -149,6 +150,13 @@ export function createTuiPluginApi(opts: Opts = {}): HostPluginApi { selected = name return true }) + const preview = + opts.theme?.preview ?? + ((name: string) => { + if (!has(name)) return false + selected = name + return true + }) const renderer: CliRenderer = opts.renderer ?? { ...Object.create(null), once(this: CliRenderer) { @@ -339,6 +347,9 @@ export function createTuiPluginApi(opts: Opts = {}): HostPluginApi { set(name) { return set(name) }, + preview(name) { + return preview(name) + }, async install(file) { if (opts.theme?.install) return opts.theme.install(file) throw new Error("base theme.install should not run") diff --git a/packages/plugin/src/tui.ts b/packages/plugin/src/tui.ts index e36d91381d5d..5b83bbb791cc 100644 --- a/packages/plugin/src/tui.ts +++ b/packages/plugin/src/tui.ts @@ -361,6 +361,7 @@ export type TuiTheme = { readonly selected: string has: (name: string) => boolean set: (name: string) => boolean + preview: (name: string) => boolean install: (jsonPath: string) => Promise mode: () => "dark" | "light" readonly ready: boolean