From 37c46e8d9ad4141424de163d880b666ec1654520 Mon Sep 17 00:00:00 2001 From: Naowal Rahman Date: Wed, 28 Jan 2026 23:02:55 -0500 Subject: [PATCH 01/10] feat(snacks): add snacks.picker action integration --- lua/opencode/integrations/picker/snacks.lua | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 lua/opencode/integrations/picker/snacks.lua diff --git a/lua/opencode/integrations/picker/snacks.lua b/lua/opencode/integrations/picker/snacks.lua new file mode 100644 index 00000000..2db2fb33 --- /dev/null +++ b/lua/opencode/integrations/picker/snacks.lua @@ -0,0 +1,31 @@ +---@module 'snacks' + +---Snacks picker integration for opencode. +---@class opencode.integrations.picker.snacks +local M = {} + +---Send selected picker items to opencode prompt. +---@param picker snacks.Picker +function M.opencode_send(picker) + 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 + entries[#entries + 1] = entry + end + end + require("opencode").prompt(table.concat(entries, "\n") .. "\n") +end + +return M From de1f887923bc0212ea2e70b22fd838de8e52aa6a Mon Sep 17 00:00:00 2001 From: Naowal Rahman Date: Wed, 4 Feb 2026 17:09:24 -0500 Subject: [PATCH 02/10] Account for zero entries edge case Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- lua/opencode/integrations/picker/snacks.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lua/opencode/integrations/picker/snacks.lua b/lua/opencode/integrations/picker/snacks.lua index 2db2fb33..e5b42e29 100644 --- a/lua/opencode/integrations/picker/snacks.lua +++ b/lua/opencode/integrations/picker/snacks.lua @@ -25,6 +25,9 @@ function M.opencode_send(picker) entries[#entries + 1] = entry end end + if #entries == 0 then + return + end require("opencode").prompt(table.concat(entries, "\n") .. "\n") end From 2f1c55e3b1bfb6cb32554a02191eaaf52ddf6cae Mon Sep 17 00:00:00 2001 From: Naowal Rahman Date: Sat, 7 Feb 2026 11:36:41 -0500 Subject: [PATCH 03/10] refactor(snacks): use Context.format in opencode_send() --- lua/opencode/integrations/picker/snacks.lua | 25 ++++++++------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/lua/opencode/integrations/picker/snacks.lua b/lua/opencode/integrations/picker/snacks.lua index e5b42e29..e44569fb 100644 --- a/lua/opencode/integrations/picker/snacks.lua +++ b/lua/opencode/integrations/picker/snacks.lua @@ -7,28 +7,21 @@ local M = {} ---Send selected picker items to opencode prompt. ---@param picker snacks.Picker function M.opencode_send(picker) + local Context = require("opencode.context") 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 - entries[#entries + 1] = entry - end + entries[#entries + 1] = Context.format({ + path = item.text, + start_line = item.pos and item.pos[1] or nil, + start_col = item.pos and item.pos[2] or nil, + end_line = item.end_pos and item.end_pos[1] or nil, + end_col = item.end_pos and item.end_pos[2] or nil, + }) end if #entries == 0 then return end - require("opencode").prompt(table.concat(entries, "\n") .. "\n") + require("opencode").prompt(table.concat(entries, "\n")) end return M From 7f3720019f75c4156d56471b2e851622a4cc238a Mon Sep 17 00:00:00 2001 From: Nick van Dyke Date: Mon, 16 Feb 2026 08:39:56 -0700 Subject: [PATCH 04/10] prefer just item location if possible --- lua/opencode/integrations/picker/snacks.lua | 35 ++++++++++----------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/lua/opencode/integrations/picker/snacks.lua b/lua/opencode/integrations/picker/snacks.lua index e44569fb..afba7f0a 100644 --- a/lua/opencode/integrations/picker/snacks.lua +++ b/lua/opencode/integrations/picker/snacks.lua @@ -1,27 +1,26 @@ ---@module 'snacks' ----Snacks picker integration for opencode. ----@class opencode.integrations.picker.snacks local M = {} ----Send selected picker items to opencode prompt. +---Send selected picker items to `opencode`. ---@param picker snacks.Picker -function M.opencode_send(picker) - local Context = require("opencode.context") - local entries = {} - for _, item in ipairs(picker:selected({ fallback = true })) do - entries[#entries + 1] = Context.format({ - path = item.text, - start_line = item.pos and item.pos[1] or nil, - start_col = item.pos and item.pos[2] or nil, - end_line = item.end_pos and item.end_pos[1] or nil, - end_col = item.end_pos and item.end_pos[2] or nil, - }) - end - if #entries == 0 then - return +function M.send(picker) + local items = vim.tbl_map(function(item) + return item.file + -- Prefer just the location if possible, so the LLM can also fetch context + and require("opencode.context").format({ + path = item.file, + start_line = item.pos and item.pos[1] or nil, + start_col = item.pos and item.pos[2] or nil, + end_line = item.end_pos and item.end_pos[1] or nil, + end_col = item.end_pos and item.end_pos[2] or nil, + }) + or item.text + end, picker:selected({ fallback = true })) + + if #items > 0 then + require("opencode").prompt(table.concat(items, "\n")) end - require("opencode").prompt(table.concat(entries, "\n")) end return M From a671b075ef6ea5c56a0003324ff1086e17505b68 Mon Sep 17 00:00:00 2001 From: Nick van Dyke Date: Mon, 16 Feb 2026 08:44:28 -0700 Subject: [PATCH 05/10] add to public API --- lua/opencode.lua | 24 ++++++++++++++++++- .../{picker => pickers}/snacks.lua | 3 ++- 2 files changed, 25 insertions(+), 2 deletions(-) rename lua/opencode/integrations/{picker => pickers}/snacks.lua (81%) diff --git a/lua/opencode.lua b/lua/opencode.lua index 74ece08d..161d7468 100644 --- a/lua/opencode.lua +++ b/lua/opencode.lua @@ -1,6 +1,10 @@ ---`opencode.nvim` public API. local M = {} +---------- +--- UI --- +---------- + ---Input a prompt for `opencode`. --- --- - Press the up arrow to browse recent asks. @@ -39,6 +43,7 @@ M.ask = function(default, opts) end end) end + ---Select from all `opencode.nvim` functionality. --- --- - Prompts @@ -57,6 +62,7 @@ M.select = function(opts) end end) end + ---Select the active `opencode` session. M.select_session = function() return require("opencode.ui.select_session") @@ -70,6 +76,7 @@ M.select_session = function() end end) end + ---Select an `opencode` server to connect to, ---sending future requests to it and subscribing to its events. M.select_server = function() @@ -90,6 +97,12 @@ M.select_server = function() end) end +M.statusline = require("opencode.status").statusline + +------------------------ +--- Programmatic API --- +------------------------ + ---Prompt `opencode`. --- --- - Resolves `prompt` if it references an `opts.prompts` entry by name. @@ -105,6 +118,7 @@ M.prompt = function(prompt, opts) end end) end + ---Command `opencode`. --- ---@param command opencode.Command|string The command to send. Can be built-in or reference your custom commands. @@ -116,10 +130,18 @@ end M.operator = require("opencode.api.operator").operator +---------------- +--- Provider --- +---------------- + M.toggle = require("opencode.provider").toggle M.start = require("opencode.provider").start M.stop = require("opencode.provider").stop -M.statusline = require("opencode.status").statusline +-------------------- +--- Integrations --- +-------------------- + +M.snacks_picker_send = require("opencode.integrations.pickers.snacks").send return M diff --git a/lua/opencode/integrations/picker/snacks.lua b/lua/opencode/integrations/pickers/snacks.lua similarity index 81% rename from lua/opencode/integrations/picker/snacks.lua rename to lua/opencode/integrations/pickers/snacks.lua index afba7f0a..be96028d 100644 --- a/lua/opencode/integrations/picker/snacks.lua +++ b/lua/opencode/integrations/pickers/snacks.lua @@ -2,7 +2,8 @@ local M = {} ----Send selected picker items to `opencode`. +---Send the selected or current `snacks.picker` items to `opencode`, +---Formats items' file and position if possible, otherwise falls back to their text content. ---@param picker snacks.Picker function M.send(picker) local items = vim.tbl_map(function(item) From 17070e54ec1ece8cfd3b1c84de32da81a8d99ba1 Mon Sep 17 00:00:00 2001 From: Nick van Dyke Date: Mon, 16 Feb 2026 08:59:34 -0700 Subject: [PATCH 06/10] add config integration to readme --- README.md | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 903d329b..c36a0b3c 100644 --- a/README.md +++ b/README.md @@ -26,10 +26,36 @@ Integrate the [opencode](https://github.com/sst/opencode) AI assistant with Neov { "nickjvandyke/opencode.nvim", dependencies = { - -- Recommended for `ask()` and `select()`. - -- Required for `snacks` provider. - ---@module 'snacks' <- Loads `snacks.nvim` types for configuration intellisense. - { "folke/snacks.nvim", opts = { input = {}, picker = {}, terminal = {} } }, + { + -- Optional, but recommended. + ---@module 'snacks' <- Loads `snacks.nvim` types for configuration intellisense. + "folke/snacks.nvim", + optional = true, + opts = { + -- Enhances `ask()`. + input = {}, + -- Enhances `select()`. + picker = { + actions = { + opencode_send = function(...) + return require('opencode').snacks_picker_send(...) + end, + }, + win = { + input = { + keys = { + [''] = { + 'opencode_send', + mode = { 'n', 'i' }, + }, + }, + }, + }, + }, + -- Required for `snacks` provider. + terminal = {} + } + }, }, config = function() ---@type opencode.Opts From 471d1cc24e5447688b08e22afa168be901b4216c Mon Sep 17 00:00:00 2001 From: Nick van Dyke Date: Mon, 16 Feb 2026 09:05:19 -0700 Subject: [PATCH 07/10] join some lines to make it shorter --- README.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index c36a0b3c..a8812462 100644 --- a/README.md +++ b/README.md @@ -37,17 +37,12 @@ Integrate the [opencode](https://github.com/sst/opencode) AI assistant with Neov -- Enhances `select()`. picker = { actions = { - opencode_send = function(...) - return require('opencode').snacks_picker_send(...) - end, + opencode_send = function(...) return require('opencode').snacks_picker_send(...) end, }, win = { input = { keys = { - [''] = { - 'opencode_send', - mode = { 'n', 'i' }, - }, + [''] = { 'opencode_send', mode = { 'n', 'i' } }, }, }, }, From b3649925737eb9257ec1d20e5035986952886b62 Mon Sep 17 00:00:00 2001 From: Nick van Dyke Date: Mon, 16 Feb 2026 09:06:21 -0700 Subject: [PATCH 08/10] words --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a8812462..0fc55421 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Integrate the [opencode](https://github.com/sst/opencode) AI assistant with Neov "nickjvandyke/opencode.nvim", dependencies = { { - -- Optional, but recommended. + -- `snacks.nvim` integration is recommended, but optional. ---@module 'snacks' <- Loads `snacks.nvim` types for configuration intellisense. "folke/snacks.nvim", optional = true, @@ -47,7 +47,7 @@ Integrate the [opencode](https://github.com/sst/opencode) AI assistant with Neov }, }, }, - -- Required for `snacks` provider. + -- Enables the `snacks` provider. terminal = {} } }, From 9a1ed5562a8963779cf6e5808219e24d02b54efc Mon Sep 17 00:00:00 2001 From: Nick van Dyke Date: Mon, 16 Feb 2026 09:07:58 -0700 Subject: [PATCH 09/10] comma --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0fc55421..79253b2e 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Integrate the [opencode](https://github.com/sst/opencode) AI assistant with Neov }, }, -- Enables the `snacks` provider. - terminal = {} + terminal = {}, } }, }, From 527a0f9a74e9f49e6407ca1db1f6df680d4346de Mon Sep 17 00:00:00 2001 From: Nick van Dyke Date: Mon, 16 Feb 2026 09:09:48 -0700 Subject: [PATCH 10/10] asdfwer --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 79253b2e..fcfc106f 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Integrate the [opencode](https://github.com/sst/opencode) AI assistant with Neov ## ✨ Features -- Connect to _any_ `opencode`s running in Neovim's CWD, or provide an integrated instance. +- Connect to _any_ `opencode` running in Neovim's CWD, or provide an integrated instance. - Share editor context (buffer, cursor, selection, diagnostics, etc.). - Input prompts with completions, highlights, and normal-mode support. - Select prompts from a library and define your own. @@ -15,8 +15,8 @@ Integrate the [opencode](https://github.com/sst/opencode) AI assistant with Neov - Reload edited buffers in real-time. - Monitor state via statusline component. - Forward Server-Sent-Events as autocmds for automation. -- Sensible defaults with well-documented, flexible configuration and API to fit your workflow. - _Vim-y_ — supports ranges and dot-repeat. +- Sensible defaults to get you started quickly. ## 📦 Setup