diff options
| author | Barrett Ruth <62671086+barrettruth@users.noreply.github.com> | 2026-09-12 09:01:41 +1000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-11 19:01:41 -0400 |
| commit | 4ceb92cd76d0234dd7b3ad775d94de46be108b21 (patch) | |
| tree | 818070b4e893bc5fc29450249cda575cdbb99323 | |
| parent | 361191790a3c55bc2079ab85ee92acc99eae44df (diff) | |
| download | rneovim-4ceb92cd76d0234dd7b3ad775d94de46be108b21.tar.gz rneovim-4ceb92cd76d0234dd7b3ad775d94de46be108b21.tar.bz2 rneovim-4ceb92cd76d0234dd7b3ad775d94de46be108b21.zip | |
feat(dir): open entries in splits with a, o mappings #41834
| -rw-r--r-- | runtime/doc/plugins.txt | 14 | ||||
| -rw-r--r-- | runtime/lua/nvim/dir.lua | 48 | ||||
| -rw-r--r-- | runtime/lua/nvim/dir/fs.lua | 9 | ||||
| -rw-r--r-- | test/functional/plugin/dir_spec.lua | 32 |
4 files changed, 76 insertions, 27 deletions
diff --git a/runtime/doc/plugins.txt b/runtime/doc/plugins.txt index 9f10625251..5a68e732a6 100644 --- a/runtime/doc/plugins.txt +++ b/runtime/doc/plugins.txt @@ -70,13 +70,19 @@ GLOBAL MAPPINGS *dir-mappings* BUFFER-LOCAL MAPPINGS *dir-buffer-mappings* • <CR> opens the file or directory under the cursor. +• a opens the file or directory under the cursor in a vertical split. +• o opens the file or directory under the cursor in a horizontal split. • - opens the parent directory. • R reloads the directory listing. -These keys map to <Plug>(nvim-dir-open), <Plug>(nvim-dir-up), and -<Plug>(nvim-dir-reload); map those to use different keys. Default mappings are -skipped when the target <Plug> mapping is already mapped. The default global and -directory-buffer "-" mappings are also skipped when "-" is already mapped. +a and o are available for local directories and keep focus in the listing. +'splitright' and 'splitbelow' control where the new window appears. + +These keys map to <Plug>(nvim-dir-open), <Plug>(nvim-dir-vsplit), +<Plug>(nvim-dir-split), <Plug>(nvim-dir-up), and <Plug>(nvim-dir-reload); map those +to use different keys. Default mappings are skipped when the target <Plug> +mapping is already mapped. The default "-", "a", and "o" mappings are also +skipped when their keys are already mapped. *dir-config* Directory buffers follow the global 'hidden' option by default. To delete them diff --git a/runtime/lua/nvim/dir.lua b/runtime/lua/nvim/dir.lua index ccce98e98c..c72d4d3b27 100644 --- a/runtime/lua/nvim/dir.lua +++ b/runtime/lua/nvim/dir.lua @@ -167,24 +167,15 @@ local function reload(buf, provider) end ---@param buf integer -local function set_maps(buf) - ---@param lhs string - ---@param plug string - local function map(lhs, plug) - if vim.fn.hasmapto(plug, 'n') == 0 then - 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 +---@param lhs string +---@param plug string +---@param force? boolean +function M._map(buf, lhs, plug, force) + api.nvim_buf_call(buf, function() + if (force or 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('<CR>', '<Plug>(nvim-dir-open)') - default_map('-', '<Plug>(nvim-dir-up)') - map('R', '<Plug>(nvim-dir-reload)') + end) end --- Let handlers reshape the rendered listing. Unlocks the buffer for the duration and @@ -286,7 +277,9 @@ function load(buf, name, provider, restore_view, setup, select) end setup_render_autocmds(buf) - set_maps(buf) + M._map(buf, '<CR>', '<Plug>(nvim-dir-open)', true) + M._map(buf, '-', '<Plug>(nvim-dir-up)') + M._map(buf, 'R', '<Plug>(nvim-dir-reload)', true) if provider.init then provider.init(buf, name) end @@ -326,12 +319,27 @@ local function get_provider(buf) return state and state.provider or nil end -function M._open_entry() +---@param cmd? 'split'|'vsplit' +function M._open_entry(cmd) 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) + if not provider or not entry then + return + end + local name = api.nvim_buf_get_name(buf) + local win = cmd and api.nvim_get_current_win() + local ok, err = pcall(function() + if cmd then + api.nvim_cmd({ cmd = cmd }, {}) + end + provider.open(buf, name, entry) + end) + if win and api.nvim_win_is_valid(win) then + api.nvim_set_current_win(win) + end + if not ok then + error(err, 0) end end diff --git a/runtime/lua/nvim/dir/fs.lua b/runtime/lua/nvim/dir/fs.lua index 0af9d3229f..9ff95ce8ad 100644 --- a/runtime/lua/nvim/dir/fs.lua +++ b/runtime/lua/nvim/dir/fs.lua @@ -102,6 +102,15 @@ function M.init(buf, path) if api.nvim_get_option_value('filetype', { buf = buf }) ~= 'directory' then api.nvim_set_option_value('filetype', 'directory', { buf = buf }) end + local dir = require('nvim.dir') + vim.keymap.set('n', '<Plug>(nvim-dir-vsplit)', function() + dir._open_entry('vsplit') + end, { buffer = buf, silent = true, desc = 'Open directory entry in a vertical split' }) + vim.keymap.set('n', '<Plug>(nvim-dir-split)', function() + dir._open_entry('split') + end, { buffer = buf, silent = true, desc = 'Open directory entry in a horizontal split' }) + dir._map(buf, 'a', '<Plug>(nvim-dir-vsplit)') + dir._map(buf, 'o', '<Plug>(nvim-dir-split)') api.nvim_buf_call(buf, function() pcall(api.nvim_cmd, { cmd = 'bcd', diff --git a/test/functional/plugin/dir_spec.lua b/test/functional/plugin/dir_spec.lua index b7318473c3..67cbb5ddd3 100644 --- a/test/functional/plugin/dir_spec.lua +++ b/test/functional/plugin/dir_spec.lua @@ -572,7 +572,7 @@ describe('nvim.dir', function() eq({ 'unsaved' }, api.nvim_buf_get_lines(old_buf, 0, -1, false)) end) - it('does not shadow startup plugin `-` mappings in directory buffers', function() + it('does not shadow startup plugin mappings in directory buffers', function() make_fixture() write_config_plugin( 'plugin/dirvish.lua', @@ -581,6 +581,8 @@ describe('nvim.dir', function() vim.keymap.set('n', '-', function() vim.g.dirvish_up = vim.g.dirvish_up + 1 end) + vim.keymap.set('n', 'a', '<Nop>') + vim.keymap.set('n', 's', '<Plug>(nvim-dir-split)') ]] ) @@ -591,12 +593,17 @@ describe('nvim.dir', function() edit(root) assert_directory(root) eq(0, fn.maparg('-', 'n', false, true).buffer) + eq('<Nop>', fn.maparg('a', 'n')) + eq('', fn.maparg('o', 'n')) - feed('-') + feed('-as') poke_eventloop() eq(1, exec_lua('return vim.g.dirvish_up')) assert_directory(root) + eq(2, #api.nvim_list_wins()) + feed('<C-W>p') + assert_directory(subdir) end) it('preserves alternate buffer when opening a parent directory', function() @@ -669,6 +676,22 @@ describe('nvim.dir', function() eq(vim.uv.fs_realpath(root), vim.uv.fs_realpath(fn.getcwd())) eq('alpha.txt', fn.findfile('alpha.txt')) + local win = api.nvim_get_current_win() + for key, entry in pairs({ a = 'alpha.txt', o = 'subdir/' }) do + local cursor = { line_of(entry), 0 } + api.nvim_win_set_cursor(0, cursor) + feed(key) + poke_eventloop() + eq(win, api.nvim_get_current_win()) + assert_directory(root) + eq(cursor, api.nvim_win_get_cursor(0)) + eq(2, #api.nvim_list_wins()) + eq(key == 'a' and 'row' or 'col', fn.winlayout()[1]) + feed('<C-W>p') + eq(root .. '/' .. entry, api.nvim_buf_get_name(0)) + command('close') + end + api.nvim_win_set_cursor(0, { line_of('alpha.txt'), 0 }) feed('<CR>') poke_eventloop() @@ -680,6 +703,9 @@ describe('nvim.dir', function() assert_directory(subdir) eq({ '' }, lines()) eq(vim.uv.fs_realpath(subdir), vim.uv.fs_realpath(fn.getcwd())) + feed('ao') + poke_eventloop() + eq(1, #api.nvim_list_wins()) feed('-') poke_eventloop() @@ -824,7 +850,7 @@ describe('nvim.dir', function() line_of(raw_name) end api.nvim_win_set_cursor(0, { line_of('line\0break.txt'), 0 }) - feed('<CR>') + feed('a<C-W>p') poke_eventloop() eq(root .. '/' .. name, api.nvim_buf_get_name(0)) |