Skip to content

Commit 6b760c3

Browse files
committed
feat(permissions): wait for idle, add opts for enabled and delay
#60
1 parent de5b146 commit 6b760c3

File tree

2 files changed

+68
-17
lines changed

2 files changed

+68
-17
lines changed

lua/opencode/config.lua

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,12 @@ vim.g.opencode_opts = vim.g.opencode_opts
4040
---Supports [snacks.picker](https://github.com/folke/snacks.nvim/blob/main/docs/picker.md).
4141
---@field select? snacks.picker.ui_select.Opts
4242
---
43+
---Options for `opencode` permission requests.
44+
---@field permissions? opencode.permissions.Opts
45+
---
4346
---Embedded terminal options for `toggle()`.
4447
---Supports [snacks.terminal](https://github.com/folke/snacks.nvim/blob/main/docs/terminal.md).
45-
---@field terminal? opencode.Opts.terminal
48+
---@field terminal? opencode.terminal.Opts
4649
---
4750
---Called when no `opencode` process is found so you can start it.
4851
---After calling this function, `opencode.nvim` will poll for a couple seconds to see if an `opencode` process appears.
@@ -108,7 +111,14 @@ local defaults = {
108111
},
109112
},
110113
},
111-
---@class opencode.Opts.terminal : snacks.terminal.Opts
114+
---@class opencode.permissions.Opts
115+
---@field enabled boolean Whether to show permission requests.
116+
---@field idle_delay_ms number Amount of user idle time before showing permission requests.
117+
permissions = {
118+
enabled = true,
119+
idle_delay_ms = 1000,
120+
},
121+
---@class opencode.terminal.Opts : snacks.terminal.Opts
112122
---@field cmd string The command to run in the embedded terminal. See [here](https://opencode.ai/docs/cli) for options.
113123
terminal = {
114124
cmd = "opencode",

plugin/permissions.lua

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,47 @@
1+
---Waits for user to be idle (no keypresses) for `timeout` milliseconds, then calls `callback`.
2+
---@param callback function Function to call when user is idle.
3+
---@param timeout number Time in milliseconds to wait for idle.
4+
local function wait_for_user_idle(callback, timeout)
5+
local idle_timer = vim.uv.new_timer()
6+
local key_listener_id = nil
7+
8+
local function on_idle()
9+
idle_timer:stop()
10+
idle_timer:close()
11+
vim.on_key(nil, key_listener_id)
12+
13+
callback()
14+
end
15+
16+
local function reset_idle_timer()
17+
idle_timer:stop()
18+
idle_timer:start(timeout, 0, vim.schedule_wrap(on_idle))
19+
end
20+
21+
key_listener_id = vim.on_key(function()
22+
reset_idle_timer()
23+
end)
24+
25+
-- Start the initial timer
26+
reset_idle_timer()
27+
end
28+
129
local is_permission_request_open = false
230
vim.api.nvim_create_autocmd("User", {
331
group = vim.api.nvim_create_augroup("OpencodePermissions", { clear = true }),
432
pattern = "OpencodeEvent",
533
callback = function(args)
34+
if not require("opencode.config").opts.permissions.enabled then
35+
return
36+
end
37+
638
local event = args.data.event
739
---@type number
840
local port = args.data.port
941

1042
if event.type == "permission.updated" then
1143
--[[
12-
--{
44+
`event.properties` example: {
1345
callID = "call_UgJGOepAJ5vQ7rkfGI5LNTaQ",
1446
id = "per_9fe806323001XBhIAz9OrYTrgl",
1547
messageID = "msg_9fe805f7700166572ZsmpxllBH",
@@ -26,20 +58,29 @@ vim.api.nvim_create_autocmd("User", {
2658
type = "bash"
2759
}
2860
--]]
29-
is_permission_request_open = true
30-
vim.ui.select({ "Once", "Always", "Reject" }, {
31-
prompt = 'opencode requesting permission: "' .. event.properties.title .. '": ',
32-
format_item = function(item)
33-
return item
34-
end,
35-
}, function(choice)
36-
is_permission_request_open = false
37-
if choice then
38-
local session_id = event.properties.sessionID
39-
local permission_id = event.properties.id
40-
require("opencode.cli.client").permit(port, session_id, permission_id, choice:lower())
41-
end
42-
end)
61+
62+
local idle_delay_ms = require("opencode.config").opts.permissions.idle_delay_ms
63+
vim.notify(
64+
"`opencode` requested permission — awaiting idle…",
65+
vim.log.levels.INFO,
66+
{ title = "opencode", timeout = idle_delay_ms }
67+
)
68+
wait_for_user_idle(function()
69+
is_permission_request_open = true
70+
vim.ui.select({ "Once", "Always", "Reject" }, {
71+
prompt = 'opencode requesting permission: "' .. event.properties.title .. '": ',
72+
format_item = function(item)
73+
return item
74+
end,
75+
}, function(choice)
76+
is_permission_request_open = false
77+
if choice then
78+
local session_id = event.properties.sessionID
79+
local permission_id = event.properties.id
80+
require("opencode.cli.client").permit(port, session_id, permission_id, choice:lower())
81+
end
82+
end)
83+
end, idle_delay_ms)
4384
elseif event.type == "permission.replied" and is_permission_request_open then
4485
-- Close our permission dialog, in case user responded in the TUI
4586
-- TODO: Hmm, we don't seem to process the event while built-in select is open...

0 commit comments

Comments
 (0)