feat(explorer): new explorer module with shortcut to start explorer picker and netrw replacement functionlity

This commit is contained in:
Folke Lemaitre 2025-01-31 08:31:49 +01:00
parent 5420a64b66
commit 670c67366f
No known key found for this signature in database
GPG key ID: 41F8B1FBACAE2040
6 changed files with 104 additions and 9 deletions

78
lua/snacks/explorer.lua Normal file
View file

@ -0,0 +1,78 @@
---@class snacks.explorer
---@overload fun(opts?: snacks.picker.explorer.Config): snacks.Picker
local M = setmetatable({}, {
__call = function(M, ...)
return M.open(...)
end,
})
M.meta = {
desc = "A file explorer (picker in disguise)",
needs_setup = true,
}
--- These are just the general explorer settings.
--- To configure the explorer picker, see `snacks.picker.explorer.Config`
---@class snacks.explorer.Config
local defaults = {
replace_netrw = true, -- Replace netrw with the snacks explorer
}
---@param event? vim.api.keyset.create_autocmd.callback_args
function M.setup(event)
local opts = Snacks.config.get("explorer", defaults)
if opts.replace_netrw then
-- Disable netrw
vim.g.loaded_netrw = 1
vim.g.loaded_netrwPlugin = 1
pcall(vim.api.nvim_del_augroup_by_name, "FileExplorer")
local group = vim.api.nvim_create_augroup("snacks.explorer", { clear = true })
local function handle(ev)
if ev.file ~= "" and vim.fn.isdirectory(ev.file) == 1 then
local picker = M.open({ cwd = ev.file })
local ref = picker:ref()
if vim.v.vim_did_enter == 0 then
-- clear bufname so we don't try loading this one again
vim.api.nvim_buf_set_name(ev.buf, "")
picker:show()
-- focus on UIEnter, since focusing before doesn't work
vim.api.nvim_create_autocmd("UIEnter", {
once = true,
group = group,
callback = function()
local p = ref()
if p then
p:_focus()
end
end,
})
else
-- after vim has entered, we also need to delete the directory buffer
-- use bufdelete to keep the window layout
Snacks.bufdelete.delete(ev.buf)
end
end
end
-- event from snacks loader
if event then
handle(event)
end
-- Open the explorer when opening a directory
vim.api.nvim_create_autocmd("BufEnter", {
group = group,
callback = handle,
})
end
end
--- Shortcut to open the explorer picker
---@param opts? snacks.picker.explorer.Config|{}
function M.open(opts)
return Snacks.picker.explorer(opts)
end
return M

View file

@ -131,17 +131,25 @@ function M.setup(opts)
local events = {
BufReadPre = { "bigfile" },
BufReadPost = { "quickfile", "indent" },
BufEnter = { "explorer" },
LspAttach = { "words" },
UIEnter = { "dashboard", "scroll", "input", "scope", "picker" },
}
local function load(event)
for _, snack in ipairs(events[event] or {}) do
---@param event string
---@param ev? vim.api.keyset.create_autocmd.callback_args
local function load(event, ev)
local todo = events[event] or {}
events[event] = nil
for _, snack in ipairs(todo) do
if M.config[snack] and M.config[snack].enabled then
(M[snack].setup or M[snack].enable)()
if M[snack].setup then
M[snack].setup(ev)
elseif M[snack].enable then
M[snack].enable()
end
end
end
events[event] = nil
end
if vim.v.vim_did_enter == 1 then
@ -154,7 +162,7 @@ function M.setup(opts)
once = true,
nested = true,
callback = function(ev)
load(ev.event)
load(ev.event, ev)
end,
})

View file

@ -7,6 +7,7 @@
---@field dashboard snacks.dashboard
---@field debug snacks.debug
---@field dim snacks.dim
---@field explorer snacks.explorer
---@field git snacks.git
---@field gitbrowse snacks.gitbrowse
---@field health snacks.health
@ -37,6 +38,7 @@
---@field bigfile? snacks.bigfile.Config|{}
---@field dashboard? snacks.dashboard.Config|{}
---@field dim? snacks.dim.Config|{}
---@field explorer? snacks.explorer.Config|{}
---@field gitbrowse? snacks.gitbrowse.Config|{}
---@field indent? snacks.indent.Config|{}
---@field input? snacks.input.Config|{}

View file

@ -37,7 +37,7 @@ M.buffers = {
},
}
---@class snacks.picker.explorer.Config: snacks.picker.files.Config
---@class snacks.picker.explorer.Config: snacks.picker.files.Config|{}
---@field follow_file? boolean follow the file from the current buffer
---@field tree? boolean show the file tree (default: true)
M.explorer = {

View file

@ -467,14 +467,18 @@ function M:show()
if self.preview.main then
self.preview.win:show()
end
self:_focus()
if self.opts.on_show then
self.opts.on_show(self)
end
end
function M:_focus()
if self.opts.focus == "input" then
self.input.win:focus()
elseif self.opts.focus == "list" then
self.list.win:focus()
end
if self.opts.on_show then
self.opts.on_show(self)
end
end
---@param item snacks.picker.Item?

View file

@ -1,5 +1,8 @@
local M = {}
---@class snacks.picker
---@field explorer fun(opts?: snacks.picker.explorer.Config): snacks.Picker
---@type table<snacks.Picker, snacks.picker.explorer.State>
M._state = setmetatable({}, { __mode = "k" })
local uv = vim.uv or vim.loop