summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-01-20 07:10:40 -0600
committerAdam <[email protected]>2026-01-20 07:33:44 -0600
commit340285575b510f4ab466fa80d0de1cf20b4e048a (patch)
tree9587a21664547875d060258ad7ee7b3de0dba290 /packages/app/src
parentdd5b5f5482df86959f0ea90e20f86ca7a5e19b08 (diff)
downloadopencode-340285575b510f4ab466fa80d0de1cf20b4e048a.tar.gz
opencode-340285575b510f4ab466fa80d0de1cf20b4e048a.zip
chore: cleanup
Diffstat (limited to 'packages/app/src')
-rw-r--r--packages/app/src/components/settings-general.tsx22
-rw-r--r--packages/app/src/components/settings-keybinds.tsx38
-rw-r--r--packages/app/src/context/command.tsx56
3 files changed, 100 insertions, 16 deletions
diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx
index 15dc98bfb..10f4facef 100644
--- a/packages/app/src/components/settings-general.tsx
+++ b/packages/app/src/components/settings-general.tsx
@@ -77,7 +77,15 @@ export const SettingsGeneral: Component = () => {
current={themeOptions().find((o) => o.id === theme.themeId())}
value={(o) => o.id}
label={(o) => o.name}
- onSelect={(option) => option && theme.setTheme(option.id)}
+ onSelect={(option) => {
+ if (!option) return
+ theme.setTheme(option.id)
+ }}
+ onHighlight={(option) => {
+ if (!option) return
+ theme.previewTheme(option.id)
+ return () => theme.cancelPreview()
+ }}
variant="secondary"
size="small"
/>
@@ -135,6 +143,10 @@ export const SettingsGeneral: Component = () => {
current={soundOptions.find((o) => o.id === settings.sounds.agent())}
value={(o) => o.id}
label={(o) => o.label}
+ onHighlight={(option) => {
+ if (!option) return
+ playSound(option.src)
+ }}
onSelect={(option) => {
if (!option) return
settings.sounds.setAgent(option.id)
@@ -151,6 +163,10 @@ export const SettingsGeneral: Component = () => {
current={soundOptions.find((o) => o.id === settings.sounds.permissions())}
value={(o) => o.id}
label={(o) => o.label}
+ onHighlight={(option) => {
+ if (!option) return
+ playSound(option.src)
+ }}
onSelect={(option) => {
if (!option) return
settings.sounds.setPermissions(option.id)
@@ -167,6 +183,10 @@ export const SettingsGeneral: Component = () => {
current={soundOptions.find((o) => o.id === settings.sounds.errors())}
value={(o) => o.id}
label={(o) => o.label}
+ onHighlight={(option) => {
+ if (!option) return
+ playSound(option.src)
+ }}
onSelect={(option) => {
if (!option) return
settings.sounds.setErrors(option.id)
diff --git a/packages/app/src/components/settings-keybinds.tsx b/packages/app/src/components/settings-keybinds.tsx
index 811b34f9b..7bc9b1fd7 100644
--- a/packages/app/src/components/settings-keybinds.tsx
+++ b/packages/app/src/components/settings-keybinds.tsx
@@ -124,13 +124,23 @@ export const SettingsKeybinds: Component = () => {
const out = new Map<string, KeybindMeta>()
out.set(PALETTE_ID, { title: "Command palette", group: "General" })
+ for (const opt of command.catalog) {
+ if (opt.id.startsWith("suggested.")) continue
+ out.set(opt.id, { title: opt.title, group: groupFor(opt.id) })
+ }
+
for (const opt of command.options) {
if (opt.id.startsWith("suggested.")) continue
+ out.set(opt.id, { title: opt.title, group: groupFor(opt.id) })
+ }
- out.set(opt.id, {
- title: opt.title,
- group: groupFor(opt.id),
- })
+ const keybinds = settings.current.keybinds as Record<string, string | undefined> | undefined
+ if (keybinds) {
+ for (const [id, value] of Object.entries(keybinds)) {
+ if (typeof value !== "string") continue
+ if (out.has(id)) continue
+ out.set(id, { title: id, group: groupFor(id) })
+ }
}
return out
@@ -181,11 +191,21 @@ export const SettingsKeybinds: Component = () => {
add(sig, { id: PALETTE_ID, title: "Command palette" })
}
- for (const opt of command.options) {
- if (opt.id.startsWith("suggested.")) continue
- if (!opt.keybind) continue
- for (const sig of signatures(opt.keybind)) {
- add(sig, { id: opt.id, title: opt.title })
+ const valueFor = (id: string) => {
+ const custom = settings.keybinds.get(id)
+ if (typeof custom === "string") return custom
+
+ const live = command.options.find((x) => x.id === id)
+ if (live?.keybind) return live.keybind
+
+ const meta = command.catalog.find((x) => x.id === id)
+ return meta?.keybind
+ }
+
+ for (const id of list().keys()) {
+ if (id === PALETTE_ID) continue
+ for (const sig of signatures(valueFor(id))) {
+ add(sig, { id, title: title(id) })
}
}
diff --git a/packages/app/src/context/command.tsx b/packages/app/src/context/command.tsx
index 7986e7509..1e71801bd 100644
--- a/packages/app/src/context/command.tsx
+++ b/packages/app/src/context/command.tsx
@@ -1,7 +1,9 @@
-import { createMemo, createSignal, onCleanup, onMount, type Accessor } from "solid-js"
+import { createEffect, createMemo, createSignal, onCleanup, onMount, type Accessor } from "solid-js"
+import { createStore } from "solid-js/store"
import { createSimpleContext } from "@opencode-ai/ui/context"
import { useDialog } from "@opencode-ai/ui/context/dialog"
import { useSettings } from "@/context/settings"
+import { Persist, persisted } from "@/utils/persist"
const IS_MAC = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform)
@@ -44,6 +46,14 @@ export interface CommandOption {
onHighlight?: () => (() => void) | void
}
+export type CommandCatalogItem = {
+ title: string
+ description?: string
+ category?: string
+ keybind?: KeybindConfig
+ slash?: string
+}
+
export function parseKeybind(config: string): Keybind[] {
if (!config || config === "none") return []
@@ -148,6 +158,11 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex
const [registrations, setRegistrations] = createSignal<Accessor<CommandOption[]>[]>([])
const [suspendCount, setSuspendCount] = createSignal(0)
+ const [catalog, setCatalog, _, catalogReady] = persisted(
+ Persist.global("command.catalog.v1"),
+ createStore<Record<string, CommandCatalogItem>>({}),
+ )
+
const bind = (id: string, def: KeybindConfig | undefined) => {
const custom = settings.keybinds.get(actionId(id))
const config = custom ?? def
@@ -155,7 +170,7 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex
return config
}
- const options = createMemo(() => {
+ const registered = createMemo(() => {
const seen = new Set<string>()
const all: CommandOption[] = []
@@ -167,7 +182,28 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex
}
}
- const resolved = all.map((opt) => ({
+ return all
+ })
+
+ createEffect(() => {
+ if (!catalogReady()) return
+
+ for (const opt of registered()) {
+ const id = actionId(opt.id)
+ setCatalog(id, {
+ title: opt.title,
+ description: opt.description,
+ category: opt.category,
+ keybind: opt.keybind,
+ slash: opt.slash,
+ })
+ }
+ })
+
+ const catalogOptions = createMemo(() => Object.entries(catalog).map(([id, meta]) => ({ id, ...meta })))
+
+ const options = createMemo(() => {
+ const resolved = registered().map((opt) => ({
...opt,
keybind: bind(opt.id, opt.keybind),
}))
@@ -246,15 +282,23 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex
return formatKeybind(settings.keybinds.get(PALETTE_ID) ?? DEFAULT_PALETTE_KEYBIND)
}
- const option = options().find((x) => x.id === id || x.id === SUGGESTED_PREFIX + id)
- if (!option?.keybind) return ""
- return formatKeybind(option.keybind)
+ const base = actionId(id)
+ const option = options().find((x) => actionId(x.id) === base)
+ if (option?.keybind) return formatKeybind(option.keybind)
+
+ const meta = catalog[base]
+ const config = bind(base, meta?.keybind)
+ if (!config) return ""
+ return formatKeybind(config)
},
show: showPalette,
keybinds(enabled: boolean) {
setSuspendCount((count) => count + (enabled ? -1 : 1))
},
suspended,
+ get catalog() {
+ return catalogOptions()
+ },
get options() {
return options()
},