Another DiRectory EXplorer for Neovim
For showcase GIFs see here
- easily navigate through your file system
- split window and project drawer support
- add, copy, move, rename and delete elements
- mark and operate on multiple elements
- automatic file system synchronization
- powered by libuv
DREX requires Neovim version ≥ 0.7
Install DREX with your favorite plugin manager
use {
'theblob42/drex.nvim',
requires = 'kyazdani42/nvim-web-devicons', -- optional
}Plug 'theblob42/drex.nvim'
Plug 'kyazdani42/nvim-web-devicons' " optionalYou only need to install nvim-web-devicons if you like to have nice file type icons. The plugin works fine without it.
Open a DREX buffer in the current working directory
:Drex
You can also provide a target path
:Drex ~/projects
To open the parent directory of the current file
:Drex %:h
Check the manual for
cmdline-specialandfilename-modifiers
DREX also comes with a simple project drawer functionality
:DrexDrawerOpen
See
:help drex-commandsfor more available commands
To see the definition of all default keybindings see the configuration section
- Use
jandklike in any other VIM buffer to navigate up and down vis mapped toVbecause there is no need for charwise selection
Basic navigation
lexpands the current element- If it is a directory open its content in a subtree
- If it is a file open the file in the current window
<Right>and<2-LeftMouse>are alternative keybindings
hcollapses the current directories subtree- If the element under the cursor is an open directory collapse it
- Otherwise collapse the parent directory of the element
<Left>and<RightMouse>are alternative keybindings
<C-v>opens a file in a vertical split<C-x>opens a file in a horizontal split<C-t>opens a file in a new tab<F5>reloads the current directory (dependent on the cursor position)<C-h>opens a new DREX buffer in the parent directory of the current root<C-l>opens the directory under the cursor in a new DREX buffer
Jumping
gjjumps to the next siblinggkjumps to the previous siblingghjumps to the parent directory of the current element
Clipboard
mmarks or unmarks the current element (add or remove it from the clipboard)Mmarks the current element (add it to the clipboard)uunmarks the current element (remove it from the clipboard)ccclears the clipboard contentcsto show and edit the content of the clipboard in a floating window
File actions
sshows the stats for the current elementacreates a new file or directory- to create a new directory end your input with a
/(\on Windows) - non-existent parent directories will be created
(e.g.
foo/bar/filewill createfooandbarif they don't exist yet)
- to create a new directory end your input with a
ddeletes the element under the cursor (or the visual selection)Ddeletes all elements currently contained in the clipboardpcopies all elements from the clipboard to the path under the cursor- this will NOT clear the clipboard, so you can continue to paste elsewhere
Pmoves all elements from the clipboard to the path under the cursorrrenames the element under the cursor (or the visual selection)- this can move the element to another location
- non-existent parent directories will be created
(e.g.
foo/bar/filewill createfooandbarif they don't exist yet)
Rto multi rename all elements from the clipboard
Search
/search for visible elements (see:help drex-search)
Copy strings
ycopies the name of the element under the cursorYcopies the relative path of the element under the cursor<C-Y>copies the absolute path of the element under the cursor
In visual mode these copy all selected elements (separated by "\n")
There is no initial setup needed to use DREX
However you may configure certain settings to your liking
Check out :help drex-configuration for more details about the individual options
See also the wiki pages about configuration and custom actions for more information about further customization
Have a look at the default configuration
require('drex.config').configure {
icons = {
file_default = "",
dir_open = "",
dir_closed = "",
link = "",
others = "",
},
colored_icons = true,
hide_cursor = true,
hijack_netrw = false,
keepalt = false,
sorting = function(a, b)
local aname, atype = a[1], a[2]
local bname, btype = b[1], b[2]
local aisdir = atype == 'directory'
local bisdir = btype == 'directory'
if aisdir ~= bisdir then
return aisdir
end
return aname < bname
end,
drawer = {
side = 'left',
default_width = 30,
window_picker = {
enabled = true,
labels = 'abcdefghijklmnopqrstuvwxyz',
},
},
actions = {
files = {
delete_cmd = nil,
},
},
disable_default_keybindings = false,
keybindings = {
['n'] = {
['v'] = 'V',
['l'] = { '<cmd>lua require("drex.elements").expand_element()<CR>', { desc = 'expand element' }},
['h'] = { '<cmd>lua require("drex.elements").collapse_directory()<CR>', { desc = 'collapse directory' }},
['<right>'] = { '<cmd>lua require("drex.elements").expand_element()<CR>', { desc = 'expand element' }},
['<left>'] = { '<cmd>lua require("drex.elements").collapse_directory()<CR>', { desc = 'collapse directory'}},
['<2-LeftMouse>'] = { '<LeftMouse><cmd>lua require("drex.elements").expand_element()<CR>', { desc = 'expand element' }},
['<RightMouse>'] = { '<LeftMouse><cmd>lua require("drex.elements").collapse_directory()<CR>', { desc = 'collapse directory' }},
['<C-v>'] = { '<cmd>lua require("drex.elements").open_file("vs")<CR>', { desc = 'open file in vsplit' }},
['<C-x>'] = { '<cmd>lua require("drex.elements").open_file("sp")<CR>', { desc = 'open file in split' }},
['<C-t>'] = { '<cmd>lua require("drex.elements").open_file("tabnew", true)<CR>', { desc = 'open file in new tab' }},
['<C-l>'] = { '<cmd>lua require("drex.elements").open_directory()<CR>', { desc = 'open directory in new buffer' }},
['<C-h>'] = { '<cmd>lua require("drex.elements").open_parent_directory()<CR>', { desc = 'open parent directory in new buffer' }},
['<F5>'] = { '<cmd>lua require("drex").reload_directory()<CR>', { desc = 'reload' }},
['gj'] = { '<cmd>lua require("drex.actions.jump").jump_to_next_sibling()<CR>', { desc = 'jump to next sibling' }},
['gk'] = { '<cmd>lua require("drex.actions.jump").jump_to_prev_sibling()<CR>', { desc = 'jump to prev sibling' }},
['gh'] = { '<cmd>lua require("drex.actions.jump").jump_to_parent()<CR>', { desc = 'jump to parent element' }},
['s'] = { '<cmd>lua require("drex.actions.stats").stats()<CR>', { desc = 'show element stats' }},
['a'] = { '<cmd>lua require("drex.actions.files").create()<CR>', { desc = 'create element' }},
['d'] = { '<cmd>lua require("drex.actions.files").delete("line")<CR>', { desc = 'delete element' }},
['D'] = { '<cmd>lua require("drex.actions.files").delete("clipboard")<CR>', { desc = 'delete (clipboard)' }},
['p'] = { '<cmd>lua require("drex.actions.files").copy_and_paste()<CR>', { desc = 'copy & paste (clipboard)' }},
['P'] = { '<cmd>lua require("drex.actions.files").cut_and_move()<CR>', { desc = 'cut & move (clipboard)' }},
['r'] = { '<cmd>lua require("drex.actions.files").rename()<CR>', { desc = 'rename element' }},
['R'] = { '<cmd>lua require("drex.actions.files").multi_rename("clipboard")<CR>', { desc = 'rename (clipboard)' }},
['/'] = { '<cmd>keepalt lua require("drex.actions.search").search()<CR>', { desc = 'search' }},
['M'] = { '<cmd>DrexMark<CR>', { desc = 'mark element' }},
['u'] = { '<cmd>DrexUnmark<CR>', { desc = 'unmark element' }},
['m'] = { '<cmd>DrexToggle<CR>', { desc = 'toggle element' }},
['cc'] = { '<cmd>lua require("drex.clipboard").clear_clipboard()<CR>', { desc = 'clear clipboard' }},
['cs'] = { '<cmd>lua require("drex.clipboard").open_clipboard_window()<CR>', { desc = 'edit clipboard' }},
['y'] = { '<cmd>lua require("drex.actions.text").copy_name()<CR>', { desc = 'copy element name' }},
['Y'] = { '<cmd>lua require("drex.actions.text").copy_relative_path()<CR>', { desc = 'copy element relative path' }},
['<C-y>'] = { '<cmd>lua require("drex.actions.text").copy_absolute_path()<CR>', { desc = 'copy element absolute path' }},
},
['v'] = {
['d'] = { ':lua require("drex.actions.files").delete("visual")<CR>', { desc = 'delete elements' }},
['r'] = { ':lua require("drex.actions.files").multi_rename("visual")<CR>', { desc = 'rename elements' }},
['M'] = { ':DrexMark<CR>', { desc = 'mark elements' }},
['u'] = { ':DrexUnmark<CR>', { desc = 'unmark elements' }},
['m'] = { ':DrexToggle<CR>', { desc = 'toggle elements' }},
['y'] = { ':lua require("drex.actions.text").copy_name(true)<CR>', { desc = 'copy element names' }},
['Y'] = { ':lua require("drex.actions.text").copy_relative_path(true)<CR>', { desc = 'copy element relative paths' }},
['<C-y>'] = { ':lua require("drex.actions.text").copy_absolute_path(true)<CR>', { desc = 'copy element absolute paths' }},
}
},
on_enter = nil,
on_leave = nil,
}Like vim-dirvish every line is just a file path hidden via conceal (plus indentation and an icon). For file system scanning, file interactions (add, delete, rename, etc.) and monitoring DREX uses libuv which is exposed via vim.loop
See also :help drex-customization and the Wiki for more information and examples
Contributions are very welcome :-) doesn't matter if it's a bug, a new feature or an addition/change to the wiki. Just go ahead and open an issue or a pull-request to kick off the discussion about it
In regards to code changes and pull-requests please consider the following points:
- follow the conventional commits guidelines for your commit messages
- make sure you're code is properly formatted using StyLua
- make sure you have the
lua52version installed, otherwise there will be problems withgotostatements (see here)
- make sure you have the