mirror of
https://github.com/neovim/neovim.git
synced 2026-07-31 12:49:11 +00:00
feat(dir): provider framework #40738
Problem: The core behaviors of `nvim.dir` cannot be reused by consumers such as the archive plugin, ssh browser, etc. Solution: - Define a basic "provider" shape. - Extract the filesystem provider.
This commit is contained in:
@@ -2,14 +2,38 @@
|
||||
--- Directory listing for `:edit <dir>`.
|
||||
|
||||
local api = vim.api
|
||||
local fs = vim.fs
|
||||
|
||||
local M = {}
|
||||
|
||||
---@type fun(buf: integer, dir: string)
|
||||
local first_open
|
||||
--- An entry rendered as one line in a listing buffer.
|
||||
---@class (private) nvim.dir.Entry
|
||||
---@field name string
|
||||
---@field dir boolean
|
||||
|
||||
local navigating = false
|
||||
--- Handler for `Provider.list`; call once with either an error or entries.
|
||||
---@alias (private) nvim.dir.ListHandler fun(err: string?, entries: nvim.dir.Entry[]?)
|
||||
|
||||
--- Source adapter that provides entries and listing actions.
|
||||
---@class (private) nvim.dir.Provider
|
||||
--- Produce entries for this listing.
|
||||
---@field list fun(buf: integer, name: string, cb: nvim.dir.ListHandler)
|
||||
--- Open an entry from the listing.
|
||||
---@field open fun(buf: integer, name: string, entry: nvim.dir.Entry)
|
||||
--- Open the parent listing.
|
||||
---@field open_parent fun(buf: integer, name: string)
|
||||
--- Run provider-specific buffer setup after a successful open.
|
||||
---@field init? fun(buf: integer, name: string)
|
||||
|
||||
---@class (private) nvim.dir.State
|
||||
---@field gen integer
|
||||
---@field provider? nvim.dir.Provider
|
||||
|
||||
local listing_group = api.nvim_create_augroup('nvim.dir.listing', { clear = false })
|
||||
|
||||
---@param err any
|
||||
local function notify_error(err)
|
||||
vim.notify('dir: ' .. tostring(err), vim.log.levels.ERROR)
|
||||
end
|
||||
|
||||
---@param buf integer
|
||||
---@param options [string, any][]
|
||||
@@ -24,53 +48,32 @@ local function set_buf_options(buf, options)
|
||||
return api.nvim_buf_is_valid(buf)
|
||||
end
|
||||
|
||||
---@param path string
|
||||
---@return string
|
||||
local function normalize_dir(path)
|
||||
return fs.normalize(fs.abspath(path))
|
||||
end
|
||||
|
||||
---@param name string
|
||||
---@return string
|
||||
local function encode_name(name)
|
||||
return (name:gsub('\n', '\0'))
|
||||
end
|
||||
|
||||
---@param line string
|
||||
---@param entry nvim.dir.Entry
|
||||
---@return string
|
||||
local function decode_line(line)
|
||||
if line:sub(-1) == '/' then
|
||||
line = line:sub(1, -2)
|
||||
end
|
||||
return (line:gsub('%z', '\n'))
|
||||
local function entry_line(entry)
|
||||
return encode_name(entry.name) .. (entry.dir and '/' or '')
|
||||
end
|
||||
|
||||
---@param entry nvim.dir.Entry
|
||||
local function select_entry(entry)
|
||||
local line = entry_line(entry)
|
||||
vim.fn.search([[\C\m^\V]] .. vim.fn.escape(line, [[\]]) .. [[\m$]], 'cw')
|
||||
end
|
||||
|
||||
---@param buf integer
|
||||
---@param dir string
|
||||
---@param name string
|
||||
---@param entries nvim.dir.Entry[]
|
||||
---@return boolean
|
||||
local function render(buf, dir)
|
||||
---@type { name: string, dir: boolean }[]
|
||||
local items = {}
|
||||
for name, type, err in fs.dir(dir, { err = true }) do
|
||||
if err then
|
||||
vim.notify('dir: ' .. err, vim.log.levels.ERROR)
|
||||
return false
|
||||
end
|
||||
if type == 'link' and vim.fn.isdirectory(fs.joinpath(dir, name)) == 1 then
|
||||
type = 'directory'
|
||||
end
|
||||
items[#items + 1] = { name = name, dir = type == 'directory' }
|
||||
end
|
||||
table.sort(items, function(a, b)
|
||||
if a.dir ~= b.dir then
|
||||
return a.dir
|
||||
end
|
||||
return a.name < b.name
|
||||
end)
|
||||
|
||||
local function render_entries(buf, name, entries)
|
||||
local lines = {} ---@type string[]
|
||||
for i, item in ipairs(items) do
|
||||
lines[i] = encode_name(item.name) .. (item.dir and '/' or '')
|
||||
for i, entry in ipairs(entries) do
|
||||
lines[i] = entry_line(entry)
|
||||
end
|
||||
|
||||
if
|
||||
@@ -88,7 +91,7 @@ local function render(buf, dir)
|
||||
api.nvim_buf_call(buf, function()
|
||||
api.nvim_cmd({
|
||||
cmd = 'file',
|
||||
args = { dir },
|
||||
args = { name },
|
||||
mods = { keepalt = true },
|
||||
magic = { file = false, bar = false },
|
||||
}, {})
|
||||
@@ -107,73 +110,59 @@ local function render(buf, dir)
|
||||
})
|
||||
end
|
||||
|
||||
--- Stop tracking a listing and remove its autocmds.
|
||||
---@param buf integer
|
||||
---@return string?
|
||||
local function entry_path(buf)
|
||||
local lnum = api.nvim_win_get_cursor(0)[1]
|
||||
local line = api.nvim_buf_get_lines(buf, lnum - 1, lnum, false)[1]
|
||||
if not line or line == '' then
|
||||
return nil
|
||||
end
|
||||
return fs.joinpath(api.nvim_buf_get_name(buf), decode_line(line))
|
||||
end
|
||||
|
||||
---@param path string
|
||||
local function edit(path)
|
||||
navigating = true
|
||||
api.nvim_cmd({ cmd = 'edit', args = { path }, magic = { file = false, bar = false } })
|
||||
navigating = false
|
||||
end
|
||||
|
||||
---@param buf integer
|
||||
local function reload(buf)
|
||||
local view = vim.fn.winsaveview()
|
||||
if render(buf, api.nvim_buf_get_name(buf)) then
|
||||
vim.fn.winrestview(view)
|
||||
end
|
||||
end
|
||||
|
||||
---@param path string
|
||||
local function navigate(path)
|
||||
edit(path)
|
||||
local buf = api.nvim_get_current_buf()
|
||||
local dir = normalize_dir(api.nvim_buf_get_name(buf))
|
||||
if vim.fn.isdirectory(dir) == 0 then
|
||||
local function close_listing(buf)
|
||||
if not api.nvim_buf_is_valid(buf) then
|
||||
return
|
||||
end
|
||||
if vim.b[buf].nvim_dir == nil then
|
||||
first_open(buf, dir)
|
||||
else
|
||||
reload(buf)
|
||||
end
|
||||
vim.b[buf].nvim_dir = nil
|
||||
api.nvim_clear_autocmds({ group = listing_group, buffer = buf })
|
||||
end
|
||||
|
||||
---@param buf integer
|
||||
local function open_entry(buf)
|
||||
local path = entry_path(buf)
|
||||
if path then
|
||||
navigate(path)
|
||||
---@return nvim.dir.State?
|
||||
local function get_state(buf)
|
||||
if not api.nvim_buf_is_valid(buf) then
|
||||
return nil
|
||||
end
|
||||
local state = vim.b[buf].nvim_dir
|
||||
return type(state) == 'table' and state or nil
|
||||
end
|
||||
|
||||
---@param buf integer
|
||||
local function open_parent(buf)
|
||||
local path = fs.normalize(api.nvim_buf_get_name(buf))
|
||||
local name = encode_name(fs.basename(path)) .. (vim.fn.isdirectory(path) == 1 and '/' or '')
|
||||
navigate(fs.dirname(path))
|
||||
vim.fn.search([[\C\m^\V]] .. vim.fn.escape(name, [[\]]) .. [[\m$]], 'cw')
|
||||
---@return nvim.dir.Entry?
|
||||
local function current_entry(buf)
|
||||
local state = get_state(buf)
|
||||
if not state or not state.provider or api.nvim_get_current_buf() ~= buf then
|
||||
return nil
|
||||
end
|
||||
local line = api.nvim_get_current_line()
|
||||
if line == '' then
|
||||
return nil
|
||||
end
|
||||
local dir = line:sub(-1) == '/'
|
||||
if dir then
|
||||
line = line:sub(1, -2)
|
||||
end
|
||||
if line == '' then
|
||||
return nil
|
||||
end
|
||||
return { name = line:gsub('%z', '\n'), dir = dir }
|
||||
end
|
||||
|
||||
function M._open_entry()
|
||||
open_entry(api.nvim_get_current_buf())
|
||||
end
|
||||
---@type fun(buf: integer, name: string, provider: nvim.dir.Provider, restore_view?: table, setup?: boolean, select?: nvim.dir.Entry)
|
||||
local load
|
||||
|
||||
function M._open_parent()
|
||||
open_parent(api.nvim_get_current_buf())
|
||||
end
|
||||
|
||||
function M._reload()
|
||||
reload(api.nvim_get_current_buf())
|
||||
---@param buf integer
|
||||
---@param provider nvim.dir.Provider
|
||||
local function reload(buf, provider)
|
||||
local state = get_state(buf)
|
||||
if not state or not state.provider then
|
||||
return
|
||||
end
|
||||
local restore_view = api.nvim_get_current_buf() == buf and vim.fn.winsaveview() or nil
|
||||
load(buf, api.nvim_buf_get_name(buf), provider, restore_view)
|
||||
end
|
||||
|
||||
---@param buf integer
|
||||
@@ -198,35 +187,149 @@ local function set_maps(buf)
|
||||
end
|
||||
|
||||
---@param buf integer
|
||||
---@param dir string
|
||||
function first_open(buf, dir)
|
||||
if not render(buf, dir) then
|
||||
return
|
||||
end
|
||||
if not api.nvim_buf_is_valid(buf) then
|
||||
return
|
||||
end
|
||||
vim.b[buf].nvim_dir = dir
|
||||
local function setup_render_autocmds(buf)
|
||||
api.nvim_clear_autocmds({ group = listing_group, buffer = buf })
|
||||
api.nvim_create_autocmd('BufReadCmd', {
|
||||
group = listing_group,
|
||||
buffer = buf,
|
||||
nested = true,
|
||||
desc = 'Reload directory listing',
|
||||
callback = function()
|
||||
if vim.b[buf].nvim_dir ~= nil then
|
||||
reload(buf)
|
||||
end
|
||||
M._reload(buf)
|
||||
end,
|
||||
})
|
||||
set_maps(buf)
|
||||
if api.nvim_get_option_value('filetype', { buf = buf }) ~= 'directory' then
|
||||
api.nvim_set_option_value('filetype', 'directory', { buf = buf })
|
||||
end
|
||||
|
||||
--- Request entries and render the current list generation.
|
||||
---@param buf integer
|
||||
---@param name string
|
||||
---@param provider nvim.dir.Provider
|
||||
---@param restore_view? table
|
||||
---@param setup? boolean
|
||||
---@param select? nvim.dir.Entry
|
||||
function load(buf, name, provider, restore_view, setup, select)
|
||||
local state = get_state(buf) or { gen = 0 }
|
||||
local list_gen = state.gen + 1
|
||||
state.gen = list_gen
|
||||
vim.b[buf].nvim_dir = state
|
||||
-- Discard the listing state if the initial load fails, but preserve an existing listing on reload failure.
|
||||
local first_render = state.provider == nil
|
||||
local done = false
|
||||
|
||||
---@param err string?
|
||||
---@param entries nvim.dir.Entry[]?
|
||||
local function on_list(err, entries)
|
||||
if done then
|
||||
return
|
||||
end
|
||||
done = true
|
||||
local current_state = get_state(buf)
|
||||
if not current_state or current_state.gen ~= list_gen then
|
||||
return
|
||||
end
|
||||
if err ~= nil then
|
||||
notify_error(err)
|
||||
if first_render then
|
||||
close_listing(buf)
|
||||
end
|
||||
return
|
||||
end
|
||||
---@cast entries nvim.dir.Entry[]
|
||||
|
||||
if not render_entries(buf, name, entries) then
|
||||
if first_render then
|
||||
close_listing(buf)
|
||||
end
|
||||
return
|
||||
end
|
||||
if restore_view and api.nvim_get_current_buf() == buf then
|
||||
vim.fn.winrestview(restore_view)
|
||||
end
|
||||
if select and api.nvim_get_current_buf() == buf then
|
||||
select_entry(select)
|
||||
end
|
||||
current_state.provider = provider
|
||||
vim.b[buf].nvim_dir = current_state
|
||||
|
||||
if not setup then
|
||||
return
|
||||
end
|
||||
|
||||
setup_render_autocmds(buf)
|
||||
set_maps(buf)
|
||||
if provider.init then
|
||||
provider.init(buf, name)
|
||||
end
|
||||
end
|
||||
|
||||
local ok, call_err = pcall(provider.list, buf, name, on_list) ---@type boolean, any
|
||||
if not ok then
|
||||
-- Route provider exceptions through the list handler so failures share one cleanup path.
|
||||
on_list(tostring(call_err), nil)
|
||||
end
|
||||
end
|
||||
|
||||
--- Open {buf} as a listing named {name} using {provider}.
|
||||
---@param buf integer
|
||||
---@param name string
|
||||
---@param provider nvim.dir.Provider
|
||||
---@param select? nvim.dir.Entry
|
||||
function M.open(buf, name, provider, select)
|
||||
buf = vim._resolve_bufnr(buf)
|
||||
local state = get_state(buf)
|
||||
local restore_view = state
|
||||
and state.provider
|
||||
and api.nvim_get_current_buf() == buf
|
||||
and vim.fn.winsaveview()
|
||||
or nil
|
||||
load(buf, name, provider, restore_view, true, select)
|
||||
end
|
||||
|
||||
---@param buf integer
|
||||
---@return nvim.dir.Provider?
|
||||
local function get_provider(buf)
|
||||
local state = get_state(buf)
|
||||
return state and state.provider or nil
|
||||
end
|
||||
|
||||
function M._open_entry()
|
||||
local buf = api.nvim_get_current_buf()
|
||||
local provider = get_provider(buf)
|
||||
local entry = current_entry(buf)
|
||||
if provider and entry then
|
||||
provider.open(buf, api.nvim_buf_get_name(buf), entry)
|
||||
end
|
||||
end
|
||||
|
||||
function M._open_parent()
|
||||
local buf = api.nvim_get_current_buf()
|
||||
local provider = get_provider(buf)
|
||||
if provider then
|
||||
provider.open_parent(buf, api.nvim_buf_get_name(buf))
|
||||
return
|
||||
end
|
||||
-- Keep the global `-` mapping useful from regular file buffers.
|
||||
require('nvim.dir.fs').open_parent_path(api.nvim_buf_get_name(buf))
|
||||
end
|
||||
|
||||
--- Reload the existing listing with its current buffer name and provider.
|
||||
--- Replace the lines and restore the view only after a successful list; preserve the existing
|
||||
--- listing on failure. Do not rerun provider initialization or reinstall listing handlers.
|
||||
---@param buf? integer
|
||||
function M._reload(buf)
|
||||
buf = vim._resolve_bufnr(buf)
|
||||
local provider = get_provider(buf)
|
||||
if provider then
|
||||
reload(buf, provider)
|
||||
end
|
||||
end
|
||||
|
||||
---@param buf integer
|
||||
---@param path string
|
||||
function M.try_open(buf, path)
|
||||
if navigating or path == '' then
|
||||
buf = vim._resolve_bufnr(buf)
|
||||
local fs_provider = require('nvim.dir.fs')
|
||||
if fs_provider.is_navigating() or path == '' then
|
||||
return
|
||||
end
|
||||
if vim.b[buf].nvim_dir ~= nil then
|
||||
@@ -242,7 +345,7 @@ function M.try_open(buf, path)
|
||||
if vim.fn.isdirectory(path) == 0 then
|
||||
return
|
||||
end
|
||||
first_open(buf, normalize_dir(path))
|
||||
M.open(buf, fs_provider.normalize(path), fs_provider)
|
||||
end
|
||||
|
||||
function M.handle_startup_dirs()
|
||||
|
||||
101
runtime/lua/nvim/dir/fs.lua
Normal file
101
runtime/lua/nvim/dir/fs.lua
Normal file
@@ -0,0 +1,101 @@
|
||||
-- Filesystem backend.
|
||||
|
||||
local api = vim.api
|
||||
local fs = vim.fs
|
||||
|
||||
local M = {}
|
||||
|
||||
local navigating = false
|
||||
|
||||
---@param path string
|
||||
---@return string
|
||||
function M.normalize(path)
|
||||
return fs.normalize(fs.abspath(path))
|
||||
end
|
||||
|
||||
---@return boolean
|
||||
function M.is_navigating()
|
||||
return navigating
|
||||
end
|
||||
|
||||
---@param path string
|
||||
local function edit(path)
|
||||
navigating = true
|
||||
local ok, err = pcall(api.nvim_cmd, {
|
||||
cmd = 'edit',
|
||||
args = { path },
|
||||
magic = { file = false, bar = false },
|
||||
})
|
||||
navigating = false
|
||||
if not ok then
|
||||
error(err, 0)
|
||||
end
|
||||
end
|
||||
|
||||
---@param path string
|
||||
---@param select? nvim.dir.Entry
|
||||
local function navigate(path, select)
|
||||
edit(path)
|
||||
local buf = api.nvim_get_current_buf()
|
||||
local dir = M.normalize(api.nvim_buf_get_name(buf))
|
||||
if vim.fn.isdirectory(dir) == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
require('nvim.dir').open(buf, dir, M, select)
|
||||
end
|
||||
|
||||
---@param path string
|
||||
function M.open_parent_path(path)
|
||||
path = M.normalize(path)
|
||||
navigate(fs.dirname(path), { name = fs.basename(path), dir = vim.fn.isdirectory(path) == 1 })
|
||||
end
|
||||
|
||||
---@param _ integer
|
||||
---@param path string
|
||||
---@param cb fun(err?: string, entries?: nvim.dir.Entry[])
|
||||
function M.list(_, path, cb)
|
||||
local entries = {} ---@type nvim.dir.Entry[]
|
||||
for name, type, err in fs.dir(path, { err = true }) do
|
||||
if err then
|
||||
cb(err)
|
||||
return
|
||||
end
|
||||
if type == 'link' and vim.fn.isdirectory(fs.joinpath(path, name)) == 1 then
|
||||
type = 'directory'
|
||||
end
|
||||
entries[#entries + 1] = {
|
||||
name = name,
|
||||
dir = type == 'directory',
|
||||
}
|
||||
end
|
||||
table.sort(entries, function(a, b)
|
||||
if a.dir ~= b.dir then
|
||||
return a.dir
|
||||
end
|
||||
return a.name < b.name
|
||||
end)
|
||||
cb(nil, entries)
|
||||
end
|
||||
|
||||
---@param _ integer
|
||||
---@param path string
|
||||
---@param entry nvim.dir.Entry
|
||||
function M.open(_, path, entry)
|
||||
navigate(fs.joinpath(path, entry.name))
|
||||
end
|
||||
|
||||
---@param _ integer
|
||||
---@param path string
|
||||
function M.open_parent(_, path)
|
||||
M.open_parent_path(path)
|
||||
end
|
||||
|
||||
---@param buf integer
|
||||
function M.init(buf)
|
||||
if api.nvim_get_option_value('filetype', { buf = buf }) ~= 'directory' then
|
||||
api.nvim_set_option_value('filetype', 'directory', { buf = buf })
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -190,6 +190,164 @@ describe('nvim.dir', function()
|
||||
assert_directory(root)
|
||||
end)
|
||||
|
||||
it('opens a custom listing provider', function()
|
||||
n.clear({ args_rm = { '-u' } })
|
||||
|
||||
exec_lua(function()
|
||||
require('nvim.dir').open(0, 'custom://root', {
|
||||
list = function(_, name, cb)
|
||||
vim.g.nvim_dir_list_name = name
|
||||
cb(nil, {
|
||||
{ name = 'child', dir = true },
|
||||
{ name = 'file.txt', dir = false },
|
||||
})
|
||||
end,
|
||||
open = function(_, name, entry)
|
||||
vim.g.nvim_dir_opened = entry.name .. ':' .. name
|
||||
end,
|
||||
open_parent = function(_, name)
|
||||
vim.g.nvim_dir_parent = name
|
||||
end,
|
||||
init = function(buf)
|
||||
vim.bo[buf].filetype = 'customdir'
|
||||
end,
|
||||
})
|
||||
end)
|
||||
|
||||
eq('custom://root', api.nvim_buf_get_name(0))
|
||||
eq('customdir', bufopt('filetype'))
|
||||
eq({ 'child/', 'file.txt' }, lines())
|
||||
eq('custom://root', exec_lua('return vim.g.nvim_dir_list_name'))
|
||||
|
||||
api.nvim_win_set_cursor(0, { 2, 0 })
|
||||
api.nvim_set_option_value('modifiable', true, { buf = 0 })
|
||||
api.nvim_set_current_line('renamed.txt')
|
||||
feed('<CR>')
|
||||
poke_eventloop()
|
||||
eq('renamed.txt:custom://root', exec_lua('return vim.g.nvim_dir_opened'))
|
||||
|
||||
feed('-')
|
||||
poke_eventloop()
|
||||
eq('custom://root', exec_lua('return vim.g.nvim_dir_parent'))
|
||||
end)
|
||||
|
||||
it('reports custom listing provider errors', function()
|
||||
n.clear({ args_rm = { '-u' } })
|
||||
|
||||
exec_lua(function()
|
||||
require('nvim.dir').open(0, 'custom://error', {
|
||||
list = function(_, _, cb)
|
||||
cb('simulated error')
|
||||
end,
|
||||
open = function() end,
|
||||
open_parent = function() end,
|
||||
})
|
||||
end)
|
||||
|
||||
ok(exec_capture('messages'):find('simulated error', 1, true) ~= nil)
|
||||
eq(false, exec_lua([[return vim.b.nvim_dir ~= nil]]))
|
||||
end)
|
||||
|
||||
it('reloads custom listing providers', function()
|
||||
n.clear({ args_rm = { '-u' } })
|
||||
|
||||
exec_lua(function()
|
||||
require('nvim.dir').open(0, 'custom://root', {
|
||||
list = function(buf, _, cb)
|
||||
vim.b[buf].custom_count = (vim.b[buf].custom_count or 0) + 1
|
||||
cb(nil, { { name = 'file' .. vim.b[buf].custom_count .. '.txt', dir = false } })
|
||||
end,
|
||||
open = function() end,
|
||||
open_parent = function() end,
|
||||
})
|
||||
end)
|
||||
|
||||
eq({ 'file1.txt' }, lines())
|
||||
feed('R')
|
||||
poke_eventloop()
|
||||
eq({ 'file2.txt' }, lines())
|
||||
end)
|
||||
|
||||
it('ignores callbacks from replaced listings', function()
|
||||
n.clear({ args_rm = { '-u' } })
|
||||
|
||||
exec_lua(function()
|
||||
local dir = require('nvim.dir')
|
||||
dir.open(0, 'custom://old', {
|
||||
list = function(_, _, cb)
|
||||
_G.nvim_dir_stale_callback = cb
|
||||
end,
|
||||
open = function() end,
|
||||
open_parent = function() end,
|
||||
})
|
||||
dir.open(0, 'custom://new', {
|
||||
list = function(_, _, cb)
|
||||
cb(nil, { { name = 'current.txt', dir = false } })
|
||||
end,
|
||||
open = function() end,
|
||||
open_parent = function() end,
|
||||
})
|
||||
end)
|
||||
|
||||
eq('custom://new', api.nvim_buf_get_name(0))
|
||||
eq({ 'current.txt' }, lines())
|
||||
|
||||
exec_lua(function()
|
||||
_G.nvim_dir_stale_callback(nil, { { name = 'stale.txt', dir = false } })
|
||||
end)
|
||||
|
||||
eq('custom://new', api.nvim_buf_get_name(0))
|
||||
eq({ 'current.txt' }, lines())
|
||||
end)
|
||||
|
||||
it('replaces listing providers', function()
|
||||
n.clear({ args_rm = { '-u' } })
|
||||
|
||||
exec_lua(function()
|
||||
local dir = require('nvim.dir')
|
||||
local function provider(label)
|
||||
return {
|
||||
list = function(buf, _, cb)
|
||||
local key = 'nvim_dir_' .. label .. '_lists'
|
||||
vim.b[buf][key] = (vim.b[buf][key] or 0) + 1
|
||||
vim.g.nvim_dir_provider_list = label .. ':' .. vim.b[buf][key]
|
||||
cb(nil, { { name = label .. '.txt', dir = false } })
|
||||
end,
|
||||
open = function(_, _, entry)
|
||||
vim.g.nvim_dir_provider_open = label .. ':' .. entry.name
|
||||
end,
|
||||
open_parent = function()
|
||||
vim.g.nvim_dir_provider_parent = label
|
||||
end,
|
||||
}
|
||||
end
|
||||
dir.open(0, 'custom://old', provider('old'))
|
||||
dir.open(0, 'custom://new', provider('new'))
|
||||
end)
|
||||
|
||||
eq({ 'new.txt' }, lines())
|
||||
eq('new:1', exec_lua('return vim.g.nvim_dir_provider_list'))
|
||||
for _, plug in ipairs({
|
||||
'<Plug>(nvim-dir-open)',
|
||||
'<Plug>(nvim-dir-up)',
|
||||
'<Plug>(nvim-dir-reload)',
|
||||
}) do
|
||||
eq(0, fn.maparg(plug, 'n', false, true).buffer)
|
||||
end
|
||||
|
||||
feed('<CR>')
|
||||
poke_eventloop()
|
||||
eq('new:new.txt', exec_lua('return vim.g.nvim_dir_provider_open'))
|
||||
|
||||
feed('-')
|
||||
poke_eventloop()
|
||||
eq('new', exec_lua('return vim.g.nvim_dir_provider_parent'))
|
||||
|
||||
feed('R')
|
||||
poke_eventloop()
|
||||
eq('new:2', exec_lua('return vim.g.nvim_dir_provider_list'))
|
||||
end)
|
||||
|
||||
it('maps - to open parent directories', function()
|
||||
make_fixture()
|
||||
n.clear({ args_rm = { '-u', '--cmd' } })
|
||||
|
||||
Reference in New Issue
Block a user