keep session navigation active in prompt modes (#29464)
This commit is contained in:
parent
86dc66eae9
commit
94f2ed1b84
3 changed files with 112 additions and 9 deletions
|
|
@ -79,8 +79,7 @@ import {
|
||||||
import type { EventSource } from "./context/sdk"
|
import type { EventSource } from "./context/sdk"
|
||||||
import { DialogVariant } from "./component/dialog-variant"
|
import { DialogVariant } from "./component/dialog-variant"
|
||||||
|
|
||||||
const appBindingCommands = [
|
const appGlobalBindingCommands = [
|
||||||
"command.palette.show",
|
|
||||||
"session.list",
|
"session.list",
|
||||||
"session.new",
|
"session.new",
|
||||||
"session.quick_switch.1",
|
"session.quick_switch.1",
|
||||||
|
|
@ -92,6 +91,10 @@ const appBindingCommands = [
|
||||||
"session.quick_switch.7",
|
"session.quick_switch.7",
|
||||||
"session.quick_switch.8",
|
"session.quick_switch.8",
|
||||||
"session.quick_switch.9",
|
"session.quick_switch.9",
|
||||||
|
] as const
|
||||||
|
|
||||||
|
const appBindingCommands = [
|
||||||
|
"command.palette.show",
|
||||||
"model.list",
|
"model.list",
|
||||||
"model.cycle_recent",
|
"model.cycle_recent",
|
||||||
"model.cycle_recent_reverse",
|
"model.cycle_recent_reverse",
|
||||||
|
|
@ -929,6 +932,10 @@ function App(props: { onSnapshot?: () => Promise<string[]> }) {
|
||||||
bindings: tuiConfig.keybinds.gather("app", appBindingCommands),
|
bindings: tuiConfig.keybinds.gather("app", appBindingCommands),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
useBindings(() => ({
|
||||||
|
bindings: tuiConfig.keybinds.gather("app.global", appGlobalBindingCommands),
|
||||||
|
}))
|
||||||
|
|
||||||
useBindings(() => ({
|
useBindings(() => ({
|
||||||
mode: OPENCODE_BASE_MODE,
|
mode: OPENCODE_BASE_MODE,
|
||||||
enabled: () => {
|
enabled: () => {
|
||||||
|
|
|
||||||
|
|
@ -134,12 +134,6 @@ const sessionBindingCommands = [
|
||||||
"session.toggle.actions",
|
"session.toggle.actions",
|
||||||
"session.toggle.scrollbar",
|
"session.toggle.scrollbar",
|
||||||
"session.toggle.generic_tool_output",
|
"session.toggle.generic_tool_output",
|
||||||
"session.page.up",
|
|
||||||
"session.page.down",
|
|
||||||
"session.line.up",
|
|
||||||
"session.line.down",
|
|
||||||
"session.half.page.up",
|
|
||||||
"session.half.page.down",
|
|
||||||
"session.first",
|
"session.first",
|
||||||
"session.last",
|
"session.last",
|
||||||
"session.messages_last_user",
|
"session.messages_last_user",
|
||||||
|
|
@ -154,6 +148,17 @@ const sessionBindingCommands = [
|
||||||
"session.child.previous",
|
"session.child.previous",
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
|
const sessionGlobalBindingCommands = [
|
||||||
|
"session.page.up",
|
||||||
|
"session.page.down",
|
||||||
|
"session.line.up",
|
||||||
|
"session.line.down",
|
||||||
|
"session.half.page.up",
|
||||||
|
"session.half.page.down",
|
||||||
|
] as const
|
||||||
|
|
||||||
|
const sessionGlobalUnfocusedBindingCommands = ["session.first", "session.last"] as const
|
||||||
|
|
||||||
const context = createContext<{
|
const context = createContext<{
|
||||||
width: number
|
width: number
|
||||||
sessionID: string
|
sessionID: string
|
||||||
|
|
@ -1067,6 +1072,15 @@ export function Session() {
|
||||||
commands: sessionCommands(),
|
commands: sessionCommands(),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
useBindings(() => ({
|
||||||
|
bindings: tuiConfig.keybinds.gather("session.global", sessionGlobalBindingCommands),
|
||||||
|
}))
|
||||||
|
|
||||||
|
useBindings(() => ({
|
||||||
|
enabled: () => renderer.currentFocusedEditor === null,
|
||||||
|
bindings: tuiConfig.keybinds.gather("session.global.unfocused", sessionGlobalUnfocusedBindingCommands),
|
||||||
|
}))
|
||||||
|
|
||||||
useBindings(() => ({
|
useBindings(() => ({
|
||||||
mode: OPENCODE_BASE_MODE,
|
mode: OPENCODE_BASE_MODE,
|
||||||
bindings: tuiConfig.keybinds.gather("session", sessionBindingCommands),
|
bindings: tuiConfig.keybinds.gather("session", sessionBindingCommands),
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,12 @@ import { testRender, useRenderer } from "@opentui/solid"
|
||||||
import { expect, test } from "bun:test"
|
import { expect, test } from "bun:test"
|
||||||
import { onCleanup } from "solid-js"
|
import { onCleanup } from "solid-js"
|
||||||
import { createTuiResolvedConfig } from "../../fixture/tui-runtime"
|
import { createTuiResolvedConfig } from "../../fixture/tui-runtime"
|
||||||
import { OpencodeKeymapProvider, registerOpencodeKeymap } from "@/cli/cmd/tui/keymap"
|
import {
|
||||||
|
getOpencodeModeStack,
|
||||||
|
OPENCODE_BASE_MODE,
|
||||||
|
OpencodeKeymapProvider,
|
||||||
|
registerOpencodeKeymap,
|
||||||
|
} from "@/cli/cmd/tui/keymap"
|
||||||
|
|
||||||
test("legacy page key aliases compile as page keys", async () => {
|
test("legacy page key aliases compile as page keys", async () => {
|
||||||
const sequences: Record<string, string[][]> = {}
|
const sequences: Record<string, string[][]> = {}
|
||||||
|
|
@ -52,3 +57,80 @@ test("legacy page key aliases compile as page keys", async () => {
|
||||||
app.renderer.destroy()
|
app.renderer.destroy()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("mode-less bindings stay active when opencode mode changes", async () => {
|
||||||
|
const counts: Record<string, Record<string, number>> = {}
|
||||||
|
|
||||||
|
function Harness() {
|
||||||
|
const renderer = useRenderer()
|
||||||
|
const keymap = createDefaultOpenTuiKeymap(renderer)
|
||||||
|
const config = createTuiResolvedConfig()
|
||||||
|
const offKeymap = registerOpencodeKeymap(keymap, renderer, config)
|
||||||
|
const offGlobal = keymap.registerLayer({
|
||||||
|
commands: [
|
||||||
|
{ name: "session.list", run() {} },
|
||||||
|
{ name: "session.new", run() {} },
|
||||||
|
{ name: "session.page.up", run() {} },
|
||||||
|
{ name: "session.first", run() {} },
|
||||||
|
],
|
||||||
|
bindings: config.keybinds.gather("test.global", [
|
||||||
|
"session.list",
|
||||||
|
"session.new",
|
||||||
|
"session.page.up",
|
||||||
|
"session.first",
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
const offBase = keymap.registerLayer({
|
||||||
|
mode: OPENCODE_BASE_MODE,
|
||||||
|
commands: [{ name: "model.list", run() {} }],
|
||||||
|
bindings: config.keybinds.gather("test.base", ["model.list"]),
|
||||||
|
})
|
||||||
|
const activeCounts = () =>
|
||||||
|
Object.fromEntries(
|
||||||
|
Array.from(
|
||||||
|
keymap.getCommandBindings({
|
||||||
|
visibility: "active",
|
||||||
|
commands: ["session.list", "session.new", "session.page.up", "session.first", "model.list"],
|
||||||
|
}),
|
||||||
|
([command, bindings]) => [command, bindings.length],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
counts.base = activeCounts()
|
||||||
|
const popQuestion = getOpencodeModeStack(keymap).push("question")
|
||||||
|
counts.question = activeCounts()
|
||||||
|
popQuestion()
|
||||||
|
const popAutocomplete = getOpencodeModeStack(keymap).push("autocomplete")
|
||||||
|
counts.autocomplete = activeCounts()
|
||||||
|
popAutocomplete()
|
||||||
|
|
||||||
|
onCleanup(() => {
|
||||||
|
offBase()
|
||||||
|
offGlobal()
|
||||||
|
offKeymap()
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<OpencodeKeymapProvider keymap={keymap}>
|
||||||
|
<box />
|
||||||
|
</OpencodeKeymapProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const app = await testRender(() => <Harness />)
|
||||||
|
try {
|
||||||
|
expect(counts).toEqual({
|
||||||
|
base: { "session.list": 1, "session.new": 1, "session.page.up": 2, "session.first": 2, "model.list": 1 },
|
||||||
|
question: { "session.list": 1, "session.new": 1, "session.page.up": 2, "session.first": 2, "model.list": 0 },
|
||||||
|
autocomplete: {
|
||||||
|
"session.list": 1,
|
||||||
|
"session.new": 1,
|
||||||
|
"session.page.up": 2,
|
||||||
|
"session.first": 2,
|
||||||
|
"model.list": 0,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
app.renderer.destroy()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue