Compare commits

..

1 Commits

Author SHA1 Message Date
Kit Langton 8cb7f49183 fix(tui): clarify saved permission copy 2026-08-07 20:33:54 +00:00
6 changed files with 9 additions and 73 deletions
+2 -3
View File
@@ -18,7 +18,6 @@ const BindingObject = Schema.StructWithRest(
Schema.Struct({
key: Schema.Union([Schema.String, KeyStroke]),
event: Schema.optional(Schema.Literals(["press", "release"])),
source: Schema.optional(Schema.Literals(["raw", "kitty"])),
preventDefault: Schema.optional(Schema.Boolean),
fallthrough: Schema.optional(Schema.Boolean),
}),
@@ -163,7 +162,7 @@ export const Definitions = {
display_thinking: keybind("none", "Toggle thinking blocks visibility"),
prompt_submit: keybind("none", "Submit prompt"),
prompt_queue: keybind({ key: "alt+return", source: "kitty" }, "Queue prompt"),
prompt_queue: keybind("alt+return", "Queue prompt"),
prompt_editor_context_clear: keybind("none", "Clear editor context"),
prompt_skills: keybind("none", "Open skill selector"),
prompt_stash: keybind("none", "Stash prompt"),
@@ -173,7 +172,7 @@ export const Definitions = {
input_clear: keybind("ctrl+c", "Clear input field"),
input_paste: keybind({ key: "ctrl+v", preventDefault: false }, "Paste from clipboard"),
input_submit: keybind("return", "Submit input"),
input_newline: keybind("shift+return,ctrl+return,alt+return,ctrl+j", "Insert newline in input"),
input_newline: keybind("shift+return,ctrl+return,ctrl+j", "Insert newline in input"),
input_move_left: keybind("left,ctrl+b", "Move cursor left in input"),
input_move_right: keybind("right,ctrl+f", "Move cursor right in input"),
input_move_up: keybind("up", "Move cursor up in input"),
-26
View File
@@ -66,32 +66,6 @@ function Provider(props: ParentProps<{ config?: KeymapConfig }>) {
}
}
const dispose = [
keymap.registerBindingFields({
source: (source, context) => {
if (source !== "raw" && source !== "kitty") throw new Error(`Invalid key source: ${String(source)}`)
context.attr("source", source)
},
}),
keymap.appendBindingTransformer((binding, context) => {
const source = binding.source
if (source !== "raw" && source !== "kitty") return
const command = binding.cmd
if (!command) return
context.add({
...binding,
cmd: (commandContext) => {
if (commandContext.event.source !== source) return false
if (typeof command === "function") return command(commandContext)
return commandContext.keymap.runCommand(command, {
event: commandContext.event,
focused: commandContext.focused,
target: commandContext.target,
payload: commandContext.payload,
})
},
})
context.skipOriginal()
}),
registerCommaBindings(keymap),
keymap.appendBindingExpander((context) => {
const key = Object.entries({ enter: "return", esc: "escape", pgdown: "pagedown", pgup: "pageup" }).reduce(
+3 -3
View File
@@ -154,14 +154,14 @@ function wildcardDirectory(value: string) {
export function permissionAlwaysLines(input: { action: string; save?: ReadonlyArray<string> }): string[] {
const save = input.save ?? []
if (save.length === 1 && save[0] === "*") {
return [`This will allow ${input.action} until OpenCode is restarted.`]
return [`This will always allow ${input.action} for this project.`]
}
return ["This will allow the following patterns until OpenCode is restarted.", ...save.map((item) => `- ${item}`)]
return ["This will always allow the following patterns for this project.", ...save.map((item) => `- ${item}`)]
}
export function permissionOptionLabel(option: "once" | "always" | "reject" | "confirm" | "cancel") {
if (option === "once") return "Allow once"
if (option === "always") return "Allow always"
if (option === "always") return "Always allow"
if (option === "reject") return "Reject"
if (option === "confirm") return "Confirm"
return "Cancel"
-37
View File
@@ -1,6 +1,5 @@
/** @jsxImportSource @opentui/solid */
import { testRender } from "@opentui/solid"
import type { TextareaRenderable } from "@opentui/core"
import { expect, test } from "bun:test"
import { ConfigProvider } from "../src/config"
import { Keymap } from "../src/context/keymap"
@@ -140,39 +139,3 @@ test("global commands stay reachable when the mode changes", async () => {
app.renderer.destroy()
}
})
test("queues explicit option enter and keeps raw option enter as newline", async () => {
async function exercise(kittyKeyboard: boolean) {
let area: TextareaRenderable | undefined
let queued = 0
function Harness() {
Keymap.createLayer(() => ({
priority: 1,
commands: [{ id: "prompt.queue", run: () => void queued++ }],
}))
return <textarea ref={(value) => (area = value)} focused />
}
const app = await testRender(
() => (
<ConfigProvider config={createTuiResolvedConfig()}>
<Keymap.Provider>
<Harness />
</Keymap.Provider>
</ConfigProvider>
),
{ kittyKeyboard },
)
try {
app.mockInput.pressEnter({ meta: true })
await app.renderOnce()
return { queued, text: area?.plainText }
} finally {
app.renderer.destroy()
}
}
expect(await exercise(true)).toEqual({ queued: 1, text: "" })
expect(await exercise(false)).toEqual({ queued: 0, text: "\n" })
})
@@ -183,11 +183,11 @@ describe("run permission shared", () => {
test("formats always-allow copy for wildcard and explicit patterns", () => {
expect(permissionAlwaysLines(req({ action: "bash", save: ["*"] }))).toEqual([
"This will allow bash until OpenCode is restarted.",
"This will always allow bash for this project.",
])
expect(permissionAlwaysLines(req({ save: ["src/**/*.ts", "src/**/*.tsx"] }))).toEqual([
"This will allow the following patterns until OpenCode is restarted.",
"This will always allow the following patterns for this project.",
"- src/**/*.ts",
"- src/**/*.tsx",
])
+2 -2
View File
@@ -82,8 +82,8 @@ describe("run runtime boot", () => {
expect(result.keybinds.get("prompt.history.next")?.[0]?.key).toBe("down")
expect(result.keybinds.get("prompt.clear")?.[0]?.key).toBe("ctrl+c")
expect(result.keybinds.get("input.submit")?.[0]?.key).toBe("return")
expect(result.keybinds.get("input.newline")?.[0]?.key).toBe("shift+return,ctrl+return,alt+return,ctrl+j")
expect(result.keybinds.get("prompt.queue")?.[0]).toMatchObject({ key: "alt+return", source: "kitty" })
expect(result.keybinds.get("input.newline")?.[0]?.key).toBe("shift+return,ctrl+return,ctrl+j")
expect(result.keybinds.get("prompt.queue")?.[0]?.key).toBe("alt+return")
})
test("preserves disabled leader from resolved tui config", async () => {