diff --git a/README.md b/README.md index b967537f..b258ccbd 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Opencode logo -### Quick buffer chat (o/) EXPERIMENTAL: +### Quick buffer chat (o/) EXPERIMENTAL 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. @@ -219,6 +219,9 @@ require('opencode').setup({ wrap = false, -- Wraps text inside input window }, }, + picker = { + snacks_layout = nil -- `layout` opts to pass to Snacks.picker.pick({ layout = ... }) + }, completion = { file_sources = { enabled = true, @@ -371,6 +374,61 @@ Available icon keys (see implementation at lua/opencode/ui/icons.lua lines 7-29) - status_on, status_off - border, bullet +### Picker Layout + +You can customize the layout of the picker used for history, session, references, and timeline + +#### Snacks Picker Layout + +There's 3 main ways on how to change the snacks picker layout + +1. Don't specify the new options -> it'll just default to the user's snack picker layout preset from their snacks config +2. Specify the new options for opencode, e.g. + + ```lua + require("opencode").setup({ + ui = { + picker = { + ---@module "snacks" + ---@type snacks.picker.layout.Config | nil + snacks_layout = { + layout = { border = "none", box = "vertical", ... } + }, + }, + }, + }) + ``` + +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` + + ```lua + -- opencode.lua + require("opencode").setup({ + ui = { + picker = { + ---@module "snacks" + ---@type snacks.picker.layout.Config | nil + snacks_layout = { + preset = "custom_layout" -- or builtin snacks, like "select", "default", etc + }, + }, + }, + }) + ``` + + ```lua + -- snacks.lua + { + "folke/snacks.nvim", + opts = { + picker = { + layouts = { + custom_layout = { + layout = { border = "none", box = "vertical", ... } + -- ... + } + ``` + ## 🧰 Usage ### Available Actions @@ -458,7 +516,7 @@ Run a prompt in a new session using the Plan agent and disabling current file co :Opencode run "Fix the bug in the current file" model=github-copilot/claude-sonned-4 ``` -##👮 Permissions +## 👮 Permissions 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. diff --git a/lua/opencode/config.lua b/lua/opencode/config.lua index 7a897862..060e72ef 100644 --- a/lua/opencode/config.lua +++ b/lua/opencode/config.lua @@ -135,6 +135,9 @@ M.defaults = { wrap = false, }, }, + picker = { + snacks_layout = nil, + }, completion = { file_sources = { enabled = true, diff --git a/lua/opencode/types.lua b/lua/opencode/types.lua index 1248eb27..310770dd 100644 --- a/lua/opencode/types.lua +++ b/lua/opencode/types.lua @@ -134,6 +134,7 @@ ---@field input { text: { wrap: boolean } } ---@field completion OpencodeCompletionConfig ---@field highlights? OpencodeHighlightConfig +---@field picker OpencodeUIPickerConfig ---@class OpencodeHighlightConfig ---@field vertical_borders? { tool?: { fg?: string, bg?: string }, user?: { fg?: string, bg?: string }, assistant?: { fg?: string, bg?: string } } @@ -149,6 +150,10 @@ ---@field rendering OpencodeUIOutputRenderingConfig ---@field always_scroll_to_bottom boolean +---@class OpencodeUIPickerConfig +---@field snacks_layout? snacks.picker.layout.Config +--- TODO: add more picker-specific presets + ---@class OpencodeContextConfig ---@field enabled boolean ---@field cursor_data { enabled: boolean, context_lines?: number } @@ -506,13 +511,3 @@ ---@field messages number Number of messages reverted ---@field tool_calls number Number of tool calls reverted ---@field files table Summary of file changes reverted - ----@class CodeReference ----@field file_path string Relative or absolute file path ----@field line number|nil Line number (1-indexed) ----@field column number|nil Column number (optional) ----@field message_id string ID of the message containing this reference ----@field match_start number Start position of match in original text ----@field match_end number End position of match in original text ----@field file string Absolute file path (for Snacks picker preview) ----@field pos number[]|nil Position as {line, col} for Snacks picker preview diff --git a/lua/opencode/ui/base_picker.lua b/lua/opencode/ui/base_picker.lua index 1a05dcb4..754d5329 100644 --- a/lua/opencode/ui/base_picker.lua +++ b/lua/opencode/ui/base_picker.lua @@ -18,6 +18,7 @@ local Promise = require('opencode.promise') ---@field width? number Optional width for the picker (defaults to config or current window width) ---@field multi_selection? table Actions that support multi-selection ---@field preview? "file"|"none"|false Preview mode: "file" for file preview, "none" or false to disable +---@field layout_opts? OpencodeUIPickerConfig ---@class TelescopeEntry ---@field value any @@ -395,10 +396,12 @@ local function snacks_picker_ui(opts) local title = type(opts.title) == 'function' and opts.title() or opts.title ---@cast title string + local layout_opts = opts.layout_opts and opts.layout_opts.snacks_layout or nil + ---@type snacks.picker.Config local snack_opts = { title = title, - layout = { + layout = layout_opts or { config = function(layout) local width = opts.width and (opts.width + 3) or nil -- extra space for snacks UI if not has_preview then diff --git a/lua/opencode/ui/session_picker.lua b/lua/opencode/ui/session_picker.lua index bfdfe97c..817cbc6f 100644 --- a/lua/opencode/ui/session_picker.lua +++ b/lua/opencode/ui/session_picker.lua @@ -112,6 +112,7 @@ function M.pick(sessions, callback) callback = callback, title = 'Select A Session', width = config.ui.picker_width or 100, + layout_opts = config.ui.picker, }) end