Skip to content

Commit 57c0087

Browse files
authored
fix: add option to specify picker layout for snacks picker used in Opencode (#167)
* fix: add option to specify picker layout for snacks picker The default snacks picker layout is used for various sources that is not always ideal for this plugin's use case. E.g., many layouts have preview = 'file', which is useless for the session_picker. There's no way to disable preview just for Opencode's snacks picker without affecting other uses of snacks picker for other sources. * better handling of layout_opts in snacks_picker_ui * add documentation
1 parent 009c07d commit 57c0087

5 files changed

Lines changed: 73 additions & 13 deletions

File tree

README.md

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<img src="https://raw.githubusercontent.com/sst/opencode/dev/packages/web/src/assets/logo-ornate-dark.svg" alt="Opencode logo" width="30%" />
1111
</div>
1212

13-
### Quick buffer chat (<leader>o/) EXPERIMENTAL:
13+
### Quick buffer chat (<leader>o/) EXPERIMENTAL
1414

1515
This is an experimental feature that allows you to chat with the AI using the current buffer context. In visual mode, it captures the selected text as context, while in normal mode, it uses the current line. The AI will respond with quick edits to the files that are applied by the plugin.
1616

@@ -219,6 +219,9 @@ require('opencode').setup({
219219
wrap = false, -- Wraps text inside input window
220220
},
221221
},
222+
picker = {
223+
snacks_layout = nil -- `layout` opts to pass to Snacks.picker.pick({ layout = ... })
224+
},
222225
completion = {
223226
file_sources = {
224227
enabled = true,
@@ -371,6 +374,61 @@ Available icon keys (see implementation at lua/opencode/ui/icons.lua lines 7-29)
371374
- status_on, status_off
372375
- border, bullet
373376

377+
### Picker Layout
378+
379+
You can customize the layout of the picker used for history, session, references, and timeline
380+
381+
#### Snacks Picker Layout
382+
383+
There's 3 main ways on how to change the snacks picker layout
384+
385+
1. Don't specify the new options -> it'll just default to the user's snack picker layout preset from their snacks config
386+
2. Specify the new options for opencode, e.g.
387+
388+
```lua
389+
require("opencode").setup({
390+
ui = {
391+
picker = {
392+
---@module "snacks"
393+
---@type snacks.picker.layout.Config | nil
394+
snacks_layout = {
395+
layout = { border = "none", box = "vertical", ... }
396+
},
397+
},
398+
},
399+
})
400+
```
401+
402+
3. Specify a [builtin layout preset](https://github.com/folke/snacks.nvim/blob/main/docs/picker.md#%EF%B8%8F-layouts) for snacks picker OR a custom layout defined in your snacks config's `opts.picker.layouts`
403+
404+
```lua
405+
-- opencode.lua
406+
require("opencode").setup({
407+
ui = {
408+
picker = {
409+
---@module "snacks"
410+
---@type snacks.picker.layout.Config | nil
411+
snacks_layout = {
412+
preset = "custom_layout" -- or builtin snacks, like "select", "default", etc
413+
},
414+
},
415+
},
416+
})
417+
```
418+
419+
```lua
420+
-- snacks.lua
421+
{
422+
"folke/snacks.nvim",
423+
opts = {
424+
picker = {
425+
layouts = {
426+
custom_layout = {
427+
layout = { border = "none", box = "vertical", ... }
428+
-- ...
429+
}
430+
```
431+
374432
## 🧰 Usage
375433

376434
### Available Actions
@@ -458,7 +516,7 @@ Run a prompt in a new session using the Plan agent and disabling current file co
458516
:Opencode run "Fix the bug in the current file" model=github-copilot/claude-sonned-4
459517
```
460518

461-
##👮 Permissions
519+
## 👮 Permissions
462520

463521
Opencode can issue permission requests for potentially destructive operations (file edits, reverting files, running shell commands, or enabling persistent tool access). Permission requests appear inline in the output and must be responded to before the agent performs the action. Visit [Opencode Permissions Documentation](https://opencode.ai/docs/permissions/) for more details.
464522

lua/opencode/config.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ M.defaults = {
139139
-- Auto-hide input window when prompt is submitted or focus switches to output window
140140
auto_hide = false,
141141
},
142+
picker = {
143+
snacks_layout = nil,
144+
},
142145
completion = {
143146
file_sources = {
144147
enabled = true,

lua/opencode/types.lua

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
---@field input { text: { wrap: boolean } }
135135
---@field completion OpencodeCompletionConfig
136136
---@field highlights? OpencodeHighlightConfig
137+
---@field picker OpencodeUIPickerConfig
137138

138139
---@class OpencodeHighlightConfig
139140
---@field vertical_borders? { tool?: { fg?: string, bg?: string }, user?: { fg?: string, bg?: string }, assistant?: { fg?: string, bg?: string } }
@@ -149,6 +150,10 @@
149150
---@field rendering OpencodeUIOutputRenderingConfig
150151
---@field always_scroll_to_bottom boolean
151152

153+
---@class OpencodeUIPickerConfig
154+
---@field snacks_layout? snacks.picker.layout.Config
155+
--- TODO: add more picker-specific presets
156+
152157
---@class OpencodeContextConfig
153158
---@field enabled boolean
154159
---@field cursor_data { enabled: boolean, context_lines?: number }
@@ -506,13 +511,3 @@
506511
---@field messages number Number of messages reverted
507512
---@field tool_calls number Number of tool calls reverted
508513
---@field files table<string, {additions: number, deletions: number}> Summary of file changes reverted
509-
510-
---@class CodeReference
511-
---@field file_path string Relative or absolute file path
512-
---@field line number|nil Line number (1-indexed)
513-
---@field column number|nil Column number (optional)
514-
---@field message_id string ID of the message containing this reference
515-
---@field match_start number Start position of match in original text
516-
---@field match_end number End position of match in original text
517-
---@field file string Absolute file path (for Snacks picker preview)
518-
---@field pos number[]|nil Position as {line, col} for Snacks picker preview

lua/opencode/ui/base_picker.lua

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ local Promise = require('opencode.promise')
1818
---@field width? number Optional width for the picker (defaults to config or current window width)
1919
---@field multi_selection? table<string, boolean> Actions that support multi-selection
2020
---@field preview? "file"|"none"|false Preview mode: "file" for file preview, "none" or false to disable
21+
---@field layout_opts? OpencodeUIPickerConfig
2122

2223
---@class TelescopeEntry
2324
---@field value any
@@ -395,10 +396,12 @@ local function snacks_picker_ui(opts)
395396
local title = type(opts.title) == 'function' and opts.title() or opts.title
396397
---@cast title string
397398

399+
local layout_opts = opts.layout_opts and opts.layout_opts.snacks_layout or nil
400+
398401
---@type snacks.picker.Config
399402
local snack_opts = {
400403
title = title,
401-
layout = {
404+
layout = layout_opts or {
402405
config = function(layout)
403406
local width = opts.width and (opts.width + 3) or nil -- extra space for snacks UI
404407
if not has_preview then

lua/opencode/ui/session_picker.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ function M.pick(sessions, callback)
112112
callback = callback,
113113
title = 'Select A Session',
114114
width = config.ui.picker_width or 100,
115+
layout_opts = config.ui.picker,
115116
})
116117
end
117118

0 commit comments

Comments
 (0)