Compare commits

...

2 Commits

Author SHA1 Message Date
Kit Langton
c1ef03d53d fix(tui): suspend agent tab keybinds in shell mode 2026-03-16 20:59:12 -04:00
Kit Langton
c40b478756 fix(tui): keep tab behavior in shell mode 2026-03-16 20:49:08 -04:00
3 changed files with 62 additions and 0 deletions

View File

@@ -33,6 +33,7 @@ import { DialogAlert } from "../../ui/dialog-alert"
import { useToast } from "../../ui/toast"
import { useKV } from "../../context/kv"
import { useTextareaKeybindings } from "../textarea-keybindings"
import { shellPassthrough } from "./key"
import { DialogSkill } from "../dialog-skill"
export type PromptProps = {
@@ -97,6 +98,21 @@ export function Prompt(props: PromptProps) {
const pasteStyleId = syntax().getStyleId("extmark.paste")!
let promptPartTypeId = 0
createEffect(
on(
() => store.mode,
(mode, prev) => {
if (prev === "shell") command.keybinds(true)
if (mode === "shell") command.keybinds(false)
},
{ defer: true },
),
)
onCleanup(() => {
if (store.mode === "shell") command.keybinds(true)
})
sdk.event.on(TuiEvent.PromptAppend.type, (evt) => {
if (!input || input.isDestroyed) return
input.insertText(evt.properties.text)
@@ -894,6 +910,10 @@ export function Prompt(props: PromptProps) {
return
}
if (store.mode === "shell") {
if (shellPassthrough(keybind, e, store.mode)) {
e.stopPropagation()
return
}
if ((e.name === "backspace" && input.visualCursor.offset === 0) || e.name === "escape") {
setStore("mode", "normal")
e.preventDefault()

View File

@@ -0,0 +1,16 @@
import type { KeybindKey } from "@/cli/cmd/tui/context/keybind"
type Mode = "normal" | "shell"
type Key = {
readonly name?: string
readonly shift?: boolean
}
export function shellPassthrough<E extends Key>(
keybind: { readonly match: (key: KeybindKey, evt: E) => boolean | undefined },
evt: E,
mode: Mode,
) {
return mode === "shell" && (keybind.match("agent_cycle", evt) || keybind.match("agent_cycle_reverse", evt))
}

View File

@@ -0,0 +1,26 @@
import { describe, expect, test } from "bun:test"
import { shellPassthrough } from "../../../src/cli/cmd/tui/component/prompt/key"
const key = (name: string, extra: { readonly shift?: boolean } = {}) => ({
name,
shift: false,
...extra,
})
describe("shellPassthrough", () => {
test("allows tab agent-cycle bindings to pass through in shell mode", () => {
const match = (target: string, evt: { readonly name?: string }) => target === "agent_cycle" && evt.name === "tab"
expect(shellPassthrough({ match }, key("tab"), "shell")).toBe(true)
})
test("allows reverse agent-cycle bindings to pass through in shell mode", () => {
const match = (target: string, evt: { readonly name?: string; readonly shift?: boolean }) =>
target === "agent_cycle_reverse" && evt.name === "tab" && evt.shift
expect(shellPassthrough({ match }, key("tab", { shift: true }), "shell")).toBe(true)
})
test("does not bypass agent-cycle outside shell mode", () => {
const match = (target: string, evt: { readonly name?: string }) => target === "agent_cycle" && evt.name === "tab"
expect(shellPassthrough({ match }, key("tab"), "normal")).toBe(false)
})
})