Skip to content
29 changes: 21 additions & 8 deletions lua/opencode/event_manager.lua
Original file line number Diff line number Diff line change
Expand Up @@ -273,14 +273,27 @@ function EventManager:_on_drained_events(events)
if event.type == 'message.part.updated' and event.properties.part then
local part_id = event.properties.part.id
if part_update_indices[part_id] then
-- vim.notify('collapsing: ' .. part_id .. ' text: ' .. vim.inspect(event.properties.part.text))
-- put this event in the earlier slot

-- move this newer part to the position of the original part
collapsed_events[part_update_indices[part_id]] = event

-- clear out this parts now unneeded position
collapsed_events[i] = nil
local previous_index = part_update_indices[part_id]

-- Preserve ordering dependencies for permission events.
-- Moving a later part update earlier can break correlation when
-- permission.updated/permission.asked sits between the two updates.
local has_intervening_permission_event = false
for j = previous_index + 1, i - 1 do
if events[j] and (events[j].type == 'permission.updated' or events[j].type == 'permission.asked') then
has_intervening_permission_event = true
break
end
end

if has_intervening_permission_event then
collapsed_events[previous_index] = nil
collapsed_events[i] = event
part_update_indices[part_id] = i
else
collapsed_events[previous_index] = event
collapsed_events[i] = nil
end
else
part_update_indices[part_id] = i
collapsed_events[i] = event
Expand Down
97 changes: 90 additions & 7 deletions lua/opencode/ui/permission_window.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,67 @@ function M.add_permission(permission)
return
end

if permission.tool then
permission._message_id = permission.tool.messageID
permission._call_id = permission.tool.callID
end

-- Update if exists, otherwise add
for i, existing in ipairs(M._permission_queue) do
if existing.id == permission.id then
M._permission_queue[i] = permission
M._setup_dialog() -- Refresh dialog when permission is updated
M._setup_dialog()
return
end
end

table.insert(M._permission_queue, permission)
M._setup_dialog() -- Setup dialog when first permission is added
M._setup_dialog()
end

---Update permission from message part data
---@param permission_id string
---@param part table
---@return boolean
function M.update_permission_from_part(permission_id, part)
if not permission_id or not part then
return false
end

local permission = nil
for i, existing in ipairs(M._permission_queue) do
if existing.id == permission_id then
permission = existing
break
end
end

if not permission then
return false
end

if part.state and part.state.input then
local input = part.state.input
local updated = false

if input.description and input.description ~= '' then
permission._description = input.description
updated = true
end

if input.command and input.command ~= '' then
permission._command = input.command
updated = true
end

if updated and M._dialog then
M._setup_dialog()
end

return true
end

return false
end

---Remove permission from queue
Expand Down Expand Up @@ -71,12 +121,33 @@ function M.format_display(output)
progress = string.format(' (%d/%d)', 1, #M._permission_queue)
end

local title = permission.title
or table.concat(permission.patterns or {}, '`, `'):gsub('\r', '\\r'):gsub('\n', '\\n')
or 'Unknown Permission'
local perm_type = permission.permission or permission.type or 'unknown'
local content = {}
local perm_type = permission.permission or permission.type or ''

if permission._description and permission._description ~= '' then
table.insert(content, (icons.get(perm_type)) .. ' *' .. perm_type .. '* ' .. permission._description)
elseif permission.title then
table.insert(content, (icons.get(perm_type)) .. ' *' .. perm_type .. '* `' .. permission.title .. '`')
else
table.insert(content, (icons.get(perm_type)) .. ' *' .. perm_type .. '*')
local lines = permission.patterns or {}
table.insert(content, string.format('```%s', perm_type))
for i, line in ipairs(lines) do
table.insert(content, line)
end
table.insert(content, '```')
end

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add an empty line after the title/description

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be there now since I applied your suggestion

local content = { (icons.get(perm_type) or '') .. ' *' .. (perm_type or '') .. '*' .. ' `' .. title .. '`' }
table.insert(content, '')

if permission._command and permission._command ~= '' then
local lines = vim.split(permission._command, '\n')
table.insert(content, string.format('```%s', perm_type))
for _, line in ipairs(lines) do
table.insert(content, line)
end
table.insert(content, '```')
end

local options = {
{ label = 'Allow once' },
Expand All @@ -88,6 +159,9 @@ function M.format_display(output)
if perm_type == 'edit' and permission.metadata and permission.metadata.diff then
render_content = function(out)
out:add_line(content[1])
if content[2] then
out:add_line(content[2])
end
out:add_line('')

local file_type = permission.metadata.filepath and vim.fn.fnamemodify(permission.metadata.filepath, ':e') or ''
Expand All @@ -112,6 +186,11 @@ function M._setup_dialog()
return
end

local saved_selection = nil
if M._dialog then
saved_selection = M._dialog:get_selection()
end

M._clear_dialog()

if not state.windows or not state.windows.output_buf then
Expand Down Expand Up @@ -176,6 +255,10 @@ function M._setup_dialog()
})

M._dialog:setup()

if saved_selection then
M._dialog:set_selection(saved_selection)
end
end

function M._clear_dialog()
Expand Down
13 changes: 13 additions & 0 deletions lua/opencode/ui/renderer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,19 @@ function M.on_part_updated(properties, revert_index)

local formatted = formatter.format_part(part, message, is_last_part)

if part.callID and state.pending_permissions then
for _, permission in ipairs(state.pending_permissions) do
local tool = permission.tool
local perm_callID = tool and tool.callID or permission.callID
local perm_messageID = tool and tool.messageID or permission.messageID

if perm_callID == part.callID and perm_messageID == part.messageID then
require('opencode.ui.permission_window').update_permission_from_part(permission.id, part)
break
end
end
end

if revert_index and is_new_part then
return
end
Expand Down
2 changes: 1 addition & 1 deletion tests/data/ansi-codes.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -8553,5 +8553,5 @@
"",
""
],
"timestamp": 1770748573
"timestamp": 1770751422
}
2 changes: 1 addition & 1 deletion tests/data/api-abort.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,5 +177,5 @@
"",
""
],
"timestamp": 1770748573
"timestamp": 1770751423
}
2 changes: 1 addition & 1 deletion tests/data/api-error.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -221,5 +221,5 @@
"",
""
],
"timestamp": 1770748573
"timestamp": 1770751423
}
2 changes: 1 addition & 1 deletion tests/data/cursor_data.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -308,5 +308,5 @@
"",
""
],
"timestamp": 1770748573
"timestamp": 1770751423
}
2 changes: 1 addition & 1 deletion tests/data/diagnostics.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -11190,5 +11190,5 @@
"",
""
],
"timestamp": 1770748574
"timestamp": 1770751424
}
2 changes: 1 addition & 1 deletion tests/data/diff.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -468,5 +468,5 @@
"",
""
],
"timestamp": 1770748574
"timestamp": 1770751424
}
2 changes: 1 addition & 1 deletion tests/data/markdown-codefence.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -794,5 +794,5 @@
"",
""
],
"timestamp": 1770748574
"timestamp": 1770751424
}
2 changes: 1 addition & 1 deletion tests/data/mentions-with-ranges.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -497,5 +497,5 @@
"",
""
],
"timestamp": 1770748575
"timestamp": 1770751424
}
2 changes: 1 addition & 1 deletion tests/data/message-removal.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -309,5 +309,5 @@
"",
""
],
"timestamp": 1770748575
"timestamp": 1770751425
}
2 changes: 1 addition & 1 deletion tests/data/multiple-messages-synthetic.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -405,5 +405,5 @@
"",
""
],
"timestamp": 1770748575
"timestamp": 1770751425
}
2 changes: 1 addition & 1 deletion tests/data/multiple-messages.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -416,5 +416,5 @@
"",
""
],
"timestamp": 1770748575
"timestamp": 1770751425
}
2 changes: 1 addition & 1 deletion tests/data/multiple-question-ask-reply-all.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -537,5 +537,5 @@
"",
""
],
"timestamp": 1770748576
"timestamp": 1770751425
}
2 changes: 1 addition & 1 deletion tests/data/multiple-question-ask.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -468,5 +468,5 @@
"",
""
],
"timestamp": 1770748576
"timestamp": 1770751426
}
2 changes: 1 addition & 1 deletion tests/data/perf.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -479,5 +479,5 @@
"",
""
],
"timestamp": 1770748576
"timestamp": 1770751426
}
2 changes: 1 addition & 1 deletion tests/data/permission-ask-new-approve.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -816,5 +816,5 @@
"",
""
],
"timestamp": 1770748577
"timestamp": 1770751427
}
2 changes: 1 addition & 1 deletion tests/data/permission-ask-new-deny.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,5 +342,5 @@
"",
""
],
"timestamp": 1770748577
"timestamp": 1770751427
}
Loading