Skip to content

Commit 2e66ef8

Browse files
committed
feat(statusline): add rudimentary statusline component
1 parent 9851bd3 commit 2e66ef8

File tree

6 files changed

+106
-11
lines changed

6 files changed

+106
-11
lines changed

README.md

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ https://github.com/user-attachments/assets/4dd19151-89e4-4272-abac-6710dbc6edc1
1111
- Select prompts from a library and define your own.
1212
- Inject relevant editor context (buffer, cursor, selection, diagnostics, ...).
1313
- Control `opencode` with commands.
14-
- Respond to `opencode` permission requests.
1514
- Auto-reload buffers edited by `opencode` in real-time.
15+
- Respond to `opencode` permission requests.
16+
- Statusline component.
1617
- Forward `opencode`'s Server-Sent-Events as Neovim autocmds for automation.
1718
- Sensible defaults with well-documented, flexible configuration and API to fit your workflow.
1819

@@ -79,7 +80,7 @@ vim.g.opencode_opts = {
7980
---@type opencode.Provider
8081
provider = {
8182
toggle = function(self)
82-
-- Called by `require("opencode").toggle()`
83+
-- Called by `require("opencode").toggle()`.
8384
end,
8485
start = function(self)
8586
-- Called when sending a prompt or command to `opencode` but no process was found.
@@ -117,7 +118,9 @@ vim.g.opencode_opts = {
117118

118119
Send a prompt to `opencode`.
119120

120-
Replaces placeholders with the corresponding context:
121+
#### Contexts
122+
123+
Replaces placeholders in the prompt with the corresponding context:
121124

122125
| Placeholder | Context |
123126
| - | - |
@@ -132,7 +135,9 @@ Replaces placeholders with the corresponding context:
132135
| `@diff` | Git diff |
133136
| `@grapple` | [grapple.nvim](https://github.com/cbochs/grapple.nvim) tags |
134137

135-
Or pass a prompt name from `opts.prompts` to review, explain, and improve your code:
138+
#### Prompts
139+
140+
Reference a prompt by name to review, explain, and improve your code:
136141

137142
| Name | Prompt |
138143
|------------------------------------|-----------------------------------------------------------|
@@ -182,10 +187,6 @@ Send a [command](https://opencode.ai/docs/keybinds) to `opencode`:
182187

183188
> Supports *all* commands — these are just the most useful ones.
184189
185-
### 💻 Toggle — `require("opencode").toggle()`
186-
187-
Toggle `opencode` via `opts.provider.toggle`. Usually not explicitly needed — `opencode.nvim` automatically starts and shows `opencode` via `opts.provider.start` and `opts.provider.show` when you send a prompt or command.
188-
189190
### 📝 Select — `require("opencode").select()`
190191

191192
A single entrypoint to all `opencode.nvim` functionality 😄
@@ -213,6 +214,31 @@ vim.api.nvim_create_autocmd("User", {
213214
})
214215
```
215216

217+
### Edits
218+
219+
When `opencode` edits a file, `opencode.nvim` automatically reloads the corresponding buffer.
220+
221+
### Permissions
222+
223+
When `opencode` requests a permission, `opencode.nvim` waits for idle to ask you to approve or deny it.
224+
225+
### Statusline
226+
227+
[lualine](https://github.com/nvim-lualine/lualine.nvim):
228+
229+
```lua
230+
require("lualine").setup({
231+
sections = {
232+
lualine_z = {
233+
{
234+
require("opencode").statusline,
235+
},
236+
}
237+
}
238+
})
239+
240+
```
241+
216242
## 🙏 Acknowledgments
217243

218244
- Inspired by [nvim-aider](https://github.com/GeorgesAlkhouri/nvim-aider), [neopencode.nvim](https://github.com/loukotal/neopencode.nvim), and [sidekick.nvim](https://github.com/folke/sidekick.nvim).

lua/opencode.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ M.toggle = require("opencode.provider").toggle
1111
M.start = require("opencode.provider").start
1212
M.show = require("opencode.provider").show
1313

14+
M.statusline = require("opencode.status").statusline
15+
1416
return M

lua/opencode/config.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ local defaults = {
107107
input = {
108108
prompt = "Ask opencode: ",
109109
-- `snacks.input`-only options
110-
icon = "󱚣 ",
110+
icon = "󰚩 ",
111111
win = {
112112
title_pos = "left",
113113
relative = "cursor",

lua/opencode/provider.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ function M.start()
7474
end
7575
end
7676

77-
---Show `opencode` via `opts.provider`.
78-
---Only called if `provider.toggle` or `provider.start` was previously called.
77+
---Show `opencode` via `opts.provider`,
78+
---if `provider.toggle` or `provider.start` was previously called.
7979
function M.show()
8080
if started then
8181
if provider and provider.show then

lua/opencode/status.lua

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
local M = {}
2+
3+
---@alias opencode.Status
4+
---| "idle"
5+
---| "error"
6+
---| "responding"
7+
---| "requesting_permission"
8+
9+
---@type nil|opencode.Status
10+
local status = nil
11+
12+
-- TODO: Still seem to not get `session.idle` events reliably... So fallback to a timer.
13+
-- I wonder if it's because of the SSE `on_stdout` edge case? We silently miss events, and it errors completely for some?
14+
local idle_timer = vim.uv.new_timer()
15+
16+
function M.update(event)
17+
if event.type == "server.connected" or event.type == "session.idle" then
18+
status = "idle"
19+
elseif
20+
event.type == "message.updated"
21+
or event.type == "message.part.updated"
22+
or event.type == "permission.replied"
23+
then
24+
status = "responding"
25+
elseif event.type == "permission.updated" then
26+
status = "requesting_permission"
27+
elseif event.type == "session.error" then
28+
status = "error"
29+
end
30+
31+
idle_timer:stop()
32+
idle_timer:start(
33+
1000,
34+
0,
35+
vim.schedule_wrap(function()
36+
if status == "responding" then
37+
status = "idle"
38+
end
39+
end)
40+
)
41+
end
42+
43+
function M.statusline()
44+
-- Kinda hard to distinguish these icons, but they're fun... :D
45+
-- And a nice one-char solution.
46+
if status == "idle" then
47+
return "󰚩"
48+
elseif status == "responding" then
49+
return "󱜙"
50+
elseif status == "requesting_permission" then
51+
return "󱚟"
52+
elseif status == "error" then
53+
return "󱚡"
54+
else
55+
return "󱚧"
56+
end
57+
end
58+
59+
return M

plugin/status.lua

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
vim.api.nvim_create_autocmd("User", {
2+
group = vim.api.nvim_create_augroup("OpencodeStatus", { clear = true }),
3+
pattern = "OpencodeEvent",
4+
callback = function(args)
5+
require("opencode.status").update(args.data.event)
6+
end,
7+
desc = "Update opencode status",
8+
})

0 commit comments

Comments
 (0)