summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorSebastian Herrlinger <[email protected]>2025-12-11 17:20:04 +0100
committerSebastian Herrlinger <[email protected]>2025-12-11 17:23:47 +0100
commite271852bc3c6e3e4ee04a2245a7bc2c8f8b7f30a (patch)
treefe60fb286b13ccbdd3433a50793e3456b4120757
parent4e02704f17be406a7cec8b5a815582a08a2043cf (diff)
downloadopencode-e271852bc3c6e3e4ee04a2245a7bc2c8f8b7f30a.tar.gz
opencode-e271852bc3c6e3e4ee04a2245a7bc2c8f8b7f30a.zip
allow custom mappings for all textarea actions via config
-rw-r--r--bun.lock42
-rw-r--r--packages/opencode/package.json4
-rw-r--r--packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx72
-rw-r--r--packages/opencode/src/config/config.ts63
-rw-r--r--packages/web/src/content/docs/keybinds.mdx40
5 files changed, 189 insertions, 32 deletions
diff --git a/bun.lock b/bun.lock
index e775f2df8..faf3f4058 100644
--- a/bun.lock
+++ b/bun.lock
@@ -243,8 +243,8 @@
"@opencode-ai/sdk": "workspace:*",
"@opencode-ai/util": "workspace:*",
"@openrouter/ai-sdk-provider": "1.5.2",
- "@opentui/core": "0.1.60",
- "@opentui/solid": "0.1.60",
+ "@opentui/core": "0.0.0-20251211-4403a69a",
+ "@opentui/solid": "0.0.0-20251211-4403a69a",
"@parcel/watcher": "2.5.1",
"@pierre/precision-diffs": "catalog:",
"@solid-primitives/event-bus": "1.1.2",
@@ -1148,21 +1148,21 @@
"@opentelemetry/api": ["@opentelemetry/[email protected]", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
- "@opentui/core": ["@opentui/[email protected]", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.60", "@opentui/core-darwin-x64": "0.1.60", "@opentui/core-linux-arm64": "0.1.60", "@opentui/core-linux-x64": "0.1.60", "@opentui/core-win32-arm64": "0.1.60", "@opentui/core-win32-x64": "0.1.60", "bun-webgpu": "0.1.4", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-28jphd0AJo48uvEuKXcT9pJhgAu8I2rEJhPt25cc5ipJ2iw/eDk1uoxrbID80MPDqgOEzN21vXmzXwCd6ao+hg=="],
+ "@opentui/core": ["@opentui/[email protected]", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.0.0-20251211-4403a69a", "@opentui/core-darwin-x64": "0.0.0-20251211-4403a69a", "@opentui/core-linux-arm64": "0.0.0-20251211-4403a69a", "@opentui/core-linux-x64": "0.0.0-20251211-4403a69a", "@opentui/core-win32-arm64": "0.0.0-20251211-4403a69a", "@opentui/core-win32-x64": "0.0.0-20251211-4403a69a", "bun-webgpu": "0.1.4", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-wTZKcokyU9yiDqyC0Pvf9eRSdT73s4Ynerkit/z8Af++tynqrTlZHZCXK3o42Ff7itCSILmijcTU94n69aEypA=="],
- "@opentui/core-darwin-arm64": ["@opentui/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N4feqnOBDA4O4yocpat5vOiV06HqJVwJGx8rEZE9DiOtl1i+1cPQ1Lx6+zWdLhbrVBJ0ENhb7Azox8sXkm/+5Q=="],
+ "@opentui/core-darwin-arm64": ["@opentui/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-VAYjTa+Eiauy8gETXadD8y0PE6ppnKasDK1X354VoexZiWFR3r7rkL+TfDfk7whhqXDYyT44JDT1QmCAhVXRzQ=="],
- "@opentui/core-darwin-x64": ["@opentui/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-+z3q4WaoIs7ANU8+eTFlvnfCjAS81rk81TOdZm4TJ53Ti3/B+yheWtnV/mLpLLhvZDz2VUVxxRmfDrGMnJb4fQ=="],
+ "@opentui/core-darwin-x64": ["@opentui/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-n9oVMpsojlILj1soORZzZ2Mjh8Zl73ZNcY7ot0iRmOjBDccrjDTsqKfxoGjKNd/xJSphLeu1LYGlcI5O5OczWQ=="],
- "@opentui/core-linux-arm64": ["@opentui/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-/Q65sjqVGB9ygJ6lStI8n1X6RyfmJZC8XofRGEuFiMLiWcWC/xoBtztdL8LAIvHQy42y2+pl9zIiW0fWSQ0wjw=="],
+ "@opentui/core-linux-arm64": ["@opentui/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-vf4eUjPMI4ANitK4MpTGenZFddKgQD/K21aN6cZjusnH3mTEJAoIR7GbNtMdz3qclU43ajpzTID9sAwhshwdVQ=="],
- "@opentui/core-linux-x64": ["@opentui/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-AegF+g7OguIpjZKN+PS55sc3ZFY6fj+fLwfETbSRGw6NqX+aiwpae0Y3gXX1s298Yq5yQEzMXnARTCJTGH4uzg=="],
+ "@opentui/core-linux-x64": ["@opentui/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-61635Up0YvVJ8gZ2eMiL1c8OfA+U6wAzT++LoaurNjbmsUAlKHws6MZdqTLw7aspJJVGsRFbA6d1Y+gXFxbDrQ=="],
- "@opentui/core-win32-arm64": ["@opentui/[email protected]", "", { "os": "win32", "cpu": "arm64" }, "sha512-fbkq8MOZJgT3r9q3JWqsfVxRpQ1SlbmhmvB35BzukXnZBK8eA178wbSadGH6irMDrkSIYye9WYddHI/iXjmgVQ=="],
+ "@opentui/core-win32-arm64": ["@opentui/[email protected]", "", { "os": "win32", "cpu": "arm64" }, "sha512-3lUddTJGKZ6uU388eU79MY//IEbgGENCITetDrrRp7v9L1AxMntE1ihf6HniziwBvKKJcsUfqLiJWcq0WPZw2w=="],
- "@opentui/core-win32-x64": ["@opentui/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-OebCL7f9+CKodBw0G+NvKIcc74bl6/sBEHfb73cACdJDJKh+T3C3Vt9H3kQQ0m1C8wRAqX6rh706OArk1pUb2A=="],
+ "@opentui/core-win32-x64": ["@opentui/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-Xwc1gqYsn8UZNTzNKkigZozAhBNBGbfX2B/I/aSbyqL0h8+XIInOodI0urzJWc0B6aEv/IDiT6Rm3coXFikLIg=="],
- "@opentui/solid": ["@opentui/[email protected]", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.60", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-pn91stzAHNGWaNL6h39q55bq3G1/DLqxKtT3wVsRAV68dHfPpwmqikX1nEJZK8OU84ZTPS9Ly9fz8po2Mot2uQ=="],
+ "@opentui/solid": ["@opentui/[email protected]", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.0.0-20251211-4403a69a", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-vuLppAdd1Qgaqhie3q2TuEr+8udjT4d8uVg5arvCe1AUDVs19I8kvadVCfzGUVmtXgFIOEakbiv6AxDq5v9Zig=="],
"@oslojs/asn1": ["@oslojs/[email protected]", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="],
@@ -4278,6 +4278,10 @@
"openid-client/jose": ["[email protected]", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="],
+ "opentui-spinner/@opentui/core": ["@opentui/[email protected]", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.60", "@opentui/core-darwin-x64": "0.1.60", "@opentui/core-linux-arm64": "0.1.60", "@opentui/core-linux-x64": "0.1.60", "@opentui/core-win32-arm64": "0.1.60", "@opentui/core-win32-x64": "0.1.60", "bun-webgpu": "0.1.4", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-28jphd0AJo48uvEuKXcT9pJhgAu8I2rEJhPt25cc5ipJ2iw/eDk1uoxrbID80MPDqgOEzN21vXmzXwCd6ao+hg=="],
+
+ "opentui-spinner/@opentui/solid": ["@opentui/[email protected]", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.60", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-pn91stzAHNGWaNL6h39q55bq3G1/DLqxKtT3wVsRAV68dHfPpwmqikX1nEJZK8OU84ZTPS9Ly9fz8po2Mot2uQ=="],
+
"p-locate/p-limit": ["[email protected]", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
"parse-bmfont-xml/xml2js": ["[email protected]", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="],
@@ -4854,6 +4858,22 @@
"opencontrol/@modelcontextprotocol/sdk/zod-to-json-schema": ["[email protected]", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g=="],
+ "opentui-spinner/@opentui/core/@opentui/core-darwin-arm64": ["@opentui/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N4feqnOBDA4O4yocpat5vOiV06HqJVwJGx8rEZE9DiOtl1i+1cPQ1Lx6+zWdLhbrVBJ0ENhb7Azox8sXkm/+5Q=="],
+
+ "opentui-spinner/@opentui/core/@opentui/core-darwin-x64": ["@opentui/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-+z3q4WaoIs7ANU8+eTFlvnfCjAS81rk81TOdZm4TJ53Ti3/B+yheWtnV/mLpLLhvZDz2VUVxxRmfDrGMnJb4fQ=="],
+
+ "opentui-spinner/@opentui/core/@opentui/core-linux-arm64": ["@opentui/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-/Q65sjqVGB9ygJ6lStI8n1X6RyfmJZC8XofRGEuFiMLiWcWC/xoBtztdL8LAIvHQy42y2+pl9zIiW0fWSQ0wjw=="],
+
+ "opentui-spinner/@opentui/core/@opentui/core-linux-x64": ["@opentui/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-AegF+g7OguIpjZKN+PS55sc3ZFY6fj+fLwfETbSRGw6NqX+aiwpae0Y3gXX1s298Yq5yQEzMXnARTCJTGH4uzg=="],
+
+ "opentui-spinner/@opentui/core/@opentui/core-win32-arm64": ["@opentui/[email protected]", "", { "os": "win32", "cpu": "arm64" }, "sha512-fbkq8MOZJgT3r9q3JWqsfVxRpQ1SlbmhmvB35BzukXnZBK8eA178wbSadGH6irMDrkSIYye9WYddHI/iXjmgVQ=="],
+
+ "opentui-spinner/@opentui/core/@opentui/core-win32-x64": ["@opentui/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-OebCL7f9+CKodBw0G+NvKIcc74bl6/sBEHfb73cACdJDJKh+T3C3Vt9H3kQQ0m1C8wRAqX6rh706OArk1pUb2A=="],
+
+ "opentui-spinner/@opentui/solid/@babel/core": ["@babel/[email protected]", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="],
+
+ "opentui-spinner/@opentui/solid/babel-preset-solid": ["[email protected]", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.1" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.8" }, "optionalPeers": ["solid-js"] }, "sha512-pCnxWrciluXCeli/dj5PIEHgbNzim3evtTn12snjqqg8QZWJNMjH1AWIp4iG/tbVjqQ72aBEymMSagvmgxubXw=="],
+
"parse-bmfont-xml/xml2js/sax": ["[email protected]", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="],
"pkg-up/find-up/locate-path": ["[email protected]", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="],
@@ -5032,6 +5052,8 @@
"opencontrol/@modelcontextprotocol/sdk/raw-body/http-errors": ["[email protected]", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="],
+ "opentui-spinner/@opentui/solid/@babel/core/semver": ["[email protected]", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
+
"pkg-up/find-up/locate-path/p-locate": ["[email protected]", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="],
"pkg-up/find-up/locate-path/path-exists": ["[email protected]", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="],
diff --git a/packages/opencode/package.json b/packages/opencode/package.json
index ec7365c42..ab08a043f 100644
--- a/packages/opencode/package.json
+++ b/packages/opencode/package.json
@@ -71,8 +71,8 @@
"@opencode-ai/sdk": "workspace:*",
"@opencode-ai/util": "workspace:*",
"@openrouter/ai-sdk-provider": "1.5.2",
- "@opentui/core": "0.1.60",
- "@opentui/solid": "0.1.60",
+ "@opentui/core": "0.0.0-20251211-4403a69a",
+ "@opentui/solid": "0.0.0-20251211-4403a69a",
"@parcel/watcher": "2.5.1",
"@pierre/precision-diffs": "catalog:",
"@solid-primitives/event-bus": "1.1.2",
diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
index fce9917c2..a5b6051ed 100644
--- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
@@ -46,6 +46,60 @@ export type PromptRef = {
const PLACEHOLDERS = ["Fix a TODO in the codebase", "What is the tech stack of this project?", "Fix broken tests"]
+const TEXTAREA_ACTIONS = [
+ "submit",
+ "newline",
+ "move-left",
+ "move-right",
+ "move-up",
+ "move-down",
+ "select-left",
+ "select-right",
+ "select-up",
+ "select-down",
+ "line-home",
+ "line-end",
+ "select-line-home",
+ "select-line-end",
+ "visual-line-home",
+ "visual-line-end",
+ "select-visual-line-home",
+ "select-visual-line-end",
+ "buffer-home",
+ "buffer-end",
+ "select-buffer-home",
+ "select-buffer-end",
+ "delete-line",
+ "delete-to-line-end",
+ "delete-to-line-start",
+ "backspace",
+ "delete",
+ "undo",
+ "redo",
+ "word-forward",
+ "word-backward",
+ "select-word-forward",
+ "select-word-backward",
+ "delete-word-forward",
+ "delete-word-backward",
+] as const
+
+function mapTextareaKeybindings(
+ keybinds: Record<string, { ctrl: boolean; meta: boolean; shift: boolean; leader: boolean; name: string }[]>,
+ action: (typeof TEXTAREA_ACTIONS)[number],
+): KeyBinding[] {
+ const configKey = `input_${action.replace(/-/g, "_")}`
+ const bindings = keybinds[configKey]
+ if (!bindings) return []
+ return bindings.map((binding) => ({
+ name: binding.name,
+ ctrl: binding.ctrl || undefined,
+ meta: binding.meta || undefined,
+ shift: binding.shift || undefined,
+ action,
+ }))
+}
+
export function Prompt(props: PromptProps) {
let input: TextareaRenderable
let anchor: BoxRenderable
@@ -76,26 +130,12 @@ export function Prompt(props: PromptProps) {
}
const textareaKeybindings = createMemo(() => {
- const newlineBindings = keybind.all.input_newline || []
- const submitBindings = keybind.all.input_submit || []
+ const keybinds = keybind.all
return [
{ name: "return", action: "submit" },
{ name: "return", meta: true, action: "newline" },
- ...newlineBindings.map((binding) => ({
- name: binding.name,
- ctrl: binding.ctrl || undefined,
- meta: binding.meta || undefined,
- shift: binding.shift || undefined,
- action: "newline" as const,
- })),
- ...submitBindings.map((binding) => ({
- name: binding.name,
- ctrl: binding.ctrl || undefined,
- meta: binding.meta || undefined,
- shift: binding.shift || undefined,
- action: "submit" as const,
- })),
+ ...TEXTAREA_ACTIONS.flatMap((action) => mapTextareaKeybindings(keybinds, action)),
] satisfies KeyBinding[]
})
diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts
index 34e3eea79..85f5b4409 100644
--- a/packages/opencode/src/config/config.ts
+++ b/packages/opencode/src/config/config.ts
@@ -466,7 +466,68 @@ export namespace Config {
input_clear: z.string().optional().default("ctrl+c").describe("Clear input field"),
input_paste: z.string().optional().default("ctrl+v").describe("Paste from clipboard"),
input_submit: z.string().optional().default("return").describe("Submit input"),
- input_newline: z.string().optional().default("shift+return,ctrl+j").describe("Insert newline in input"),
+ input_newline: z
+ .string()
+ .optional()
+ .default("shift+return,ctrl+return,alt+return,ctrl+j")
+ .describe("Insert newline in input"),
+ input_move_left: z.string().optional().default("left,ctrl+b").describe("Move cursor left in input"),
+ input_move_right: z.string().optional().default("right,ctrl+f").describe("Move cursor right in input"),
+ input_move_up: z.string().optional().default("up").describe("Move cursor up in input"),
+ input_move_down: z.string().optional().default("down").describe("Move cursor down in input"),
+ input_select_left: z.string().optional().default("shift+left").describe("Select left in input"),
+ input_select_right: z.string().optional().default("shift+right").describe("Select right in input"),
+ input_select_up: z.string().optional().default("shift+up").describe("Select up in input"),
+ input_select_down: z.string().optional().default("shift+down").describe("Select down in input"),
+ input_line_home: z.string().optional().default("ctrl+a").describe("Move to start of line in input"),
+ input_line_end: z.string().optional().default("ctrl+e").describe("Move to end of line in input"),
+ input_select_line_home: z.string().optional().default("none").describe("Select to start of line in input"),
+ input_select_line_end: z.string().optional().default("none").describe("Select to end of line in input"),
+ input_visual_line_home: z.string().optional().default("none").describe("Move to start of visual line in input"),
+ input_visual_line_end: z.string().optional().default("none").describe("Move to end of visual line in input"),
+ input_select_visual_line_home: z
+ .string()
+ .optional()
+ .default("none")
+ .describe("Select to start of visual line in input"),
+ input_select_visual_line_end: z
+ .string()
+ .optional()
+ .default("none")
+ .describe("Select to end of visual line in input"),
+ input_buffer_home: z.string().optional().default("home").describe("Move to start of buffer in input"),
+ input_buffer_end: z.string().optional().default("end").describe("Move to end of buffer in input"),
+ input_select_buffer_home: z
+ .string()
+ .optional()
+ .default("shift+home")
+ .describe("Select to start of buffer in input"),
+ input_select_buffer_end: z.string().optional().default("shift+end").describe("Select to end of buffer in input"),
+ input_delete_line: z.string().optional().default("alt+d").describe("Delete line in input"),
+ input_delete_to_line_end: z.string().optional().default("ctrl+k").describe("Delete to end of line in input"),
+ input_delete_to_line_start: z.string().optional().default("ctrl+u").describe("Delete to start of line in input"),
+ input_backspace: z.string().optional().default("backspace,shift+backspace").describe("Backspace in input"),
+ input_delete: z.string().optional().default("delete,shift+delete").describe("Delete character in input"),
+ input_undo: z.string().optional().default("ctrl+-,cmd+z").describe("Undo in input"),
+ input_redo: z.string().optional().default("ctrl+.,cmd+shift+z").describe("Redo in input"),
+ input_word_forward: z.string().optional().default("alt+f,alt+right").describe("Move word forward in input"),
+ input_word_backward: z.string().optional().default("alt+b,alt+left").describe("Move word backward in input"),
+ input_select_word_forward: z
+ .string()
+ .optional()
+ .default("alt+shift+f,alt+shift+right")
+ .describe("Select word forward in input"),
+ input_select_word_backward: z
+ .string()
+ .optional()
+ .default("alt+shift+b,alt+shift+left")
+ .describe("Select word backward in input"),
+ input_delete_word_forward: z.string().optional().default("ctrl+d").describe("Delete word forward in input"),
+ input_delete_word_backward: z
+ .string()
+ .optional()
+ .default("ctrl+w,alt+backspace")
+ .describe("Delete word backward in input"),
history_previous: z.string().optional().default("up").describe("Previous history item"),
history_next: z.string().optional().default("down").describe("Next history item"),
session_child_cycle: z.string().optional().default("<leader>right").describe("Next child session"),
diff --git a/packages/web/src/content/docs/keybinds.mdx b/packages/web/src/content/docs/keybinds.mdx
index 36b51c68d..67e53c455 100644
--- a/packages/web/src/content/docs/keybinds.mdx
+++ b/packages/web/src/content/docs/keybinds.mdx
@@ -46,10 +46,44 @@ OpenCode has a list of keybinds that you can customize through the OpenCode conf
"agent_cycle_reverse": "shift+tab",
"input_clear": "ctrl+c",
"input_paste": "ctrl+v",
- "input_submit": "enter",
- "input_newline": "shift+enter,ctrl+j",
+ "input_submit": "return",
+ "input_newline": "shift+return,ctrl+return,alt+return,ctrl+j",
+ "input_move_left": "left,ctrl+b",
+ "input_move_right": "right,ctrl+f",
+ "input_move_up": "up",
+ "input_move_down": "down",
+ "input_select_left": "shift+left",
+ "input_select_right": "shift+right",
+ "input_select_up": "shift+up",
+ "input_select_down": "shift+down",
+ "input_line_home": "ctrl+a",
+ "input_line_end": "ctrl+e",
+ "input_select_line_home": "none",
+ "input_select_line_end": "none",
+ "input_visual_line_home": "none",
+ "input_visual_line_end": "none",
+ "input_select_visual_line_home": "none",
+ "input_select_visual_line_end": "none",
+ "input_buffer_home": "home",
+ "input_buffer_end": "end",
+ "input_select_buffer_home": "shift+home",
+ "input_select_buffer_end": "shift+end",
+ "input_delete_line": "alt+d",
+ "input_delete_to_line_end": "ctrl+k",
+ "input_delete_to_line_start": "ctrl+u",
+ "input_backspace": "backspace,shift+backspace",
+ "input_delete": "delete,shift+delete",
+ "input_undo": "ctrl+-,cmd+z",
+ "input_redo": "ctrl+.,cmd+shift+z",
+ "input_word_forward": "alt+f,alt+right",
+ "input_word_backward": "alt+b,alt+left",
+ "input_select_word_forward": "alt+shift+f,alt+shift+right",
+ "input_select_word_backward": "alt+shift+b,alt+shift+left",
+ "input_delete_word_forward": "ctrl+d",
+ "input_delete_word_backward": "ctrl+w,alt+backspace",
"history_previous": "up",
- "history_next": "down"
+ "history_next": "down",
+ "terminal_suspend": "ctrl+z"
}
}
```