Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
281e58b
feat: add keybind support for custom slash commands
ariane-emory Dec 17, 2025
326718d
fix: handle undefined values in command keybind parsing
ariane-emory Dec 17, 2025
ac4ba7f
feat: preserve prompt text as command arguments in keybind execution
ariane-emory Dec 18, 2025
db95d88
Merge dev branch, resolving types.gen.ts conflict
ariane-emory Dec 18, 2025
0db39ae
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 19, 2025
271fa87
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 19, 2025
6fb751c
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 20, 2025
576aedf
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 20, 2025
7a283f5
fix: remove unused sdk variable in app.tsx
ariane-emory Dec 21, 2025
1a8503d
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 21, 2025
6945498
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 21, 2025
f125cdd
Merge branch 'dev' into feat/revise-keybindable-commands
ariane-emory Dec 24, 2025
69aaecc
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 24, 2025
1f55399
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 25, 2025
5e75dce
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 25, 2025
87fa148
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 25, 2025
894d6b4
Merge branch 'feat/keybindable-commands' of github.com:ariane-emory/o…
ariane-emory Dec 25, 2025
0c74d2e
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 25, 2025
c202342
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 26, 2025
d84172f
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 27, 2025
4e24e58
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 27, 2025
0f15eaf
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 27, 2025
3c88bd0
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 28, 2025
83bd58c
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 54 additions & 1 deletion packages/opencode/src/cli/cmd/tui/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { DialogHelp } from "./ui/dialog-help"
import { CommandProvider, useCommandDialog } from "@tui/component/dialog-command"
import { DialogAgent } from "@tui/component/dialog-agent"
import { DialogSessionList } from "@tui/component/dialog-session-list"
import { KeybindProvider } from "@tui/context/keybind"
import { KeybindProvider, useKeybind } from "@tui/context/keybind"
import { ThemeProvider, useTheme } from "@tui/context/theme"
import { Home } from "@tui/routes/home"
import { Session } from "@tui/routes/session"
Expand All @@ -35,6 +35,7 @@ import { Provider } from "@/provider/provider"
import { ArgsProvider, useArgs, type Args } from "./context/args"
import open from "open"
import { PromptRefProvider, usePromptRef } from "./context/prompt"
import { Keybind } from "@/util/keybind"

async function getTerminalBackgroundColor(): Promise<"dark" | "light"> {
// can't set raw mode if not a TTY
Expand Down Expand Up @@ -178,6 +179,7 @@ function App() {
const sync = useSync()
const exit = useExit()
const promptRef = usePromptRef()
const keybind = useKeybind()

// Wire up console copy-to-clipboard via opentui's onCopySelection callback
renderer.console.onCopySelection = async (text: string) => {
Expand Down Expand Up @@ -499,6 +501,57 @@ function App() {
},
])

// Handle custom command keybinds
useKeyboard((evt) => {
if (command.suspended()) return
if (dialog.stack.length > 0) return
if (evt.defaultPrevented) return

const keybinds = sync.data.config.keybinds ?? {}
for (const [key, value] of Object.entries(keybinds)) {
if (!key.startsWith("/")) continue
if (!value) continue

const commandName = key.slice(1)
const commandKeybinds = Keybind.parse(value)
const parsed = keybind.parse(evt)

for (const kb of commandKeybinds) {
if (Keybind.match(kb, parsed)) {
evt.preventDefault()

// Find the command to verify it exists
const cmd = sync.data.command.find((c) => c.name === commandName)
if (!cmd) {
toast.show({
variant: "error",
message: `Command not found: ${commandName}`,
duration: 3000,
})
return
}

// Preserve existing prompt text as command arguments
const current = promptRef.current
if (current) {
const existingInput = current.current.input.trim()
const commandInput = existingInput
? `/${commandName} ${existingInput}`
: `/${commandName}`

current.set({
input: commandInput,
parts: current.current.parts,
})
current.submit()
}

return
}
}
}
})

createEffect(() => {
const currentModel = local.model.current()
if (!currentModel) return
Expand Down
2 changes: 1 addition & 1 deletion packages/opencode/src/cli/cmd/tui/context/keybind.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const { use: useKeybind, provider: KeybindProvider } = createSimpleContex
const keybinds = createMemo(() => {
return pipe(
sync.data.config.keybinds ?? {},
mapValues((value) => Keybind.parse(value)),
mapValues((value) => (value ? Keybind.parse(value) : [])),
)
})
const [store, setStore] = createStore({
Expand Down
2 changes: 1 addition & 1 deletion packages/opencode/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ export namespace Config {
terminal_title_toggle: z.string().optional().default("none").describe("Toggle terminal title"),
tips_toggle: z.string().optional().default("<leader>h").describe("Toggle tips on home screen"),
})
.strict()
.catchall(z.string())
.meta({
ref: "KeybindsConfig",
})
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/js/src/v2/gen/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,7 @@ export type KeybindsConfig = {
* Toggle tips on home screen
*/
tips_toggle?: string
[key: string]: string | undefined
}

/**
Expand Down