Skip to content

feat(snacks): add snacks.picker action integration#152

Open
naowalrahman wants to merge 4 commits intonickjvandyke:mainfrom
naowalrahman:snacks-action-integration
Open

feat(snacks): add snacks.picker action integration#152
naowalrahman wants to merge 4 commits intonickjvandyke:mainfrom
naowalrahman:snacks-action-integration

Conversation

@naowalrahman
Copy link

Description

Adds a function under lua/opencode/integrations/picker/snacks.lua that can be used to set up a snacks.picker action that sends the selected/current items to opencode via a keybind.

Note

Line number, if available, is appended to the end of the reference because diagnostic text content usually doesn't have the line number. This is redundant for grep/file references, because the text content for those items do have the line number already, but for the sake of simplicity it is better to just have the line number at the end anyway.

Integration looks like this:

return {
    "folke/snacks.nvim",
    opts = {
        picker = {
            actions = {
                opencode_send = require("opencode.integrations.picker.snacks").opencode_send,
            },
            win = {
                input = {
                    keys = {
                        ["<a-a>"] = {
                            "opencode_send",
                            mode = { "n", "i" },
                        },
                    },
                },
            },
        },
    },
}

Related Issue(s)

Copilot AI review requested due to automatic review settings January 29, 2026 04:13
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a snacks.picker action integration that sends the currently selected (or fallback) picker items into the opencode prompt.

Changes:

  • Introduces opencode_send(picker) action for snacks.picker.
  • Builds a newline-delimited list of selected picker entries and appends it to the opencode prompt.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 10 to 24
local entries = {}
for _, item in ipairs(picker:selected({ fallback = true })) do
local entry = ""
if item.text and item.text ~= "" then -- Includes file reference
entry = item.text
end
-- Append line numbers if available
if item.file and item.pos then
local line_ref = ("L%d"):format(item.pos[1])
if item.end_pos and item.end_pos[1] ~= item.pos[1] then
line_ref = line_ref .. ("-L%d"):format(item.end_pos[1])
end
entry = entry .. " " .. line_ref
end
if entry ~= "" then
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

entry is only populated from item.text. For items where item.file/item.pos exist but item.text is empty (common for many picker items), the code will end up sending just a line ref (e.g. " L10") or dropping the item entirely, which is not a valid opencode file reference. Consider using opencode.context.Context.format({ path = item.file, start_line = ..., start_col = ... }) (and optionally appending item.text as a label) so the output always includes the required @path prefix when a file is available.

Suggested change
local entries = {}
for _, item in ipairs(picker:selected({ fallback = true })) do
local entry = ""
if item.text and item.text ~= "" then -- Includes file reference
entry = item.text
end
-- Append line numbers if available
if item.file and item.pos then
local line_ref = ("L%d"):format(item.pos[1])
if item.end_pos and item.end_pos[1] ~= item.pos[1] then
line_ref = line_ref .. ("-L%d"):format(item.end_pos[1])
end
entry = entry .. " " .. line_ref
end
if entry ~= "" then
local Context = require("opencode.context").Context
local entries = {}
for _, item in ipairs(picker:selected({ fallback = true })) do
local entry
-- Prefer constructing a proper opencode context when file and position are available
if item.file and item.pos then
local start_line = item.pos[1]
local start_col = item.pos[2]
local ctx = Context.format({
path = item.file,
start_line = start_line,
start_col = start_col,
})
if item.text and item.text ~= "" then
entry = ctx .. " " .. item.text
else
entry = ctx
end
-- Fallback: no file info, just use the text if present
elseif item.text and item.text ~= "" then
entry = item.text
end
if entry and entry ~= "" then

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

This is wrong because item.text is never empty in my experience. Tested on file picker, grep, diagnostics, etc.

Comment on lines 17 to 23
if item.file and item.pos then
local line_ref = ("L%d"):format(item.pos[1])
if item.end_pos and item.end_pos[1] ~= item.pos[1] then
line_ref = line_ref .. ("-L%d"):format(item.end_pos[1])
end
entry = entry .. " " .. line_ref
end
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

This reimplements location formatting manually and only includes line numbers. The project already has Context.format (lua/opencode/context.lua) which handles required spacing for @path references and supports line/column ranges. Reusing it here will avoid subtle formatting bugs and keep location formatting consistent across integrations.

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

@path references for the plugin were removed in a recent commit because opencode doesn't parse them unless you use the native TUI picker and press tab

Copy link
Owner

Choose a reason for hiding this comment

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

I think we can still re-use Context.format here though right? Assuming we have the necessary fields on item

Copy link
Author

Choose a reason for hiding this comment

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

you are right!

@dmtrKovalenko
Copy link
Contributor

Updated even though it is limiting the experience. But I think not to much if you don't know about it

@nickjvandyke nickjvandyke force-pushed the main branch 6 times, most recently from de5f1cc to 5de2380 Compare February 2, 2026 16:31
@naowalrahman
Copy link
Author

Updated even though it is limiting the experience. But I think not to much if you don't know about it

@dmtrKovalenko what do you mean?

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@naowalrahman
Copy link
Author

@nickjvandyke addressed copilot's comments, sorry for taking a while 😅. The LuaLS diagnostic check failing seems to be unrelated to the PR, because this PR doesn't change lua/opencode/provider/snacks.lua.

@nickjvandyke
Copy link
Owner

I think @dmtrKovalenko meant to comment in #151

No worries on the wait, I know all too well that there's not always time for FOSS 😂 Thanks for addressing, I will take a look ASAP!

@nickjvandyke
Copy link
Owner

Can you merge main to your branch? I think another PR may have fixed the diagnostic error you're getting

@naowalrahman
Copy link
Author

@nickjvandyke should be good now hopefully!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants