feat(picker): allow showing the preview in the main buffer

This commit is contained in:
Folke Lemaitre 2025-01-13 21:03:39 +01:00
parent 235c8cb683
commit deeacf77c0
No known key found for this signature in database
GPG key ID: 41F8B1FBACAE2040
5 changed files with 65 additions and 13 deletions

View file

@ -44,7 +44,7 @@ local M = {}
---@field reverse? boolean when true, the list will be reversed (bottom-up)
---@field fullscreen? boolean open in fullscreen
---@field cycle? boolean cycle through the list
---@field preview? boolean show preview window
---@field preview? boolean|"main" show preview window in the picker or the main window
---@field preset? string|fun(source:string):string
---@class snacks.picker.win.Config

View file

@ -17,6 +17,9 @@ function M.get(picker)
---@param t table<string, snacks.win.Action>
---@param k string
__index = function(t, k)
if type(k) ~= "string" then
return
end
local p = ref()
if not p then
return

View file

@ -82,9 +82,11 @@ function M.new(opts)
M._pickers[self] = true
M._active[self] = true
local layout = Snacks.picker.config.layout(self.opts)
self.list = require("snacks.picker.core.list").new(self)
self.input = require("snacks.picker.core.input").new(self)
self.preview = require("snacks.picker.core.preview").new(self.opts)
self.preview =
require("snacks.picker.core.preview").new(self.opts, layout.preview == "main" and self.parent_win or nil)
M.last = {
opts = self.opts,
@ -109,11 +111,10 @@ function M.new(opts)
end
end)
self:init_layout()
self:init_layout(layout)
self.input.win:on("VimResized", function()
vim.schedule(function()
local layout = Snacks.picker.config.layout(self.opts)
self:set_layout(layout)
self:set_layout(Snacks.picker.config.layout(self.opts))
end)
end)
@ -132,6 +133,12 @@ function M:init_layout(layout)
layout = layout or Snacks.picker.config.layout(self.opts)
self.resolved_layout = vim.deepcopy(layout)
local opts = layout --[[@as snacks.layout.Config]]
local preview_main = layout.preview == "main"
local preview_hidden = layout.preview == false or preview_main
local backdrop = nil
if preview_main then
backdrop = false
end
self.layout = Snacks.layout.new(vim.tbl_deep_extend("force", opts, {
win = {
wo = {
@ -141,13 +148,17 @@ function M:init_layout(layout)
wins = {
input = self.input.win,
list = self.list.win,
preview = self.preview.win,
preview = not preview_main and self.preview.win or nil,
},
hidden = { layout.preview == false and "preview" or nil },
hidden = { preview_hidden and "preview" or nil },
on_update = function()
self:update_titles()
end,
layout = {
backdrop = backdrop,
},
}))
self.preview:update(preview_main and self.parent_win or nil)
-- apply box highlight groups
local boxwhl = Snacks.picker.highlight.winhl("SnacksPickerBox")
for _, win in pairs(self.layout.box_wins) do
@ -246,6 +257,9 @@ function M:show()
end
self.shown = true
self.layout:show()
if self.preview.main then
self.preview.win:show()
end
self.input.win:focus()
end
@ -290,6 +304,7 @@ function M:close()
if (current == self.input.win.win or current == self.list.win.win) and vim.api.nvim_win_is_valid(self.parent_win) then
vim.api.nvim_set_current_win(self.parent_win)
end
self.preview.win:close()
self.layout:close()
self.updater:stop()
M._active[self] = nil

View file

@ -3,6 +3,8 @@
---@field win snacks.win
---@field previewer snacks.picker.Previewer
---@field state table<string, any>
---@field main? number
---@field win_opts {main: snacks.win.Config, layout: snacks.win.Config, win: snacks.win.Config}
local M = {}
M.__index = M
@ -18,26 +20,45 @@ local ns = vim.api.nvim_create_namespace("snacks.picker.preview")
local ns_loc = vim.api.nvim_create_namespace("snacks.picker.preview.loc")
---@param opts snacks.picker.Config
function M.new(opts)
---@param main? number
function M.new(opts, main)
local self = setmetatable({}, M)
self.win = Snacks.win(Snacks.win.resolve(
local win_opts = Snacks.win.resolve(
{
title_pos = "center",
},
opts.win.preview,
{
show = false,
enter = false,
width = 0,
height = 0,
fixbuf = false,
wo = {
winhighlight = Snacks.picker.highlight.winhl("SnacksPickerPreview"),
},
bo = { filetype = "snacks_picker_preview" },
on_win = function()
self.item = nil
self:reset()
end,
}
))
)
self.win_opts = {
main = {
relative = "win",
backdrop = false,
wo = {
winhighlight = "NormalFloat:Normal",
},
},
layout = {
backdrop = win_opts.backdrop == true,
relative = "win",
wo = {
winhighlight = Snacks.picker.highlight.winhl("SnacksPickerPreview"),
},
},
}
self.win = Snacks.win(win_opts)
self:update(main)
self.state = {}
self.win:on("WinClosed", function()
@ -51,6 +72,16 @@ function M.new(opts)
return self
end
---@param main? number
function M:update(main)
self.main = main
self.win_opts.main.win = main
self.win.opts = vim.tbl_deep_extend("force", self.win.opts, main and self.win_opts.main or self.win_opts.layout)
if self.win:valid() then
self.win:update()
end
end
---@param picker snacks.Picker
function M:preview(picker)
local item = picker:current()

View file

@ -522,6 +522,9 @@ end
---@param title string
---@param pos? "center"|"left"|"right"
function M:set_title(title, pos)
if not self:has_border() then
return
end
title = vim.trim(title)
if title ~= "" then
-- HACK: add extra space when last char is non word