Skip to content

Commit e8ae2b9

Browse files
committed
feat: Normal buffer keymaps
1 parent f87e18f commit e8ae2b9

5 files changed

Lines changed: 110 additions & 11 deletions

File tree

README.md

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Integrate the [opencode](https://github.com/sst/opencode) AI assistant with Neov
4848
vim.keymap.set({ "n", "x" }, "go", function() return require("opencode").operator("@this ") end, { desc = "Add range to opencode", expr = true })
4949
vim.keymap.set("n", "goo", function() return require("opencode").operator("@this ") .. "_" end, { desc = "Add line to opencode", expr = true })
5050

51+
-- The default <C-u>/<C-d> keymaps will work in the normal mode but it is possible to scroll opencode from any buffer:
5152
vim.keymap.set("n", "<S-C-u>", function() require("opencode").command("session.half.page.up") end, { desc = "Scroll opencode up" })
5253
vim.keymap.set("n", "<S-C-d>", function() require("opencode").command("session.half.page.down") end, { desc = "Scroll opencode down" })
5354

@@ -79,17 +80,17 @@ programs.nixvim = {
7980

8081
`opencode.nvim` replaces placeholders in prompts with the corresponding context:
8182

82-
| Placeholder | Context |
83-
| -------------- | ------------------------------------------------------------- |
84-
| `@this` | Operator range or visual selection if any, else cursor position |
85-
| `@buffer` | Current buffer |
86-
| `@buffers` | Open buffers |
87-
| `@visible` | Visible text |
88-
| `@diagnostics` | Current buffer diagnostics |
89-
| `@quickfix` | Quickfix list |
90-
| `@diff` | Git diff |
91-
| `@marks` | Global marks |
92-
| `@grapple` | [grapple.nvim](https://github.com/cbochs/grapple.nvim) tags |
83+
| Placeholder | Context |
84+
| -------------- | --------------------------------------------------------------- |
85+
| `@this` | Operator range or visual selection if any, else cursor position |
86+
| `@buffer` | Current buffer |
87+
| `@buffers` | Open buffers |
88+
| `@visible` | Visible text |
89+
| `@diagnostics` | Current buffer diagnostics |
90+
| `@quickfix` | Quickfix list |
91+
| `@diff` | Git diff |
92+
| `@marks` | Global marks |
93+
| `@grapple` | [grapple.nvim](https://github.com/cbochs/grapple.nvim) tags |
9394

9495
### Prompts
9596

@@ -107,6 +108,37 @@ Select or reference prompts to review, explain, and improve your code:
107108
| `review` | Review `@this` for correctness and readability |
108109
| `test` | Add tests for `@this` |
109110

111+
### Keymaps
112+
113+
`opencode.nvim` sets these buffer-local keymaps in opencode terminal buffers by default:
114+
115+
| Keymap | Command | Description |
116+
| ------- | ------------------------ | ---------------------------- |
117+
| `<C-u>` | `session.half.page.up` | Scroll up half page |
118+
| `<C-d>` | `session.half.page.down` | Scroll down half page |
119+
| `<Esc>` | `session.interrupt` | Interrup (same as esc press) |
120+
| `gg` | `session.first` | Go to first message |
121+
| `G` | `session.last` | Go to last message |
122+
123+
You can customize or disable these keymaps:
124+
125+
```lua
126+
vim.g.opencode_opts = {
127+
-- Customize keymaps
128+
keymaps = {
129+
n = {
130+
["<C-u>"] = { "session.half.page.up", desc = "Scroll up" },
131+
["<C-d>"] = { "session.half.page.down", desc = "Scroll down" },
132+
["gg"] = false, -- Disable this keymap
133+
-- Add custom keymaps
134+
["<C-n>"] = { "session.new", desc = "New session" },
135+
},
136+
},
137+
-- Or disable all default keymaps
138+
-- keymaps = false,
139+
}
140+
```
141+
110142
### Provider
111143

112144
You can manually run `opencode` inside Neovim's CWD however you like and `opencode.nvim` will find it!

lua/opencode/config.lua

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,23 @@ vim.g.opencode_opts = vim.g.opencode_opts
3737
---
3838
---Provide an integrated `opencode` when one is not found.
3939
---@field provider? opencode.Provider|opencode.provider.Opts
40+
---
41+
---Buffer-local keymaps for opencode terminal buffers.
42+
---Set to `false` to disable all default keymaps.
43+
---@field keymaps? opencode.keymaps.Opts|false
4044

4145
---@class opencode.Prompt : opencode.api.prompt.Opts
4246
---@field prompt string The prompt to send to `opencode`.
4347
---@field ask? boolean Call `ask(prompt)` instead of `prompt(prompt)`. Useful for prompts that expect additional user input.
4448

49+
---Buffer-local keymaps for opencode terminal buffers.
50+
---@class opencode.keymaps.Opts
51+
---@field n? table<string, opencode.keymap.Def|false> Normal mode keymaps. Set to `false` to disable a default keymap.
52+
53+
---@class opencode.keymap.Def
54+
---@field [1] string|fun() The command string or callback function.
55+
---@field desc? string Description for the keymap.
56+
4557
---@type opencode.Opts
4658
local defaults = {
4759
port = nil,
@@ -116,6 +128,15 @@ local defaults = {
116128
idle_delay_ms = 1000,
117129
},
118130
},
131+
keymaps = {
132+
n = {
133+
["<C-u>"] = { "session.half.page.up", desc = "Scroll up half page" },
134+
["<C-d>"] = { "session.half.page.down", desc = "Scroll down half page" },
135+
["gg"] = { "session.first", desc = "Go to first message" },
136+
["G"] = { "session.last", desc = "Go to last message" },
137+
["<Esc>"] = { "session.interrupt", desc = "Interrupt current session (esc)" },
138+
},
139+
},
119140
provider = {
120141
cmd = "opencode --port",
121142
enabled = vim.tbl_filter(

lua/opencode/keymaps.lua

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
local M = {}
2+
3+
---Apply buffer-local keymaps to the given buffer.
4+
---@param bufnr integer The buffer number to apply keymaps to.
5+
function M.apply(bufnr)
6+
local opts = require("opencode.config").opts.keymaps
7+
if opts == false then
8+
return
9+
end
10+
11+
local command = require("opencode.api.command").command
12+
13+
if opts and opts.n then
14+
for lhs, def in pairs(opts.n) do
15+
if def ~= false then
16+
local rhs = def[1]
17+
local callback
18+
if type(rhs) == "string" then
19+
callback = function()
20+
command(rhs)
21+
end
22+
else
23+
-- It's a function
24+
callback = rhs
25+
end
26+
27+
vim.keymap.set("n", lhs, callback, {
28+
buffer = bufnr,
29+
desc = def.desc,
30+
})
31+
end
32+
end
33+
end
34+
end
35+
36+
return M

lua/opencode/provider/terminal.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ function Terminal:start()
4949
self.bufnr = vim.api.nvim_create_buf(true, false)
5050
self.winid = vim.api.nvim_open_win(self.bufnr, true, self.opts)
5151

52+
require("opencode.keymaps").apply(self.bufnr)
53+
5254
-- Redraw terminal buffer on initial render.
5355
-- Fixes empty columns on the right side.
5456
local auid

plugin/keymaps.lua

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- Apply buffer-local keymaps to opencode terminal buffers.
2+
-- This handles the snacks provider (and any other provider using `opencode_terminal` filetype).
3+
vim.api.nvim_create_autocmd("FileType", {
4+
pattern = "opencode_terminal",
5+
callback = function(ev)
6+
require("opencode.keymaps").apply(ev.buf)
7+
end,
8+
})

0 commit comments

Comments
 (0)