import { useDialog } from "@tui/ui/dialog" import { DialogSelect, type DialogSelectOption, type DialogSelectRef } from "@tui/ui/dialog-select" import { createContext, createMemo, createSignal, onCleanup, useContext, type Accessor, type ParentProps, } from "solid-js" import { useKeyboard } from "@opentui/solid" import { useKeybind } from "@tui/context/keybind" import type { KeybindsConfig } from "@opencode-ai/sdk/v2" type Context = ReturnType const ctx = createContext() export type CommandOption = DialogSelectOption & { keybind?: keyof KeybindsConfig suggested?: boolean } function init() { const [registrations, setRegistrations] = createSignal[]>([]) const [suspendCount, setSuspendCount] = createSignal(0) const dialog = useDialog() const keybind = useKeybind() const options = createMemo(() => { const all = registrations().flatMap((x) => x()) const suggested = all.filter((x) => x.suggested) return [ ...suggested.map((x) => ({ ...x, category: "Suggested", value: "suggested." + x.value, })), ...all, ].map((x) => ({ ...x, footer: x.keybind ? keybind.print(x.keybind) : undefined, })) }) const suspended = () => suspendCount() > 0 useKeyboard((evt) => { if (suspended()) return if (dialog.stack.length > 0) return for (const option of options()) { if (option.keybind && keybind.match(option.keybind, evt)) { evt.preventDefault() option.onSelect?.(dialog) return } } }) const result = { trigger(name: string, source?: "prompt") { for (const option of options()) { if (option.value === name) { option.onSelect?.(dialog, source) return } } }, keybinds(enabled: boolean) { setSuspendCount((count) => count + (enabled ? -1 : 1)) }, suspended, show() { dialog.replace(() => ) }, register(cb: () => CommandOption[]) { const results = createMemo(cb) setRegistrations((arr) => [results, ...arr]) onCleanup(() => { setRegistrations((arr) => arr.filter((x) => x !== results)) }) }, get options() { return options() }, } return result } export function useCommandDialog() { const value = useContext(ctx) if (!value) { throw new Error("useCommandDialog must be used within a CommandProvider") } return value } export function CommandProvider(props: ParentProps) { const value = init() const dialog = useDialog() const keybind = useKeybind() useKeyboard((evt) => { if (value.suspended()) return if (dialog.stack.length > 0) return if (evt.defaultPrevented) return if (keybind.match("command_list", evt)) { evt.preventDefault() dialog.replace(() => ) return } }) return {props.children} } function DialogCommand(props: { options: CommandOption[] }) { let ref: DialogSelectRef return ( (ref = r)} title="Commands" options={props.options.filter((x) => !ref?.filter || !x.value.startsWith("suggested."))} /> ) }