From 9edf57e665820c5dff20425236fb309c4fb48ff6 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Thu, 16 Jul 2026 13:26:01 -0500 Subject: [PATCH] fix(dir): custom 3P directory-browser #40725 Problem: Third-party directory browsers do not have a documented way to take over local directory buffers from nvim.dir. Solution: Document deleting the nvim.dir augroup and handling FileType directory as the after-startup handoff, and avoid installing the built-in buffer-local "-" mapping when "-" is already mapped. --- runtime/doc/plugins.txt | 26 ++++++++++++++++++- runtime/lua/nvim/dir.lua | 9 ++++++- test/functional/plugin/dir_spec.lua | 40 +++++++++++++++++++---------- 3 files changed, 60 insertions(+), 15 deletions(-) diff --git a/runtime/doc/plugins.txt b/runtime/doc/plugins.txt index 2cd552aa8b..a924ca90b7 100644 --- a/runtime/doc/plugins.txt +++ b/runtime/doc/plugins.txt @@ -53,6 +53,28 @@ To disable the built-in directory browser, set this before startup: >lua vim.g.loaded_nvim_dir_plugin = 1 < +Replacing the directory browser *dir-replace-browser* + +To use another directory browser for the current session, delete the +`nvim.dir` autocommand group on or after |VimEnter| and handle |FileType| "directory": +>lua + vim.api.nvim_del_augroup_by_name('nvim.dir') + vim.api.nvim_create_autocmd('FileType', { + pattern = 'directory', + callback = function(args) + require('my_browser').open(args.buf, vim.api.nvim_buf_get_name(args.buf)) + end, + }) +< +This stops the built-in directory-opening autocommands. The plugin and its +mappings remain loaded. + +Define replacement keymaps explicitly, for example: >lua + vim.keymap.set('n', '-', function() + require('my_browser').open_parent() + end) +< + Mappings: *dir-mappings* > - Open the parent directory of the current file or directory. @@ -66,7 +88,9 @@ Directory buffer mappings: *dir-buffer-mappings* < These keys map to (nvim-dir-open), (nvim-dir-up), and -(nvim-dir-reload); map those to use different keys. +(nvim-dir-reload); map those to use different keys. Default mappings are +skipped when the target mapping is already mapped. The default global and +directory-buffer "-" mappings are also skipped when "-" is already mapped. The listing is read-only and does not modify the filesystem. diff --git a/runtime/lua/nvim/dir.lua b/runtime/lua/nvim/dir.lua index 3448fb3eab..daf5bd7a09 100644 --- a/runtime/lua/nvim/dir.lua +++ b/runtime/lua/nvim/dir.lua @@ -185,8 +185,15 @@ local function set_maps(buf) vim.keymap.set('n', lhs, plug, { buffer = buf, silent = true }) end end + ---@param lhs string + ---@param plug string + local function default_map(lhs, plug) + if vim.fn.mapcheck(lhs, 'n') == '' and vim.fn.hasmapto(plug, 'n') == 0 then + vim.keymap.set('n', lhs, plug, { buffer = buf, silent = true }) + end + end map('', '(nvim-dir-open)') - map('-', '(nvim-dir-up)') + default_map('-', '(nvim-dir-up)') map('R', '(nvim-dir-reload)') end diff --git a/test/functional/plugin/dir_spec.lua b/test/functional/plugin/dir_spec.lua index 1c6cd01d73..4bf1ec75e2 100644 --- a/test/functional/plugin/dir_spec.lua +++ b/test/functional/plugin/dir_spec.lua @@ -56,6 +56,15 @@ local function filesystem_root(path) return root end +local function write_config_plugin(path, text) + local plugin_file = vim.fs.joinpath(vim.fn.stdpath('config'), path) + vim.fs.mkdir(vim.fs.dirname(plugin_file), { parents = true }) + finally(function() + os.remove(plugin_file) + end) + t.write_file(plugin_file, text) +end + ---@param args? string[] ---@return string[] local function with_buftype_optionset(args) @@ -194,25 +203,30 @@ describe('nvim.dir', function() eq('alpha.txt', api.nvim_get_current_line()) end) - it('startup plugins can replace the `-` mapping', function() - local plugin_file = vim.fs.joinpath(vim.fn.stdpath('config'), 'plugin/dirvish.lua') - vim.fs.mkdir(vim.fs.dirname(plugin_file), { parents = true }) - finally(function() - os.remove(plugin_file) -- XXX: Remove file only, to avoid n.rmdir() hang on Windows. - end) - vim.fn.writefile( + it('does not shadow startup plugin `-` mappings in directory buffers', function() + make_fixture() + write_config_plugin( + 'plugin/dirvish.lua', [[ - if vim.fn.mapcheck('-', 'n') == '' and vim.fn.hasmapto('(dirvish_up)', 'n') == 0 then - vim.keymap.set('n', '-', '(dirvish_up)') - end - ]], - plugin_file + vim.g.dirvish_up = 0 + vim.keymap.set('n', '-', function() + vim.g.dirvish_up = vim.g.dirvish_up + 1 + end) + ]] ) n.clear({ args_rm = { '-u', '--cmd' } }) eq(1, fn.exists('g:loaded_nvim_dir_plugin')) -- Avoid false negatives. - eq('(dirvish_up)', fn.mapcheck('-', 'n')) + edit(root) + assert_directory(root) + eq(0, fn.maparg('-', 'n', false, true).buffer) + + feed('-') + poke_eventloop() + + eq(1, exec_lua('return vim.g.dirvish_up')) + assert_directory(root) end) it('preserves alternate buffer when opening a parent directory', function()