tui: improve keybind handling and app exit cleanup

This commit is contained in:
Dax Raad 2025-09-24 04:30:29 -04:00
parent 887a3336cc
commit 45f90bc4b3
3 changed files with 20 additions and 22 deletions

View file

@ -6,7 +6,8 @@ import type { KeybindsConfig } from "@opencode-ai/sdk"
import { createContext } from "solid-js"
import type { ParsedKey } from "@opentui/core"
import { createStore } from "solid-js/store"
import { useKeyboard } from "@opentui/solid"
import { useKeyboard, useRenderer } from "@opentui/solid"
import { Instance } from "../../../../project/instance"
export function init() {
const sync = useSync()
@ -22,13 +23,19 @@ export function init() {
leader: false,
})
useKeyboard((evt) => {
const renderer = useRenderer()
useKeyboard(async (evt) => {
if (result.match("leader", evt)) {
setStore("leader", !store.leader)
setTimeout(() => {
setStore("leader", false)
}, 2000)
}
if (result.match("app_exit", evt)) {
await Instance.disposeAll()
renderer.destroy()
}
})
const result = {

View file

@ -27,6 +27,7 @@ import { useKeyboard, type BoxProps, type JSX } from "@opentui/solid"
import { useSDK } from "./context/sdk"
import { useCommandDialog } from "./component/dialog-command"
import { Shimmer } from "./ui/shimmer"
import { useKeybind } from "./context/keybind"
export function Session() {
const route = useRouteData("session")
@ -39,9 +40,10 @@ export function Session() {
createEffect(() => sync.session.sync(route.sessionID))
const sdk = useSDK()
const keybind = useKeybind()
useKeyboard((evt) => {
if (evt.name === "pageup") scroll.scrollBy(-scroll.height / 2)
if (evt.name === "pagedown") scroll.scrollBy(scroll.height / 2)
if (keybind.match("messages_page_up", evt)) scroll.scrollBy(-scroll.height / 2)
if (keybind.match("messages_page_down", evt)) scroll.scrollBy(scroll.height / 2)
if (evt.name === "escape")
sdk.session.abort({
path: {

View file

@ -13,12 +13,10 @@ import { SyncProvider } from "./context/sync"
import { LocalProvider, useLocal } from "./context/local"
import { DialogModel } from "./component/dialog-model"
import { Session } from "./session"
import { Instance } from "../../../project/instance"
import { EventLoop } from "../../../util/eventloop"
import { CommandProvider, useCommandDialog } from "./component/dialog-command"
import { DialogAgent } from "./component/dialog-agent"
import { DialogSessionList } from "./component/dialog-session-list"
import { KeybindProvider } from "./context/keybind"
import { KeybindProvider, useKeybind } from "./context/keybind"
export const TuiCommand = cmd({
command: "$0 [project]",
@ -67,15 +65,6 @@ export const TuiCommand = cmd({
handler: async () => {
await render(
() => {
const renderer = useRenderer()
useKeyboard(async (evt) => {
if (!evt.name) return
if (evt.name === "c" && evt.ctrl) {
await Instance.disposeAll()
renderer.destroy()
await EventLoop.wait()
}
})
return (
<RouteProvider>
<ThemeProvider>
@ -113,12 +102,16 @@ function App() {
const dialog = useDialog()
const local = useLocal()
const command = useCommandDialog()
const keybind = useKeybind()
useKeyboard(async (evt) => {
if (evt.name === "tab") {
local.agent.move(evt.shift ? -1 : 1)
if (keybind.match("agent_cycle", evt)) {
local.agent.move(1)
return
}
if (keybind.match("agent_cycle_reverse", evt)) {
local.agent.move(-1)
}
if (evt.meta && evt.name === "t") {
renderer.toggleDebugOverlay()
@ -129,10 +122,6 @@ function App() {
renderer.console.toggle()
return
}
if (evt.meta && evt.name === "m") {
dialog.replace(() => <DialogModel />)
return
}
})
createEffect(() => {