feat: automated migration from view.mappings.list to on_attach, see https://github.com/nvim-tree/nvim-tree.lua/wiki/Migrating-To-on_attach (#1579)

* chore(mappings): migrate legacy mappings under the hood

* chore(mappings): POC for help and :help on_attach keymaps

* chore(mappings): POC for help and :help on_attach keymaps

* chore(mappings): add desc to all mappings, show in help, reformat help

* chore(mappings): add desc to all mappings

* chore(mappings): add desc to all mappings

* chore(mappings): escape help keys

* chore(mappings): migrate legacy mappings under the hood: map keymap to legacy mappings

* chore(mappings): migrate legacy mappings under the hood: remove dispatch

* Revert "chore(mappings): migrate legacy mappings under the hood: remove dispatch"

This reverts commit f6f439ba59.

* chore(mappings): migrate legacy mappings under the hood: pass node to action_cb

* chore(mappings): migrate legacy mappings under the hood: remove dispatch

* chore(mappings): migrate legacy mappings under the hood: replace mappigns with keymaps in help

* chore(mappings): generate on_attach from user's legacy mappings

* chore(mappings): generate on_attach from user's legacy mappings

* chore(mappings): merge cleanup

* chore(mappings): use default mappings when on_attach not present, log legacy migration

* on_attach is default or user only, legacy and generation includes defaults (#1777)

* chore(mappings): remove mappings via vim.keymap.del instead of filtering mappings, to allow for multiple ways of specifying a key

* doc: specify that the terminal emulator must be configured to use the patched font

* feat(renderer): add NvimTreeOpenedFolderIcon NvimTreeClosedFolderIcon (#1768)

* feat: Add highlight group for opened folder

closes #1674

* docs: Add NvimTreeOpenedFolderIcon default

* feat: Add NvimTreeClosedFolderIcon highlight group

Defaults to NvimTreeFolderIcon

* feat: add diagnostics.show_on_open_dirs git.show_on_open_dirs (#1778)

* feat(diagnostics): only show diagnostic on closed folder

* feat(git): only show git icon on closed folder

* docs: Update feature_request.md (#1788)

* Update feature_request.md

Closes #1654

* Update feature_request.md

Co-authored-by: Alexander Courtis <alex@courtis.org>

* 1786 git next prev land on dirs (#1787)

* Filtered dir with git status that are open when show_on_open_dir is false

* refactored for single source of truth of existence of git status on a node

Putting `has_git_status()` in `explorer.common` because that's where node.status is constructed
Or at least I think that's where it's constructed

* 1786 semantic nit

Co-authored-by: Alexander Courtis <alex@courtis.org>

* fix(git): git rename not showing up for the renamed file (#1783)

* fixed git rename not showing up for the renamed file

* considered " -> " being a part of the filename

Fixed -> pattern to escape -
Fixed "\"" and "\\" in filename

* using string.find(, , true) to match plain ->

* Using -z and removed unnecessary logic

* feat(view): always enable cursorline, users may change this behaviour via Event.TreeOpen (#1814)

* Update view.lua

* set cursorline to true

* feat(event): dispatch Event.NodeRenamed on cut-paste (#1817)

* feat(view): add filters.git_clean, filters.no_buffer (#1784)

* feat(view): add filters.git_clean

* feat(view): add filters.git_clean

* feat(view): add filters.no_buffer

* feat(view): filters.no_buffer misses unloaded, handles buffer in/out

* feat(view): filters.no_buffer matches directories specifically

* feat(view): filters.no_buffer clarify targets

* feat: add placeholder filters.diagnostics_ok, refactor filters

* feat(view): remove placeholder filters.diagnostics_ok

* doc: consolidate and clarify :help examples

* doc: format help

* feat: paste and create always target closed folder, remove create_in_closed_folder (#1802)

* Fix default for file creation in closed directories

* Make paste in closed directories consistent with create

* doc: clarify create_in_closed_folder

* Remove create_in_closed_folder option

* doc: clarify create_in_closed_folder removal message (whoops)

Co-authored-by: Alexander Courtis <alex@courtis.org>

* on_attach is user's or default, nothing else; legacy generated on_attach includes defaults

Co-authored-by: baahrens <bahrens@compeon.de>
Co-authored-by: Richard Li <38484873+chomosuke@users.noreply.github.com>
Co-authored-by: gegoune <69750637+gegoune@users.noreply.github.com>
Co-authored-by: rishabhjain9191 <rishabh.jain9191@gmail.com>
Co-authored-by: Anton <14187674+antosha417@users.noreply.github.com>
Co-authored-by: Eric Haynes <ehaynes99@gmail.com>

* on_attach_default hardcoded

* format default_on_attach

* source default on_attach directly

* remove human mappings help

* simplified on_attach generation

* simplified on_attach generation

* generate default on_attach

* generate default on_attach

* split out keymap_legacy

* add recently introduced mappings

* legacy api.config.mappings.active and default

* legacy api.config.mappings.active and default

* on_attach help and readme

* legacy generate handles action = ""

* legacy generate handles action =

* legacy generate gives defaults when no user mappings

* legacy generate handles action = ""

* legacy generate api handles overrides

* legacy generate handles subsequent setup, on_attach retains deep copies of legacy config

* add wiki link to generated on_attach

* add opts helper function for on_attach, prefixing 'nvim-tree: '

---------

Co-authored-by: kiyan <yazdani.kiyan@protonmail.com>
Co-authored-by: baahrens <bahrens@compeon.de>
Co-authored-by: Richard Li <38484873+chomosuke@users.noreply.github.com>
Co-authored-by: gegoune <69750637+gegoune@users.noreply.github.com>
Co-authored-by: rishabhjain9191 <rishabh.jain9191@gmail.com>
Co-authored-by: Anton <14187674+antosha417@users.noreply.github.com>
Co-authored-by: Eric Haynes <ehaynes99@gmail.com>
This commit is contained in:
Alexander Courtis 2023-02-27 14:19:50 +11:00 committed by GitHub
parent 9c97e6449b
commit 74959750f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 767 additions and 1175 deletions

View File

@ -30,6 +30,10 @@ Take a look at the [wiki](https://github.com/nvim-tree/nvim-tree.lua/wiki) for S
Existing `*_on_setup*` mechanisms have been removed in favour of [Open At Startup](https://github.com/nvim-tree/nvim-tree.lua/wiki/Open-At-Startup) Existing `*_on_setup*` mechanisms have been removed in favour of [Open At Startup](https://github.com/nvim-tree/nvim-tree.lua/wiki/Open-At-Startup)
## New Mapping Method 2023-02-27
[:help nvim-tree.view.mappings](doc/nvim-tree-lua.txt) have been deprecated in favour of [:help nvim-tree.on_attach](doc/nvim-tree-lua.txt). Please visit [Migrating To on_attach](https://github.com/nvim-tree/nvim-tree.lua/wiki/Migrating-To-on_attach) to transition.
## Requirements ## Requirements
[neovim >=0.8.0](https://github.com/neovim/neovim/wiki/Installing-Neovim) [neovim >=0.8.0](https://github.com/neovim/neovim/wiki/Installing-Neovim)
@ -77,14 +81,6 @@ require("nvim-tree").setup()
-- OR setup with some options -- OR setup with some options
require("nvim-tree").setup({ require("nvim-tree").setup({
sort_by = "case_sensitive", sort_by = "case_sensitive",
view = {
width = 30,
mappings = {
list = {
{ key = "u", action = "dir_up" },
},
},
},
renderer = { renderer = {
group_empty = true, group_empty = true,
}, },
@ -96,7 +92,7 @@ require("nvim-tree").setup({
For complete list of available configuration options see [:help nvim-tree-setup](doc/nvim-tree-lua.txt) For complete list of available configuration options see [:help nvim-tree-setup](doc/nvim-tree-lua.txt)
Each option is documented in `:help nvim-tree.OPTION_NAME`. Nested options can be accessed by appending `.`, for example [:help nvim-tree.view.mappings](doc/nvim-tree-lua.txt) Each option is documented in `:help nvim-tree.OPTION_NAME`. Nested options can be accessed by appending `.`, for example [:help nvim-tree.filters.dotfiles](doc/nvim-tree-lua.txt)
## Commands ## Commands
@ -114,10 +110,10 @@ Basic commands:
## Mappings ## Mappings
nvim-tree comes with number of mappings; for default mappings please see [:help nvim-tree-default-mappings](doc/nvim-tree-lua.txt), for way of configuring mappings see [:help nvim-tree-mappings](doc/nvim-tree-lua.txt)
`g?` toggles help, showing all the mappings and their actions. `g?` toggles help, showing all the mappings and their actions.
To customise your mappings see [:help nvim-tree.on_attach](doc/nvim-tree-lua.txt) and [:help nvim-tree-mappings](doc/nvim-tree-lua.txt)
## Roadmap ## Roadmap
nvim-tree is stable and new major features will not be added. The focus is on existing user experience. nvim-tree is stable and new major features will not be added. The focus is on existing user experience.
@ -133,25 +129,13 @@ Development is focused on:
## API ## API
nvim-tree exposes a public API. This is non breaking, with additions made as necessary. nvim-tree exposes a public API. This is non breaking, with additions made as necessary. See [:help nvim-tree-api](doc/nvim-tree-lua.txt)
See wiki [Recipes](https://github.com/nvim-tree/nvim-tree.lua/wiki/Recipes) and [Tips](https://github.com/nvim-tree/nvim-tree.lua/wiki/Tips) for ideas and insipration. See wiki [Recipes](https://github.com/nvim-tree/nvim-tree.lua/wiki/Recipes) and [Tips](https://github.com/nvim-tree/nvim-tree.lua/wiki/Tips) for ideas and insipration.
Please raise a [feature request](https://github.com/nvim-tree/nvim-tree.lua/issues/new?assignees=&labels=feature+request&template=feature_request.md&title=) if the API is insufficent for your needs. [Contributions](#Contributing) are always welcome. Please raise a [feature request](https://github.com/nvim-tree/nvim-tree.lua/issues/new?assignees=&labels=feature+request&template=feature_request.md&title=) if the API is insufficent for your needs. [Contributions](#Contributing) are always welcome.
[:help nvim-tree-api](doc/nvim-tree-lua.txt) You may also subscribe to events that nvim-tree will dispatch in a variety of situations, see [:help nvim-tree-events](doc/nvim-tree-lua.txt)
### Events
Users may subscribe to events that nvim-tree will dispatch in a variety of situations.
[:help nvim-tree-events](doc/nvim-tree-lua.txt)
### Actions
Custom actions may be mapped which can invoke API or perform your own actions.
[:help nvim-tree-mappings](doc/nvim-tree-lua.txt)
## Contributing ## Contributing

View File

@ -11,6 +11,8 @@ CONTENTS *nvim-tree*
4. Setup/Configuration |nvim-tree-setup| 4. Setup/Configuration |nvim-tree-setup|
5. Api |nvim-tree-api| 5. Api |nvim-tree-api|
6. Mappings |nvim-tree-mappings| 6. Mappings |nvim-tree-mappings|
6.1 Default Mappings |nvim-tree-mappings-default|
6.2 Legacy Mappings |nvim-tree-mappings-legacy|
7. Highlight Groups |nvim-tree-highlight| 7. Highlight Groups |nvim-tree-highlight|
8. Events |nvim-tree-events| 8. Events |nvim-tree-events|
9. Bookmarks |nvim-tree-bookmarks| 9. Bookmarks |nvim-tree-bookmarks|
@ -99,27 +101,27 @@ Setup should be run in a lua file or in a |lua-heredoc| if using in a vim file.
============================================================================== ==============================================================================
3. COMMANDS *nvim-tree-commands* 3. COMMANDS *nvim-tree-commands*
|:NvimTreeOpen| *:NvimTreeOpen*
opens the tree. Takes an optional path argument. opens the tree. Takes an optional path argument.
|:NvimTreeClose| *:NvimTreeClose*
closes the tree closes the tree
|:NvimTreeToggle| *:NvimTreeToggle*
open or close the tree. Takes an optional path argument. open or close the tree. Takes an optional path argument.
|:NvimTreeFocus| *:NvimTreeFocus*
open the tree if it is closed, and then focus on the tree open the tree if it is closed, and then focus on the tree
|:NvimTreeRefresh| *:NvimTreeRefresh*
refresh the tree refresh the tree
|:NvimTreeFindFile| *:NvimTreeFindFile*
The command will change the cursor in the tree for the current bufname. The command will change the cursor in the tree for the current bufname.
@ -129,7 +131,7 @@ Setup should be run in a lua file or in a |lua-heredoc| if using in a vim file.
Invoke with a bang `:NvimTreeFindFile!` to update the root. Invoke with a bang `:NvimTreeFindFile!` to update the root.
|:NvimTreeFindFileToggle| *:NvimTreeFindFileToggle*
close the tree or change the cursor in the tree for the current bufname, close the tree or change the cursor in the tree for the current bufname,
similar to combination of |:NvimTreeToggle| and |:NvimTreeFindFile|. Takes an similar to combination of |:NvimTreeToggle| and |:NvimTreeFindFile|. Takes an
@ -137,11 +139,11 @@ Setup should be run in a lua file or in a |lua-heredoc| if using in a vim file.
Invoke with a bang `:NvimTreeFindFileToggle!` to update the root. Invoke with a bang `:NvimTreeFindFileToggle!` to update the root.
|:NvimTreeClipboard| *:NvimTreeClipboard*
Print clipboard content for both cut and copy Print clipboard content for both cut and copy
|:NvimTreeResize| *:NvimTreeResize*
Resize the NvimTree window to the given size. Example: `:NvimTreeResize 50` Resize the NvimTree window to the given size. Example: `:NvimTreeResize 50`
resizes the window to the width of 50. If the size starts with "+" or "-" it resizes the window to the width of 50. If the size starts with "+" or "-" it
@ -149,15 +151,21 @@ Setup should be run in a lua file or in a |lua-heredoc| if using in a vim file.
Example `:NvimTreeResize -20` removes the value 20 from the current width. And Example `:NvimTreeResize -20` removes the value 20 from the current width. And
`:NvimTreeResize +20` adds the value 20 to the current width. `:NvimTreeResize +20` adds the value 20 to the current width.
|:NvimTreeCollapse| *:NvimTreeCollapse*
Collapses the nvim-tree recursively. Collapses the nvim-tree recursively.
|:NvimTreeCollapseKeepBuffers| *:NvimTreeCollapseKeepBuffers*
Collapses the nvim-tree recursively, but keep the directories open, which are Collapses the nvim-tree recursively, but keep the directories open, which are
used in an open buffer. used in an open buffer.
*:NvimTreeGenerateOnAttach*
Creates and opens a new file `/tmp/my_on_attach.lua` containing an
|nvim-tree.on_attach| function based on your |nvim-tree.view.mappings|,
|nvim-tree.remove_keymaps| as well as the defaults.
See https://github.com/nvim-tree/nvim-tree.lua/wiki/Migrating-To-on_attach
============================================================================== ==============================================================================
4. SETUP *nvim-tree-setup* 4. SETUP *nvim-tree-setup*
@ -184,7 +192,7 @@ Subsequent calls to setup will replace the previous configuration.
sync_root_with_cwd = false, sync_root_with_cwd = false,
reload_on_bufenter = false, reload_on_bufenter = false,
respect_buf_cwd = false, respect_buf_cwd = false,
on_attach = "disable", on_attach = "default",
remove_keymaps = false, remove_keymaps = false,
select_prompts = false, select_prompts = false,
view = { view = {
@ -682,22 +690,13 @@ performance.
Type: {string}, Default: `{}` Type: {string}, Default: `{}`
*nvim-tree.on_attach* *nvim-tree.on_attach*
Function ran when creating the nvim-tree buffer. Runs when creating the nvim-tree buffer. Use this to set your nvim-tree
This can be used to attach keybindings to the tree buffer. specific mappings. See |nvim-tree-mappings|.
When on_attach is "disabled", it will use the older mapping strategy, otherwise it When on_attach is not a function, |nvim-tree-mappings-default| will be called.
will use the newer one. Type: `function(bufnr) | string`, Default: `"default"`
Type: `function(bufnr)`, Default: `"disable"`
e.g. >
local api = require("nvim-tree.api")
local function on_attach(bufnr)
vim.keymap.set("n", "<C-P>", function()
local node = api.tree.get_node_under_cursor()
print(node.absolute_path)
end, { buffer = bufnr, noremap = true, silent = true, nowait = true, desc = "print the node's absolute path" })
end
<
*nvim-tree.remove_keymaps* *nvim-tree.remove_keymaps*
Deprecated: please see |nvim-tree-mappings-legacy|
This can be used to remove the default mappings in the tree. This can be used to remove the default mappings in the tree.
- Remove specific keys by passing a `string` table of keys - Remove specific keys by passing a `string` table of keys
eg. {"<C-o>", "<CR>", "o", "<Tab>"} eg. {"<C-o>", "<CR>", "o", "<Tab>"}
@ -774,17 +773,18 @@ Window / buffer setup.
Type: `string`, Default: `"yes"` Type: `string`, Default: `"yes"`
*nvim-tree.view.mappings* *nvim-tree.view.mappings*
Configuration options for |nvim-tree-mappings| Deprecated: please see |nvim-tree-mappings-legacy|
*nvim-tree.view.mappings.custom_only* *nvim-tree.view.mappings.custom_only*
Will use only the provided user mappings and not the default otherwise, Will use only the provided user mappings and not the default otherwise,
extends the default mappings with the provided user mappings. extends the default mappings with the provided user mappings.
Overrides |nvim-tree.remove_keymaps|
Type: `boolean`, Default: `false` Type: `boolean`, Default: `false`
*nvim-tree.view.mappings.list* *nvim-tree.view.mappings.list*
A list of keymaps that will extend or override the default keymaps. A list of keymaps that will extend or override the default keymaps.
Type: `table` Type: `table`
Default: see |nvim-tree-default-mappings| Default: see |nvim-tree-mappings-legacy|
*nvim-tree.view.float* *nvim-tree.view.float*
Configuration options for floating window Configuration options for floating window
@ -1426,15 +1426,16 @@ api.tree.toggle_help() *nvim-tree.api.tree.toggle_help()*
- navigate.select - navigate.select
api.config.mappings.active() *nvim-tree.api.config.mappings.active()* api.config.mappings.active() *nvim-tree.api.config.mappings.active()*
Retrieve a clone of the currently active mappings: Deprecated: only functions when using legacy |nvim-tree.view.mappings|
|nvim-tree-default-mappings| with |nvim-tree.view.mappings| applied. Retrieve a clone of the currently active mappings: defaults + user.
Changing the active mappings will require a call to |nvim-tree-setup| Changing the active mappings will require a call to |nvim-tree-setup|
Return: ~ Return: ~
(table) as per |nvim-tree.view.mappings.list| (table) as per |nvim-tree.view.mappings.list|
api.config.mappings.default() *nvim-tree.api.config.mappings.default()* api.config.mappings.default() *nvim-tree.api.config.mappings.default()*
Retrieve a clone of the default mappings: |nvim-tree-default-mappings| Deprecated: only functions when using legacy |nvim-tree.view.mappings|
Retrieve a clone of the default mappings.
Return: ~ Return: ~
(table) as per |nvim-tree.view.mappings.list| (table) as per |nvim-tree.view.mappings.list|
@ -1442,8 +1443,128 @@ api.config.mappings.default() *nvim-tree.api.config.mappings.default()*
============================================================================== ==============================================================================
6. MAPPINGS *nvim-tree-mappings* 6. MAPPINGS *nvim-tree-mappings*
Setting your own mapping in the configuration will soon be deprecated, see Mappings are set via the |nvim-tree.on_attach| function, which is run upon
|nvim-tree.on_attach| for experimental replacement. creating the nvim-tree buffer. Mappings may be directly to |nvim-tree-api|
functions or your own.
When on_attach is not a function, |nvim-tree-mappings-default| will be used.
Active mappings may be viewed via HELP, default `g?`. The mapping's description
is used when displaying HELP.
The `on_attach` function is passed the `bufnr` of nvim-tree. Use
|vim.keymap.set()| or |nvim_set_keymap()| to define mappings as usual. e.g.
>
local M = {}
local api = require("nvim-tree.api")
function M.on_attach(bufnr)
-- put some default mappings here
vim.keymap.set('n', 'h', api.tree.toggle_help, { desc = 'Help', buffer = bufnr, noremap = true, silent = true, nowait = true })
vim.keymap.set('n', '?', api.tree.toggle_help, { desc = 'Help', buffer = bufnr, noremap = true, silent = true, nowait = true })
vim.keymap.set('n', 'p', M.print_node_path, { desc = 'Print', buffer = bufnr, noremap = true, silent = true, nowait = true })
end
function M.print_node_path()
local node = api.tree.get_node_under_cursor()
print(node.absolute_path)
end
require("nvim-tree").setup({
on_attach = M.on_attach,
--
})
<
Mouse support is defined in |KeyBindings|
Single left mouse mappings can be achieved via `<LeftRelease>`.
Single right / middle mouse mappings will requre changes to |mousemodel| or |mouse|.
==============================================================================
6.1 DEFAULT MAPPINGS *nvim-tree-mappings-default*
In the absence of an |nvim-tree.on_attach| function, the following defaults
will be applied.
You are encouraged to copy these to your own |nvim-tree.on_attach| function.
>
local on_attach = function(bufnr)
local api = require('nvim-tree.api')
-- BEGIN_DEFAULT_ON_ATTACH
local opts = function(desc)
return { desc = 'nvim-tree: ' .. desc, buffer = bufnr, noremap = true, silent = true, nowait = true }
end
vim.keymap.set('n', '<C-]>', api.tree.change_root_to_node, opts('CD'))
vim.keymap.set('n', '<C-e>', api.node.open.replace_tree_buffer, opts('Open: In Place'))
vim.keymap.set('n', '<C-k>', api.node.show_info_popup, opts('Info'))
vim.keymap.set('n', '<C-r>', api.fs.rename_sub, opts('Rename: Omit Filename'))
vim.keymap.set('n', '<C-t>', api.node.open.tab, opts('Open: New Tab'))
vim.keymap.set('n', '<C-v>', api.node.open.vertical, opts('Open: Vertical Split'))
vim.keymap.set('n', '<C-x>', api.node.open.horizontal, opts('Open: Horizontal Split'))
vim.keymap.set('n', '<BS>', api.node.navigate.parent_close, opts('Close Directory'))
vim.keymap.set('n', '<CR>', api.node.open.edit, opts('Open'))
vim.keymap.set('n', '<Tab>', api.node.open.preview, opts('Open Preview'))
vim.keymap.set('n', '>', api.node.navigate.sibling.next, opts('Next Sibling'))
vim.keymap.set('n', '<', api.node.navigate.sibling.prev, opts('Previous Sibling'))
vim.keymap.set('n', '.', api.node.run.cmd, opts('Run Command'))
vim.keymap.set('n', '-', api.tree.change_root_to_parent, opts('Up'))
vim.keymap.set('n', 'a', api.fs.create, opts('Create'))
vim.keymap.set('n', 'bmv', api.marks.bulk.move, opts('Move Bookmarked'))
vim.keymap.set('n', 'B', api.tree.toggle_no_buffer_filter, opts('Toggle No Buffer'))
vim.keymap.set('n', 'c', api.fs.copy.node, opts('Copy'))
vim.keymap.set('n', 'C', api.tree.toggle_git_clean_filter, opts('Toggle Git Clean'))
vim.keymap.set('n', '[c', api.node.navigate.git.prev, opts('Prev Git'))
vim.keymap.set('n', ']c', api.node.navigate.git.next, opts('Next Git'))
vim.keymap.set('n', 'd', api.fs.remove, opts('Delete'))
vim.keymap.set('n', 'D', api.fs.trash, opts('Trash'))
vim.keymap.set('n', 'E', api.tree.expand_all, opts('Expand All'))
vim.keymap.set('n', 'e', api.fs.rename_basename, opts('Rename: Basename'))
vim.keymap.set('n', ']e', api.node.navigate.diagnostics.next, opts('Next Diagnostic'))
vim.keymap.set('n', '[e', api.node.navigate.diagnostics.prev, opts('Prev Diagnostic'))
vim.keymap.set('n', 'F', api.live_filter.clear, opts('Clean Filter'))
vim.keymap.set('n', 'f', api.live_filter.start, opts('Filter'))
vim.keymap.set('n', 'g?', api.tree.toggle_help, opts('Help'))
vim.keymap.set('n', 'gy', api.fs.copy.absolute_path, opts('Copy Absolute Path'))
vim.keymap.set('n', 'H', api.tree.toggle_hidden_filter, opts('Toggle Dotfiles'))
vim.keymap.set('n', 'I', api.tree.toggle_gitignore_filter, opts('Toggle Git Ignore'))
vim.keymap.set('n', 'J', api.node.navigate.sibling.last, opts('Last Sibling'))
vim.keymap.set('n', 'K', api.node.navigate.sibling.first, opts('First Sibling'))
vim.keymap.set('n', 'm', api.marks.toggle, opts('Toggle Bookmark'))
vim.keymap.set('n', 'o', api.node.open.edit, opts('Open'))
vim.keymap.set('n', 'O', api.node.open.no_window_picker, opts('Open: No Window Picker'))
vim.keymap.set('n', 'p', api.fs.paste, opts('Paste'))
vim.keymap.set('n', 'P', api.node.navigate.parent, opts('Parent Directory'))
vim.keymap.set('n', 'q', api.tree.close, opts('Close'))
vim.keymap.set('n', 'r', api.fs.rename, opts('Rename'))
vim.keymap.set('n', 'R', api.tree.reload, opts('Refresh'))
vim.keymap.set('n', 's', api.node.run.system, opts('Run System'))
vim.keymap.set('n', 'S', api.tree.search_node, opts('Search'))
vim.keymap.set('n', 'U', api.tree.toggle_custom_filter, opts('Toggle Hidden'))
vim.keymap.set('n', 'W', api.tree.collapse_all, opts('Collapse'))
vim.keymap.set('n', 'x', api.fs.cut, opts('Cut'))
vim.keymap.set('n', 'y', api.fs.copy.filename, opts('Copy Name'))
vim.keymap.set('n', 'Y', api.fs.copy.relative_path, opts('Copy Relative Path'))
vim.keymap.set('n', '<2-LeftMouse>', api.node.open.edit, opts('Open'))
vim.keymap.set('n', '<2-RightMouse>', api.tree.change_root_to_node, opts('CD'))
-- END_DEFAULT_ON_ATTACH
end
<
==============================================================================
6.2 LEGACY MAPPINGS *nvim-tree-mappings-legacy*
nvim-tree mappings were provided via the deprecated |nvim-tree.view.mappings|
and |nvim-tree.remove_keymaps|
These are ignored when |nvim-tree.on_attach| is present.
You are encouraged to migrate you existing legacy mappings to
|nvim-tree.on_attach| using |:NvimTreeGenerateOnAttach|
Please visit https://github.com/nvim-tree/nvim-tree.lua/wiki/Migrating-To-on_attach
`view.mappings.list` is a table of: `view.mappings.list` is a table of:
{key} (string|table of string) mandatory |{lhs}|. {key} (string|table of string) mandatory |{lhs}|.
@ -1483,121 +1604,6 @@ Examples:
---- ----
< <
Mouse support defined in |KeyBindings|
Single left mouse mappings can be achieved via `<LeftRelease>`.
Single right / middle mouse mappings will requre changes to |mousemodel| or |mouse|.
DEFAULT MAPPINGS *nvim-tree-default-mappings*
`<CR>` edit open a file or folder; root will cd to the above directory
`o`
`<2-LeftMouse>`
`<C-e>` edit_in_place edit the file in place, effectively replacing the tree explorer
`O` edit_no_picker same as (edit) with no window picker
`<C-]>` cd cd in the directory under the cursor
`<2-RightMouse>`
`<C-v>` vsplit open the file in a vertical split
`<C-x>` split open the file in a horizontal split
`<C-t>` tabnew open the file in a new tab
`<` prev_sibling navigate to the previous sibling of current file/directory
`>` next_sibling navigate to the next sibling of current file/directory
`P` parent_node move cursor to the parent directory
`<BS>` close_node close current opened directory or parent
`<Tab>` preview open the file as a preview (keeps the cursor in the tree)
`K` first_sibling navigate to the first sibling of current file/directory
`J` last_sibling navigate to the last sibling of current file/directory
`C` toggle_git_clean toggle visibility of git clean via |filters.git_clean| option
`I` toggle_git_ignored toggle visibility of files/folders hidden via |git.ignore| option
`H` toggle_dotfiles toggle visibility of dotfiles via |filters.dotfiles| option
`B` toggle_no_buffer toggle visibility of files/folders hidden via |filters.no_buffer| option
`U` toggle_custom toggle visibility of files/folders hidden via |filters.custom| option
`R` refresh refresh the tree
`a` create add a file; leaving a trailing `/` will add a directory
`d` remove delete a file (will prompt for confirmation)
`D` trash trash a file via |trash| option
`r` rename rename a file
`<C-r>` full_rename rename a file and omit the filename on input
`e` rename_basename rename a file with filename-modifiers ':t:r' without changing extension
`x` cut add/remove file/directory to cut clipboard
`c` copy add/remove file/directory to copy clipboard
`p` paste paste from clipboard; cut clipboard has precedence over copy; will prompt for confirmation
`y` copy_name copy name to system clipboard
`Y` copy_path copy relative path to system clipboard
`gy` copy_absolute_path copy absolute path to system clipboard
`[e` prev_diag_item go to next diagnostic item
`[c` prev_git_item go to next git item
`]e` next_diag_item go to prev diagnostic item
`]c` next_git_item go to prev git item
`-` dir_up navigate up to the parent directory of the current file/directory
`s` system_open open a file with default system application or a folder with default file manager, using |system_open| option
`f` live_filter live filter nodes dynamically based on regex matching.
`F` clear_live_filter clear live filter
`q` close close tree window
`W` collapse_all collapse the whole tree
`E` expand_all expand the whole tree, stopping after expanding |actions.expand_all.max_folder_discovery| folders; this might hang neovim for a while if running on a big folder
`S` search_node prompt the user to enter a path and then expands the tree to match the path
`.` run_file_command enter vim command mode with the file the cursor is on
`<C-k>` toggle_file_info toggle a popup with file infos about the file under the cursor
`g?` toggle_help toggle help
`m` toggle_mark Toggle node in bookmarks
`bmv` bulk_move Move all bookmarked nodes into specified location
>
view.mappings.list = { -- BEGIN_DEFAULT_MAPPINGS
{ key = { "<CR>", "o", "<2-LeftMouse>" }, action = "edit" },
{ key = "<C-e>", action = "edit_in_place" },
{ key = "O", action = "edit_no_picker" },
{ key = { "<C-]>", "<2-RightMouse>" }, action = "cd" },
{ key = "<C-v>", action = "vsplit" },
{ key = "<C-x>", action = "split" },
{ key = "<C-t>", action = "tabnew" },
{ key = "<", action = "prev_sibling" },
{ key = ">", action = "next_sibling" },
{ key = "P", action = "parent_node" },
{ key = "<BS>", action = "close_node" },
{ key = "<Tab>", action = "preview" },
{ key = "K", action = "first_sibling" },
{ key = "J", action = "last_sibling" },
{ key = "C", action = "toggle_git_clean" },
{ key = "I", action = "toggle_git_ignored" },
{ key = "H", action = "toggle_dotfiles" },
{ key = "B", action = "toggle_no_buffer" },
{ key = "U", action = "toggle_custom" },
{ key = "R", action = "refresh" },
{ key = "a", action = "create" },
{ key = "d", action = "remove" },
{ key = "D", action = "trash" },
{ key = "r", action = "rename" },
{ key = "<C-r>", action = "full_rename" },
{ key = "e", action = "rename_basename" },
{ key = "x", action = "cut" },
{ key = "c", action = "copy" },
{ key = "p", action = "paste" },
{ key = "y", action = "copy_name" },
{ key = "Y", action = "copy_path" },
{ key = "gy", action = "copy_absolute_path" },
{ key = "[e", action = "prev_diag_item" },
{ key = "[c", action = "prev_git_item" },
{ key = "]e", action = "next_diag_item" },
{ key = "]c", action = "next_git_item" },
{ key = "-", action = "dir_up" },
{ key = "s", action = "system_open" },
{ key = "f", action = "live_filter" },
{ key = "F", action = "clear_live_filter" },
{ key = "q", action = "close" },
{ key = "W", action = "collapse_all" },
{ key = "E", action = "expand_all" },
{ key = "S", action = "search_node" },
{ key = ".", action = "run_file_command" },
{ key = "<C-k>", action = "toggle_file_info" },
{ key = "g?", action = "toggle_help" },
{ key = "m", action = "toggle_mark" },
{ key = "bmv", action = "bulk_move" },
} -- END_DEFAULT_MAPPINGS
<
============================================================================== ==============================================================================
7. HIGHLIGHT GROUPS *nvim-tree-highlight* 7. HIGHLIGHT GROUPS *nvim-tree-highlight*

View File

@ -14,6 +14,7 @@ local git = require "nvim-tree.git"
local filters = require "nvim-tree.explorer.filters" local filters = require "nvim-tree.explorer.filters"
local modified = require "nvim-tree.modified" local modified = require "nvim-tree.modified"
local notify = require "nvim-tree.notify" local notify = require "nvim-tree.notify"
local keymap_legacy = require "nvim-tree.keymap-legacy"
local _config = {} local _config = {}
@ -68,9 +69,6 @@ function M.change_root(filepath, bufnr)
change_dir.fn(vim.fn.fnamemodify(filepath, ":p:h")) change_dir.fn(vim.fn.fnamemodify(filepath, ":p:h"))
end end
---@deprecated
M.on_keypress = require("nvim-tree.actions.dispatch").dispatch
function M.open_replacing_current_buffer(cwd) function M.open_replacing_current_buffer(cwd)
if view.is_visible() then if view.is_visible() then
return return
@ -379,6 +377,7 @@ local function setup_vim_commands()
vim.api.nvim_create_user_command("NvimTreeCollapseKeepBuffers", function() vim.api.nvim_create_user_command("NvimTreeCollapseKeepBuffers", function()
collapse_all.fn(true) collapse_all.fn(true)
end, { bar = true }) end, { bar = true })
vim.api.nvim_create_user_command("NvimTreeGenerateOnAttach", keymap_legacy.cmd_generate_on_attach, {})
end end
function M.change_dir(name) function M.change_dir(name)
@ -562,7 +561,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
sync_root_with_cwd = false, sync_root_with_cwd = false,
reload_on_bufenter = false, reload_on_bufenter = false,
respect_buf_cwd = false, respect_buf_cwd = false,
on_attach = "disable", on_attach = "default",
remove_keymaps = false, remove_keymaps = false,
select_prompts = false, select_prompts = false,
view = { view = {
@ -862,6 +861,7 @@ function M.setup(conf)
validate_options(conf) validate_options(conf)
local opts = merge_options(conf) local opts = merge_options(conf)
local netrw_disabled = opts.disable_netrw or opts.hijack_netrw local netrw_disabled = opts.disable_netrw or opts.hijack_netrw
_config.root_dirs = opts.root_dirs _config.root_dirs = opts.root_dirs
@ -885,6 +885,8 @@ function M.setup(conf)
log.raw("config", "%s\n", vim.inspect(opts)) log.raw("config", "%s\n", vim.inspect(opts))
end end
keymap_legacy.generate_legacy_on_attach(opts)
require("nvim-tree.actions").setup(opts) require("nvim-tree.actions").setup(opts)
require("nvim-tree.keymap").setup(opts) require("nvim-tree.keymap").setup(opts)
require("nvim-tree.colors").setup() require("nvim-tree.colors").setup()

View File

@ -1,131 +0,0 @@
local view = require "nvim-tree.view"
local lib = require "nvim-tree.lib"
local M = {}
local Actions = {
close = view.close,
-- Tree modifiers
collapse_all = require("nvim-tree.actions.tree-modifiers.collapse-all").fn,
expand_all = require("nvim-tree.actions.tree-modifiers.expand-all").fn,
toggle_dotfiles = require("nvim-tree.actions.tree-modifiers.toggles").dotfiles,
toggle_custom = require("nvim-tree.actions.tree-modifiers.toggles").custom,
toggle_git_ignored = require("nvim-tree.actions.tree-modifiers.toggles").git_ignored,
toggle_git_clean = require("nvim-tree.actions.tree-modifiers.toggles").git_clean,
toggle_no_buffer = require("nvim-tree.actions.tree-modifiers.toggles").no_buffer,
-- Filesystem operations
copy_absolute_path = require("nvim-tree.actions.fs.copy-paste").copy_absolute_path,
copy_name = require("nvim-tree.actions.fs.copy-paste").copy_filename,
copy_path = require("nvim-tree.actions.fs.copy-paste").copy_path,
copy = require("nvim-tree.actions.fs.copy-paste").copy,
create = require("nvim-tree.actions.fs.create-file").fn,
cut = require("nvim-tree.actions.fs.copy-paste").cut,
full_rename = require("nvim-tree.actions.fs.rename-file").fn ":p",
paste = require("nvim-tree.actions.fs.copy-paste").paste,
trash = require("nvim-tree.actions.fs.trash").fn,
remove = require("nvim-tree.actions.fs.remove-file").fn,
rename = require("nvim-tree.actions.fs.rename-file").fn ":t",
rename_basename = require("nvim-tree.actions.fs.rename-file").fn ":t:r",
-- Movements in tree
close_node = require("nvim-tree.actions.moves.parent").fn(true),
first_sibling = require("nvim-tree.actions.moves.sibling").fn "first",
last_sibling = require("nvim-tree.actions.moves.sibling").fn "last",
next_diag_item = require("nvim-tree.actions.moves.item").fn("next", "diag"),
next_git_item = require("nvim-tree.actions.moves.item").fn("next", "git"),
next_sibling = require("nvim-tree.actions.moves.sibling").fn "next",
parent_node = require("nvim-tree.actions.moves.parent").fn(false),
prev_diag_item = require("nvim-tree.actions.moves.item").fn("prev", "diag"),
prev_git_item = require("nvim-tree.actions.moves.item").fn("prev", "git"),
prev_sibling = require("nvim-tree.actions.moves.sibling").fn "prev",
-- Other types
refresh = require("nvim-tree.actions.reloaders.reloaders").reload_explorer,
dir_up = require("nvim-tree.actions.root.dir-up").fn,
search_node = require("nvim-tree.actions.finders.search-node").fn,
run_file_command = require("nvim-tree.actions.node.run-command").run_file_command,
toggle_file_info = require("nvim-tree.actions.node.file-popup").toggle_file_info,
system_open = require("nvim-tree.actions.node.system-open").fn,
toggle_mark = require("nvim-tree.marks").toggle_mark,
bulk_move = require("nvim-tree.marks.bulk-move").bulk_move,
}
local function handle_action_on_help_ui(action)
if action == "close" or action == "toggle_help" then
require("nvim-tree.actions.tree-modifiers.toggles").help()
end
end
local function handle_filter_actions(action)
if action == "live_filter" then
require("nvim-tree.live-filter").start_filtering()
elseif action == "clear_live_filter" then
require("nvim-tree.live-filter").clear_filter()
end
end
local function change_dir_action(node)
if node.name == ".." then
require("nvim-tree.actions.root.change-dir").fn ".."
elseif node.nodes ~= nil then
require("nvim-tree.actions.root.change-dir").fn(lib.get_last_group_node(node).absolute_path)
end
end
local function open_file(action, node)
local path = node.absolute_path
if node.link_to and not node.nodes then
path = node.link_to
end
require("nvim-tree.actions.node.open-file").fn(action, path)
end
local function handle_tree_actions(action)
local node = lib.get_node_at_cursor()
if not node then
return
end
local custom_function = M.custom_keypress_funcs[action]
local defined_action = Actions[action]
if type(custom_function) == "function" then
return custom_function(node)
elseif defined_action then
return defined_action(node)
end
local is_parent = node.name == ".."
if action == "preview" and is_parent then
return
end
if action == "cd" or is_parent then
return change_dir_action(node)
end
if node.nodes then
lib.expand_or_collapse(node)
else
open_file(action, node)
end
end
function M.dispatch(action)
if view.is_help_ui() or action == "toggle_help" then
handle_action_on_help_ui(action)
elseif action == "live_filter" or action == "clear_live_filter" then
handle_filter_actions(action)
else
handle_tree_actions(action)
end
end
function M.setup(custom_keypress_funcs)
M.custom_keypress_funcs = custom_keypress_funcs
end
return M

View File

@ -1,415 +1,4 @@
-- @deprecated: new implementation in nvim-tree.keymap. Please do not edit this file. local M = {}
local log = require "nvim-tree.log"
local view = require "nvim-tree.view"
local notify = require "nvim-tree.notify"
-- BEGIN_DEFAULT_MAPPINGS
local DEFAULT_MAPPINGS = {
{
key = { "<CR>", "o", "<2-LeftMouse>" },
action = "edit",
desc = "open a file or folder; root will cd to the above directory",
},
{
key = "<C-e>",
action = "edit_in_place",
desc = "edit the file in place, effectively replacing the tree explorer",
},
{
key = "O",
action = "edit_no_picker",
desc = "same as (edit) with no window picker",
},
{
key = { "<C-]>", "<2-RightMouse>" },
action = "cd",
desc = "cd in the directory under the cursor",
},
{
key = "<C-v>",
action = "vsplit",
desc = "open the file in a vertical split",
},
{
key = "<C-x>",
action = "split",
desc = "open the file in a horizontal split",
},
{
key = "<C-t>",
action = "tabnew",
desc = "open the file in a new tab",
},
{
key = "<",
action = "prev_sibling",
desc = "navigate to the previous sibling of current file/directory",
},
{
key = ">",
action = "next_sibling",
desc = "navigate to the next sibling of current file/directory",
},
{
key = "P",
action = "parent_node",
desc = "move cursor to the parent directory",
},
{
key = "<BS>",
action = "close_node",
desc = "close current opened directory or parent",
},
{
key = "<Tab>",
action = "preview",
desc = "open the file as a preview (keeps the cursor in the tree)",
},
{
key = "K",
action = "first_sibling",
desc = "navigate to the first sibling of current file/directory",
},
{
key = "J",
action = "last_sibling",
desc = "navigate to the last sibling of current file/directory",
},
{
key = "C",
action = "toggle_git_clean",
desc = "toggle visibility of git clean via |filters.git_clean| option",
},
{
key = "I",
action = "toggle_git_ignored",
desc = "toggle visibility of files/folders hidden via |git.ignore| option",
},
{
key = "H",
action = "toggle_dotfiles",
desc = "toggle visibility of dotfiles via |filters.dotfiles| option",
},
{
key = "B",
action = "toggle_no_buffer",
desc = "toggle visibility of files/folders hidden via |filters.no_buffer| option",
},
{
key = "U",
action = "toggle_custom",
desc = "toggle visibility of files/folders hidden via |filters.custom| option",
},
{
key = "R",
action = "refresh",
desc = "refresh the tree",
},
{
key = "a",
action = "create",
desc = "add a file; leaving a trailing `/` will add a directory",
},
{
key = "d",
action = "remove",
desc = "delete a file (will prompt for confirmation)",
},
{
key = "D",
action = "trash",
desc = "trash a file via |trash| option",
},
{
key = "r",
action = "rename",
desc = "rename a file",
},
{
key = "<C-r>",
action = "full_rename",
desc = "rename a file and omit the filename on input",
},
{
key = "e",
action = "rename_basename",
desc = "rename a file with filename-modifiers ':t:r' without changing extension",
},
{
key = "x",
action = "cut",
desc = "add/remove file/directory to cut clipboard",
},
{
key = "c",
action = "copy",
desc = "add/remove file/directory to copy clipboard",
},
{
key = "p",
action = "paste",
desc = "paste from clipboard; cut clipboard has precedence over copy; will prompt for confirmation",
},
{
key = "y",
action = "copy_name",
desc = "copy name to system clipboard",
},
{
key = "Y",
action = "copy_path",
desc = "copy relative path to system clipboard",
},
{
key = "gy",
action = "copy_absolute_path",
desc = "copy absolute path to system clipboard",
},
{
key = "[e",
action = "prev_diag_item",
desc = "go to next diagnostic item",
},
{
key = "[c",
action = "prev_git_item",
desc = "go to next git item",
},
{
key = "]e",
action = "next_diag_item",
desc = "go to prev diagnostic item",
},
{
key = "]c",
action = "next_git_item",
desc = "go to prev git item",
},
{
key = "-",
action = "dir_up",
desc = "navigate up to the parent directory of the current file/directory",
},
{
key = "s",
action = "system_open",
desc = "open a file with default system application or a folder with default file manager, using |system_open| option",
},
{
key = "f",
action = "live_filter",
desc = "live filter nodes dynamically based on regex matching.",
},
{
key = "F",
action = "clear_live_filter",
desc = "clear live filter",
},
{
key = "q",
action = "close",
desc = "close tree window",
},
{
key = "W",
action = "collapse_all",
desc = "collapse the whole tree",
},
{
key = "E",
action = "expand_all",
desc = "expand the whole tree, stopping after expanding |actions.expand_all.max_folder_discovery| folders; this might hang neovim for a while if running on a big folder",
},
{
key = "S",
action = "search_node",
desc = "prompt the user to enter a path and then expands the tree to match the path",
},
{
key = ".",
action = "run_file_command",
desc = "enter vim command mode with the file the cursor is on",
},
{
key = "<C-k>",
action = "toggle_file_info",
desc = "toggle a popup with file infos about the file under the cursor",
},
{
key = "g?",
action = "toggle_help",
desc = "toggle help",
},
{
key = "m",
action = "toggle_mark",
desc = "Toggle node in bookmarks",
},
{
key = "bmv",
action = "bulk_move",
desc = "Move all bookmarked nodes into specified location",
},
}
-- END_DEFAULT_MAPPINGS
local M = {
mappings = {},
custom_keypress_funcs = {},
}
local function set_map_for(bufnr)
local opts = { noremap = true, silent = true, nowait = true, buffer = bufnr }
return function(mode, rhs)
return function(lhs)
vim.keymap.set(mode or "n", lhs, rhs, opts)
end
end
end
local function run_dispatch(action)
return function()
require("nvim-tree.actions.dispatch").dispatch(action)
end
end
function M.apply_mappings(bufnr)
local setter_for = set_map_for(bufnr)
for _, b in pairs(M.mappings) do
local rhs = b.cb or run_dispatch(b.action)
if rhs then
local setter = setter_for(b.mode, rhs)
local keys = type(b.key) == "table" and b.key or { b.key }
for _, key in pairs(keys) do
setter(key)
end
end
end
end
local function merge_mappings(user_mappings)
if #user_mappings == 0 then
return M.mappings
end
local function is_empty(s)
return s == ""
end
local user_keys = {}
local removed_keys = {}
-- remove default mappings if action is a empty string
for _, map in pairs(user_mappings) do
if type(map.key) == "table" then
for _, key in pairs(map.key) do
table.insert(user_keys, key)
if is_empty(map.action) then
table.insert(removed_keys, key)
end
end
else
table.insert(user_keys, map.key)
if is_empty(map.action) then
table.insert(removed_keys, map.key)
end
end
if map.action and type(map.action_cb) == "function" then
if not is_empty(map.action) then
M.custom_keypress_funcs[map.action] = map.action_cb
else
notify.warn "action can't be empty if action_cb provided"
end
end
end
local default_map = vim.tbl_filter(function(map)
if type(map.key) == "table" then
local filtered_keys = {}
for _, key in pairs(map.key) do
if not vim.tbl_contains(user_keys, key) and not vim.tbl_contains(removed_keys, key) then
table.insert(filtered_keys, key)
end
end
map.key = filtered_keys
return not vim.tbl_isempty(map.key)
else
return not vim.tbl_contains(user_keys, map.key) and not vim.tbl_contains(removed_keys, map.key)
end
end, M.mappings)
local user_map = vim.tbl_filter(function(map)
return not is_empty(map.action)
end, user_mappings)
return vim.fn.extend(default_map, user_map)
end
local function copy_mappings(user_mappings)
if #user_mappings == 0 then
return M.mappings
end
for _, map in pairs(user_mappings) do
if map.action and type(map.action_cb) == "function" then
M.custom_keypress_funcs[map.action] = map.action_cb
end
end
return user_mappings
end
local function cleanup_existing_mappings()
local bufnr = view.get_bufnr()
if bufnr == nil or not vim.api.nvim_buf_is_valid(bufnr) then
return
end
for _, b in pairs(M.mappings) do
local keys = type(b.key) == "table" and b.key or { b.key }
for _, key in pairs(keys) do
vim.keymap.del(b.mode or "n", key, { buffer = bufnr })
end
end
end
local function filter_mappings(mappings, keys)
if type(keys) == "boolean" and keys then
return {}
elseif type(keys) == "table" then
return vim.tbl_filter(function(m)
if type(m.key) == "table" then
m.key = vim.tbl_filter(function(k)
return not vim.tbl_contains(keys, k)
end, m.key)
return #m.key > 0
else
return not vim.tbl_contains(keys, m.key)
end
end, vim.deepcopy(mappings))
else
return vim.deepcopy(mappings)
end
end
local DEFAULT_MAPPING_CONFIG = {
custom_only = false,
list = {},
}
--- clone default for the user
--- @return table
function M.default_mappings_clone()
return vim.deepcopy(DEFAULT_MAPPINGS)
end
--- clone active for the user
--- @return table
function M.active_mappings_clone()
return vim.deepcopy(M.mappings)
end
function M.setup(opts) function M.setup(opts)
require("nvim-tree.actions.fs.trash").setup(opts) require("nvim-tree.actions.fs.trash").setup(opts)
@ -422,25 +11,6 @@ function M.setup(opts)
require("nvim-tree.actions.fs.remove-file").setup(opts) require("nvim-tree.actions.fs.remove-file").setup(opts)
require("nvim-tree.actions.fs.copy-paste").setup(opts) require("nvim-tree.actions.fs.copy-paste").setup(opts)
require("nvim-tree.actions.tree-modifiers.expand-all").setup(opts) require("nvim-tree.actions.tree-modifiers.expand-all").setup(opts)
cleanup_existing_mappings()
M.mappings = filter_mappings(DEFAULT_MAPPINGS, opts.remove_keymaps)
local user_map_config = (opts.view or {}).mappings or {}
local options = vim.tbl_deep_extend("force", DEFAULT_MAPPING_CONFIG, user_map_config)
if options.custom_only then
M.mappings = copy_mappings(options.list)
else
M.mappings = merge_mappings(options.list)
end
require("nvim-tree.actions.dispatch").setup(M.custom_keypress_funcs)
if log.enabled "config" then
log.line("config", "active mappings")
log.raw("config", "%s\n", vim.inspect(M.mappings))
end
end end
return M return M

View File

@ -22,7 +22,9 @@ end
---@field find_file boolean|nil default false ---@field find_file boolean|nil default false
---@field update_root boolean|nil default false ---@field update_root boolean|nil default false
Api.tree.open = require("nvim-tree").open Api.tree.open = function(...)
require("nvim-tree").open(...)
end
---@class ApiTreeToggleOpts ---@class ApiTreeToggleOpts
---@field path string|nil ---@field path string|nil
@ -31,7 +33,9 @@ Api.tree.open = require("nvim-tree").open
---@field update_root boolean|nil default false ---@field update_root boolean|nil default false
---@field focus boolean|nil default true ---@field focus boolean|nil default true
Api.tree.toggle = require("nvim-tree").toggle Api.tree.toggle = function(...)
require("nvim-tree").toggle(...)
end
Api.tree.close = require("nvim-tree.view").close Api.tree.close = require("nvim-tree.view").close
@ -39,11 +43,15 @@ Api.tree.close_in_this_tab = require("nvim-tree.view").close_this_tab_only
Api.tree.close_in_all_tabs = require("nvim-tree.view").close_all_tabs Api.tree.close_in_all_tabs = require("nvim-tree.view").close_all_tabs
Api.tree.focus = require("nvim-tree").focus Api.tree.focus = function()
require("nvim-tree").focus()
end
Api.tree.reload = require("nvim-tree.actions.reloaders.reloaders").reload_explorer Api.tree.reload = require("nvim-tree.actions.reloaders.reloaders").reload_explorer
Api.tree.change_root = require("nvim-tree").change_dir Api.tree.change_root = function(...)
require("nvim-tree").change_dir(...)
end
Api.tree.change_root_to_node = inject_node(function(node) Api.tree.change_root_to_node = inject_node(function(node)
if node.name == ".." then if node.name == ".." then
@ -162,7 +170,11 @@ Api.marks.navigate.next = require("nvim-tree.marks.navigation").next
Api.marks.navigate.prev = require("nvim-tree.marks.navigation").prev Api.marks.navigate.prev = require("nvim-tree.marks.navigation").prev
Api.marks.navigate.select = require("nvim-tree.marks.navigation").select Api.marks.navigate.select = require("nvim-tree.marks.navigation").select
Api.config.mappings.active = require("nvim-tree.actions").active_mappings_clone Api.config.mappings.active = function()
Api.config.mappings.default = require("nvim-tree.actions").default_mappings_clone return require("nvim-tree.keymap-legacy").active_mappings_clone()
end
Api.config.mappings.default = function()
return require("nvim-tree.keymap-legacy").default_mappings_clone()
end
return Api return Api

View File

@ -1,10 +0,0 @@
-- INFO: DEPRECATED FILE, DO NOT ADD ANYTHING IN THERE
-- keeping to avoid breaking user configs. Will remove during a weekend.
local M = {}
-- TODO: remove this once the cb property is not supported in mappings
function M.nvim_tree_callback(callback_name)
return string.format("<cmd>lua require'nvim-tree.actions.dispatch'.dispatch('%s')<CR>", callback_name)
end
return M

View File

@ -0,0 +1,410 @@
local api = require "nvim-tree.api"
local open_file = require "nvim-tree.actions.node.open-file"
local keymap = require "nvim-tree.keymap"
local notify = require "nvim-tree.notify"
local M = {
-- only populated when legacy mappings active
on_attach_lua = nil,
-- API config.mappings.active .default
legacy_default = {},
legacy_active = {},
-- used by generated on_attach
on_attach = {
list = {},
unmapped_keys = {},
remove_defaults = false,
},
}
local BEGIN_ON_ATTACH = [[
--
-- This function has been generated from your
-- view.mappings.list
-- view.mappings.custom_only
-- remove_keymaps
--
-- You should add this function to your configuration and set on_attach = on_attach in the nvim-tree setup call.
--
-- Although care was taken to ensure correctness and completeness, your review is required.
--
-- Please check for the following issues in auto generated content:
-- "Mappings removed" is as you expect
-- "Mappings migrated" are correct
--
-- Please see https://github.com/nvim-tree/nvim-tree.lua/wiki/Migrating-To-on_attach for assistance in migrating.
--
local api = require('nvim-tree.api')
local on_attach = function(bufnr)
local opts = function(desc)
return { desc = 'nvim-tree: ' .. desc, buffer = bufnr, noremap = true, silent = true, nowait = true }
end
]]
local END_ON_ATTACH = [[
end
]]
local REMOVAL_COMMENT_ON_ATTACH = [[
-- Mappings removed via:
-- remove_keymaps
-- OR
-- view.mappings.list..action = ""
--
-- The dummy set before del is done for safety, in case a default mapping does not exist.
--
-- You might tidy things by removing these along with their default mapping.
]]
local CUSTOM_COMMENT_ON_ATTACH = [[
-- Mappings migrated from view.mappings.list
--
-- You will need to insert "your code goes here" for any mappings with a custom action_cb
]]
local NO_DEFAULTS_COMMENT_ON_ATTACH = [[
-- Default mappings not inserted as:
-- remove_keymaps = true
-- OR
-- view.mappings.custom_only = true
]]
local DEFAULT_ON_ATTACH = [[
-- Default mappings. Feel free to modify or remove as you wish.
--
-- BEGIN_DEFAULT_ON_ATTACH
vim.keymap.set('n', '<C-]>', api.tree.change_root_to_node, opts('CD'))
vim.keymap.set('n', '<C-e>', api.node.open.replace_tree_buffer, opts('Open: In Place'))
vim.keymap.set('n', '<C-k>', api.node.show_info_popup, opts('Info'))
vim.keymap.set('n', '<C-r>', api.fs.rename_sub, opts('Rename: Omit Filename'))
vim.keymap.set('n', '<C-t>', api.node.open.tab, opts('Open: New Tab'))
vim.keymap.set('n', '<C-v>', api.node.open.vertical, opts('Open: Vertical Split'))
vim.keymap.set('n', '<C-x>', api.node.open.horizontal, opts('Open: Horizontal Split'))
vim.keymap.set('n', '<BS>', api.node.navigate.parent_close, opts('Close Directory'))
vim.keymap.set('n', '<CR>', api.node.open.edit, opts('Open'))
vim.keymap.set('n', '<Tab>', api.node.open.preview, opts('Open Preview'))
vim.keymap.set('n', '>', api.node.navigate.sibling.next, opts('Next Sibling'))
vim.keymap.set('n', '<', api.node.navigate.sibling.prev, opts('Previous Sibling'))
vim.keymap.set('n', '.', api.node.run.cmd, opts('Run Command'))
vim.keymap.set('n', '-', api.tree.change_root_to_parent, opts('Up'))
vim.keymap.set('n', 'a', api.fs.create, opts('Create'))
vim.keymap.set('n', 'bmv', api.marks.bulk.move, opts('Move Bookmarked'))
vim.keymap.set('n', 'B', api.tree.toggle_no_buffer_filter, opts('Toggle No Buffer'))
vim.keymap.set('n', 'c', api.fs.copy.node, opts('Copy'))
vim.keymap.set('n', 'C', api.tree.toggle_git_clean_filter, opts('Toggle Git Clean'))
vim.keymap.set('n', '[c', api.node.navigate.git.prev, opts('Prev Git'))
vim.keymap.set('n', ']c', api.node.navigate.git.next, opts('Next Git'))
vim.keymap.set('n', 'd', api.fs.remove, opts('Delete'))
vim.keymap.set('n', 'D', api.fs.trash, opts('Trash'))
vim.keymap.set('n', 'E', api.tree.expand_all, opts('Expand All'))
vim.keymap.set('n', 'e', api.fs.rename_basename, opts('Rename: Basename'))
vim.keymap.set('n', ']e', api.node.navigate.diagnostics.next, opts('Next Diagnostic'))
vim.keymap.set('n', '[e', api.node.navigate.diagnostics.prev, opts('Prev Diagnostic'))
vim.keymap.set('n', 'F', api.live_filter.clear, opts('Clean Filter'))
vim.keymap.set('n', 'f', api.live_filter.start, opts('Filter'))
vim.keymap.set('n', 'g?', api.tree.toggle_help, opts('Help'))
vim.keymap.set('n', 'gy', api.fs.copy.absolute_path, opts('Copy Absolute Path'))
vim.keymap.set('n', 'H', api.tree.toggle_hidden_filter, opts('Toggle Dotfiles'))
vim.keymap.set('n', 'I', api.tree.toggle_gitignore_filter, opts('Toggle Git Ignore'))
vim.keymap.set('n', 'J', api.node.navigate.sibling.last, opts('Last Sibling'))
vim.keymap.set('n', 'K', api.node.navigate.sibling.first, opts('First Sibling'))
vim.keymap.set('n', 'm', api.marks.toggle, opts('Toggle Bookmark'))
vim.keymap.set('n', 'o', api.node.open.edit, opts('Open'))
vim.keymap.set('n', 'O', api.node.open.no_window_picker, opts('Open: No Window Picker'))
vim.keymap.set('n', 'p', api.fs.paste, opts('Paste'))
vim.keymap.set('n', 'P', api.node.navigate.parent, opts('Parent Directory'))
vim.keymap.set('n', 'q', api.tree.close, opts('Close'))
vim.keymap.set('n', 'r', api.fs.rename, opts('Rename'))
vim.keymap.set('n', 'R', api.tree.reload, opts('Refresh'))
vim.keymap.set('n', 's', api.node.run.system, opts('Run System'))
vim.keymap.set('n', 'S', api.tree.search_node, opts('Search'))
vim.keymap.set('n', 'U', api.tree.toggle_custom_filter, opts('Toggle Hidden'))
vim.keymap.set('n', 'W', api.tree.collapse_all, opts('Collapse'))
vim.keymap.set('n', 'x', api.fs.cut, opts('Cut'))
vim.keymap.set('n', 'y', api.fs.copy.filename, opts('Copy Name'))
vim.keymap.set('n', 'Y', api.fs.copy.relative_path, opts('Copy Relative Path'))
vim.keymap.set('n', '<2-LeftMouse>', api.node.open.edit, opts('Open'))
vim.keymap.set('n', '<2-RightMouse>', api.tree.change_root_to_node, opts('CD'))
-- END_DEFAULT_ON_ATTACH
]]
-- stylua: ignore start
local LEGACY_MAPPINGS = {
edit = { key = { "<CR>", "o", "<2-LeftMouse>" }, desc = "Open", fn = api.node.open.edit, n = "api.node.open.edit" },
edit_in_place = { key = "<C-e>", desc = "Open: In Place", fn = api.node.open.replace_tree_buffer, n = "api.node.open.replace_tree_buffer" },
edit_no_picker = { key = "O", desc = "Open: No Window Picker", fn = api.node.open.no_window_picker, n = "api.node.open.no_window_picker" },
cd = { key = { "<C-]>", "<2-RightMouse>" }, desc = "CD", fn = api.tree.change_root_to_node, n = "api.tree.change_root_to_node" },
vsplit = { key = "<C-v>", desc = "Open: Vertical Split", fn = api.node.open.vertical, n = "api.node.open.vertical" },
split = { key = "<C-x>", desc = "Open: Horizontal Split", fn = api.node.open.horizontal, n = "api.node.open.horizontal" },
tabnew = { key = "<C-t>", desc = "Open: New Tab", fn = api.node.open.tab, n = "api.node.open.tab" },
prev_sibling = { key = "<", desc = "Previous Sibling", fn = api.node.navigate.sibling.prev, n = "api.node.navigate.sibling.prev" },
next_sibling = { key = ">", desc = "Next Sibling", fn = api.node.navigate.sibling.next, n = "api.node.navigate.sibling.next" },
parent_node = { key = "P", desc = "Parent Directory", fn = api.node.navigate.parent, n = "api.node.navigate.parent" },
close_node = { key = "<BS>", desc = "Close Directory", fn = api.node.navigate.parent_close, n = "api.node.navigate.parent_close" },
preview = { key = "<Tab>", desc = "Open Preview", fn = api.node.open.preview, n = "api.node.open.preview" },
first_sibling = { key = "K", desc = "First Sibling", fn = api.node.navigate.sibling.first, n = "api.node.navigate.sibling.first" },
last_sibling = { key = "J", desc = "Last Sibling", fn = api.node.navigate.sibling.last, n = "api.node.navigate.sibling.last" },
toggle_git_ignored = { key = "I", desc = "Toggle Git Ignore", fn = api.tree.toggle_gitignore_filter, n = "api.tree.toggle_gitignore_filter" },
toggle_no_buffer = { key = "B", desc = "Toggle No Buffer", fn = api.tree.toggle_no_buffer_filter, n = "api.tree.toggle_no_buffer_filter" },
toggle_git_clean = { key = "C", desc = "Toggle Git Clean", fn = api.tree.toggle_git_clean_filter, n = "api.tree.toggle_git_clean_filter" },
toggle_dotfiles = { key = "H", desc = "Toggle Dotfiles", fn = api.tree.toggle_hidden_filter, n = "api.tree.toggle_hidden_filter" },
toggle_custom = { key = "U", desc = "Toggle Hidden", fn = api.tree.toggle_custom_filter, n = "api.tree.toggle_custom_filter" },
refresh = { key = "R", desc = "Refresh", fn = api.tree.reload, n = "api.tree.reload" },
create = { key = "a", desc = "Create", fn = api.fs.create, n = "api.fs.create" },
remove = { key = "d", desc = "Delete", fn = api.fs.remove, n = "api.fs.remove" },
trash = { key = "D", desc = "Trash", fn = api.fs.trash, n = "api.fs.trash" },
rename = { key = "r", desc = "Rename", fn = api.fs.rename, n = "api.fs.rename" },
full_rename = { key = "<C-r>", desc = "Rename: Omit Filename", fn = api.fs.rename_sub, n = "api.fs.rename_sub" },
rename_basename = { key = "e", desc = "Rename: Basename", fn = api.fs.rename_basename, n = "api.fs.rename_basename" },
cut = { key = "x", desc = "Cut", fn = api.fs.cut, n = "api.fs.cut" },
copy = { key = "c", desc = "Copy", fn = api.fs.copy.node, n = "api.fs.copy.node" },
paste = { key = "p", desc = "Paste", fn = api.fs.paste, n = "api.fs.paste" },
copy_name = { key = "y", desc = "Copy Name", fn = api.fs.copy.filename, n = "api.fs.copy.filename" },
copy_path = { key = "Y", desc = "Copy Relative Path", fn = api.fs.copy.relative_path, n = "api.fs.copy.relative_path" },
copy_absolute_path = { key = "gy", desc = "Copy Absolute Path", fn = api.fs.copy.absolute_path, n = "api.fs.copy.absolute_path" },
next_diag_item = { key = "]e", desc = "Next Diagnostic", fn = api.node.navigate.diagnostics.next, n = "api.node.navigate.diagnostics.next" },
next_git_item = { key = "]c", desc = "Next Git", fn = api.node.navigate.git.next, n = "api.node.navigate.git.next" },
prev_diag_item = { key = "[e", desc = "Prev Diagnostic", fn = api.node.navigate.diagnostics.prev, n = "api.node.navigate.diagnostics.prev" },
prev_git_item = { key = "[c", desc = "Prev Git", fn = api.node.navigate.git.prev, n = "api.node.navigate.git.prev" },
dir_up = { key = "-", desc = "Up", fn = api.tree.change_root_to_parent, n = "api.tree.change_root_to_parent" },
system_open = { key = "s", desc = "Run System", fn = api.node.run.system, n = "api.node.run.system" },
live_filter = { key = "f", desc = "Filter", fn = api.live_filter.start, n = "api.live_filter.start" },
clear_live_filter = { key = "F", desc = "Clean Filter", fn = api.live_filter.clear, n = "api.live_filter.clear" },
close = { key = "q", desc = "Close", fn = api.tree.close, n = "api.tree.close" },
collapse_all = { key = "W", desc = "Collapse", fn = api.tree.collapse_all, n = "api.tree.collapse_all" },
expand_all = { key = "E", desc = "Expand All", fn = api.tree.expand_all, n = "api.tree.expand_all" },
search_node = { key = "S", desc = "Search", fn = api.tree.search_node, n = "api.tree.search_node" },
run_file_command = { key = ".", desc = "Run Command", fn = api.node.run.cmd, n = "api.node.run.cmd" },
toggle_file_info = { key = "<C-k>", desc = "Info", fn = api.node.show_info_popup, n = "api.node.show_info_popup" },
toggle_help = { key = "g?", desc = "Help", fn = api.tree.toggle_help, n = "api.tree.toggle_help" },
toggle_mark = { key = "m", desc = "Toggle Bookmark", fn = api.marks.toggle, n = "api.marks.toggle" },
bulk_move = { key = "bmv", desc = "Move Bookmarked", fn = api.marks.bulk.move, n = "api.marks.bulk.move" },
}
-- stylua: ignore end
local function all_mapped_keys(list)
local mapped_keys = {}
for _, map in pairs(list) do
if map.action ~= "" then
local keys = type(map.key) == "table" and map.key or { map.key }
for _, key in ipairs(keys) do
table.insert(mapped_keys, key)
end
end
end
return mapped_keys
end
local function all_unmapped_keys(list, remove_keys)
local unmapped_keys = vim.deepcopy(remove_keys)
for _, map in pairs(list) do
if map.action == "" then
local keys = type(map.key) == "table" and map.key or { map.key }
for _, key in ipairs(keys) do
table.insert(unmapped_keys, key)
end
end
end
return unmapped_keys
end
local function generate_on_attach_function(list, unmapped_keys, remove_defaults)
M.on_attach.list = vim.deepcopy(list)
M.on_attach.unmapped_keys = vim.deepcopy(unmapped_keys)
M.on_attach.remove_defaults = remove_defaults
return function(bufnr)
-- apply defaults first
if not M.on_attach.remove_defaults then
keymap.default_on_attach(bufnr)
end
-- explicit removals
for _, key in ipairs(M.on_attach.unmapped_keys) do
vim.keymap.set("n", key, "", { buffer = bufnr })
vim.keymap.del("n", key, { buffer = bufnr })
end
-- mappings
for _, m in ipairs(M.on_attach.list) do
local keys = type(m.key) == "table" and m.key or { m.key }
for _, k in ipairs(keys) do
if LEGACY_MAPPINGS[m.action] then
-- straight action
vim.keymap.set(
m.mode or "n",
k,
LEGACY_MAPPINGS[m.action].fn,
{ desc = m.action, buffer = bufnr, noremap = true, silent = true, nowait = true }
)
elseif type(m.action_cb) == "function" then
-- action_cb
vim.keymap.set(m.mode or "n", k, function()
m.action_cb(api.tree.get_node_under_cursor())
end, { desc = m.action, buffer = bufnr, noremap = true, silent = true, nowait = true })
end
end
end
end
end
local function generate_on_attach_lua(list, unmapped_keys, remove_defaults)
local lua = BEGIN_ON_ATTACH
if remove_defaults then
-- no defaults
lua = lua .. NO_DEFAULTS_COMMENT_ON_ATTACH
else
-- defaults with explicit removals
lua = lua .. "\n" .. DEFAULT_ON_ATTACH
if #unmapped_keys > 0 then
lua = lua .. REMOVAL_COMMENT_ON_ATTACH
end
for _, key in ipairs(unmapped_keys) do
lua = lua .. string.format([[ vim.keymap.set('n', '%s', '', { buffer = bufnr })]], key) .. "\n"
lua = lua .. string.format([[ vim.keymap.del('n', '%s', { buffer = bufnr })]], key) .. "\n"
end
end
-- list
if #list > 0 then
lua = lua .. CUSTOM_COMMENT_ON_ATTACH
end
for _, m in ipairs(list) do
local keys = type(m.key) == "table" and m.key or { m.key }
for _, k in ipairs(keys) do
if LEGACY_MAPPINGS[m.action] then
lua = lua
.. string.format(
[[ vim.keymap.set('%s', '%s', %s, opts('%s'))]],
m.mode or "n",
k,
LEGACY_MAPPINGS[m.action].n,
LEGACY_MAPPINGS[m.action].desc
)
.. "\n"
elseif type(m.action_cb) == "function" then
lua = lua .. string.format([[ vim.keymap.set('%s', '%s', function()]], m.mode or "n", k) .. "\n"
lua = lua .. [[ local node = api.tree.get_node_under_cursor()]] .. "\n"
lua = lua .. [[ -- your code goes here]] .. "\n"
lua = lua .. string.format([[ end, opts('%s'))]], m.action) .. "\n\n"
end
end
end
return lua .. "\n" .. END_ON_ATTACH
end
local function generate_legacy_default_mappings()
local mappings = {}
for a, m in pairs(LEGACY_MAPPINGS) do
table.insert(mappings, {
action = a,
desc = m.desc,
key = m.key,
})
end
return mappings
end
local function generate_legacy_active_mappings(list, defaults, unmapped_keys, mapped_keys, remove_defaults)
local filtered_defaults
if remove_defaults then
--
-- unmap all defaults
--
filtered_defaults = {}
else
--
-- unmap defaults by removal and override
--
local to_unmap = vim.fn.extend(unmapped_keys, mapped_keys)
filtered_defaults = vim.tbl_filter(function(m)
if type(m.key) == "table" then
m.key = vim.tbl_filter(function(k)
return not vim.tbl_contains(to_unmap, k)
end, m.key)
return #m.key > 0
else
return not vim.tbl_contains(to_unmap, m.key)
end
end, vim.deepcopy(defaults))
end
--
-- remove user action = ""
--
local user_map = vim.tbl_filter(function(map)
return map.action ~= ""
end, list)
--
-- merge
--
return vim.fn.extend(filtered_defaults, user_map)
end
function M.generate_legacy_on_attach(opts)
M.on_attach_lua = nil
if type(opts.on_attach) == "function" then
return
end
local list = opts.view and opts.view.mappings and opts.view.mappings.list or {}
local remove_keymaps = type(opts.remove_keymaps) == "table" and opts.remove_keymaps or {}
local remove_defaults = opts.remove_keymaps == true
or opts.view and opts.view.mappings and opts.view.mappings.custom_only
-- do nothing unless the user has configured something
if #list == 0 and #remove_keymaps == 0 and not remove_defaults then
return
end
local mapped_keys = all_mapped_keys(list)
local unmapped_keys = all_unmapped_keys(list, remove_keymaps)
opts.on_attach = generate_on_attach_function(list, unmapped_keys, remove_defaults)
M.on_attach_lua = generate_on_attach_lua(list, unmapped_keys, remove_defaults)
M.legacy_default = generate_legacy_default_mappings()
M.legacy_active = generate_legacy_active_mappings(list, M.legacy_default, unmapped_keys, mapped_keys, remove_defaults)
end
function M.cmd_generate_on_attach()
if not M.on_attach_lua then
notify.info "No view.mappings.list for on_attach generation."
return
end
local name = "/tmp/my_on_attach.lua"
local file = io.output(name)
io.write(M.on_attach_lua)
io.close(file)
open_file.fn("edit", name)
end
function M.active_mappings_clone()
return vim.deepcopy(M.legacy_active)
end
function M.default_mappings_clone()
return vim.deepcopy(M.legacy_default)
end
return M

View File

@ -1,290 +1,76 @@
local Api = require "nvim-tree.api" local api = require "nvim-tree.api"
local M = {} local M = {}
local DEFAULT_KEYMAPS = { -- stylua: ignore start
{ function M.default_on_attach(bufnr)
key = { "<CR>", "o", "<2-LeftMouse>" }, -- BEGIN_DEFAULT_ON_ATTACH
callback = Api.node.open.edit, local opts = function(desc)
desc = "open a file or folder; root will cd to the above directory", return { desc = 'nvim-tree: ' .. desc, buffer = bufnr, noremap = true, silent = true, nowait = true }
},
{
key = "<C-e>",
callback = Api.node.open.replace_tree_buffer,
desc = "edit the file in place, effectively replacing the tree explorer",
},
{
key = "O",
callback = Api.node.open.no_window_picker,
desc = "same as (edit) with no window picker",
},
{
key = { "<C-]>", "<2-RightMouse>" },
callback = Api.tree.change_root_to_node,
desc = "cd in the directory under the cursor",
},
{
key = "<C-v>",
callback = Api.node.open.vertical,
desc = "open the file in a vertical split",
},
{
key = "<C-x>",
callback = Api.node.open.horizontal,
desc = "open the file in a horizontal split",
},
{
key = "<C-t>",
callback = Api.node.open.tab,
desc = "open the file in a new tab",
},
{
key = "<",
callback = Api.node.navigate.sibling.prev,
desc = "navigate to the previous sibling of current file/directory",
},
{
key = ">",
callback = Api.node.navigate.sibling.next,
desc = "navigate to the next sibling of current file/directory",
},
{
key = "P",
callback = Api.node.navigate.parent,
desc = "move cursor to the parent directory",
},
{
key = "<BS>",
callback = Api.node.navigate.parent_close,
desc = "close current opened directory or parent",
},
{
key = "<Tab>",
callback = Api.node.open.preview,
desc = "open the file as a preview (keeps the cursor in the tree)",
},
{
key = "K",
callback = Api.node.navigate.sibling.first,
desc = "navigate to the first sibling of current file/directory",
},
{
key = "J",
callback = Api.node.navigate.sibling.last,
desc = "navigate to the last sibling of current file/directory",
},
{
key = "I",
callback = Api.tree.toggle_gitignore_filter,
desc = "toggle visibility of files/folders hidden via |git.ignore| option",
},
{
key = "H",
callback = Api.tree.toggle_hidden_filter,
desc = "toggle visibility of dotfiles via |filters.dotfiles| option",
},
{
key = "U",
callback = Api.tree.toggle_custom_filter,
desc = "toggle visibility of files/folders hidden via |filters.custom| option",
},
{
key = "R",
callback = Api.tree.reload,
desc = "refresh the tree",
},
{
key = "a",
callback = Api.fs.create,
desc = "add a file; leaving a trailing `/` will add a directory",
},
{
key = "d",
callback = Api.fs.remove,
desc = "delete a file (will prompt for confirmation)",
},
{
key = "D",
callback = Api.fs.trash,
desc = "trash a file via |trash| option",
},
{
key = "r",
callback = Api.fs.rename,
desc = "rename a file",
},
{
key = "<C-r>",
callback = Api.fs.rename_sub,
desc = "rename a file and omit the filename on input",
},
{
key = "x",
callback = Api.fs.cut,
desc = "add/remove file/directory to cut clipboard",
},
{
key = "c",
callback = Api.fs.copy.node,
desc = "add/remove file/directory to copy clipboard",
},
{
key = "p",
callback = Api.fs.paste,
desc = "paste from clipboard; cut clipboard has precedence over copy; will prompt for confirmation",
},
{
key = "y",
callback = Api.fs.copy.filename,
desc = "copy name to system clipboard",
},
{
key = "Y",
callback = Api.fs.copy.relative_path,
desc = "copy relative path to system clipboard",
},
{
key = "gy",
callback = Api.fs.copy.absolute_path,
desc = "copy absolute path to system clipboard",
},
{
key = "]e",
callback = Api.node.navigate.diagnostics.next,
desc = "go to next diagnostic item",
},
{
key = "]c",
callback = Api.node.navigate.git.next,
desc = "go to next git item",
},
{
key = "[e",
callback = Api.node.navigate.diagnostics.prev,
desc = "go to prev diagnostic item",
},
{
key = "[c",
callback = Api.node.navigate.git.prev,
desc = "go to prev git item",
},
{
key = "-",
callback = Api.tree.change_root_to_parent,
desc = "navigate up to the parent directory of the current file/directory",
},
{
key = "s",
callback = Api.node.run.system,
desc = "open a file with default system application or a folder with default file manager, using |system_open| option",
},
{
key = "f",
callback = Api.live_filter.start,
desc = "live filter nodes dynamically based on regex matching.",
},
{
key = "F",
callback = Api.live_filter.clear,
desc = "clear live filter",
},
{
key = "q",
callback = Api.tree.close,
desc = "close tree window",
},
{
key = "W",
callback = Api.tree.collapse_all,
desc = "collapse the whole tree",
},
{
key = "E",
callback = Api.tree.expand_all,
desc = "expand the whole tree, stopping after expanding |callbacks.expand_all.max_folder_discovery| folders; this might hang neovim for a while if running on a big folder",
},
{
key = "S",
callback = Api.tree.search_node,
desc = "prompt the user to enter a path and then expands the tree to match the path",
},
{
key = ".",
callback = Api.node.run.cmd,
desc = "enter vim command mode with the file the cursor is on",
},
{
key = "<C-k>",
callback = Api.node.show_info_popup,
desc = "toggle a popup with file infos about the file under the cursor",
},
{
key = "g?",
callback = Api.tree.toggle_help,
desc = "toggle help",
},
{
key = "m",
callback = Api.marks.toggle,
desc = "Toggle node in bookmarks",
},
{
key = "bmv",
callback = Api.marks.bulk.move,
desc = "Move all bookmarked nodes into specified location",
},
}
function M.set_keymaps(bufnr)
local opts = { noremap = true, silent = true, nowait = true, buffer = bufnr }
for _, km in ipairs(M.keymaps) do
local keys = type(km.key) == "table" and km.key or { km.key }
for _, key in ipairs(keys) do
vim.keymap.set("n", key, km.callback, opts)
end
end
end end
local function filter_default_mappings(keys_to_disable) vim.keymap.set('n', '<C-]>', api.tree.change_root_to_node, opts('CD'))
local new_map = {} vim.keymap.set('n', '<C-e>', api.node.open.replace_tree_buffer, opts('Open: In Place'))
for _, m in pairs(DEFAULT_KEYMAPS) do vim.keymap.set('n', '<C-k>', api.node.show_info_popup, opts('Info'))
local keys = type(m.key) == "table" and m.key or { m.key } vim.keymap.set('n', '<C-r>', api.fs.rename_sub, opts('Rename: Omit Filename'))
local reminding_keys = {} vim.keymap.set('n', '<C-t>', api.node.open.tab, opts('Open: New Tab'))
for _, key in pairs(keys) do vim.keymap.set('n', '<C-v>', api.node.open.vertical, opts('Open: Vertical Split'))
local found = false vim.keymap.set('n', '<C-x>', api.node.open.horizontal, opts('Open: Horizontal Split'))
for _, key_to_disable in pairs(keys_to_disable) do vim.keymap.set('n', '<BS>', api.node.navigate.parent_close, opts('Close Directory'))
if key_to_disable == key then vim.keymap.set('n', '<CR>', api.node.open.edit, opts('Open'))
found = true vim.keymap.set('n', '<Tab>', api.node.open.preview, opts('Open Preview'))
break vim.keymap.set('n', '>', api.node.navigate.sibling.next, opts('Next Sibling'))
end vim.keymap.set('n', '<', api.node.navigate.sibling.prev, opts('Previous Sibling'))
end vim.keymap.set('n', '.', api.node.run.cmd, opts('Run Command'))
if not found then vim.keymap.set('n', '-', api.tree.change_root_to_parent, opts('Up'))
table.insert(reminding_keys, key) vim.keymap.set('n', 'a', api.fs.create, opts('Create'))
end vim.keymap.set('n', 'bmv', api.marks.bulk.move, opts('Move Bookmarked'))
end vim.keymap.set('n', 'B', api.tree.toggle_no_buffer_filter, opts('Toggle No Buffer'))
if #reminding_keys > 0 then vim.keymap.set('n', 'c', api.fs.copy.node, opts('Copy'))
local map = vim.deepcopy(m) vim.keymap.set('n', 'C', api.tree.toggle_git_clean_filter, opts('Toggle Git Clean'))
map.key = reminding_keys vim.keymap.set('n', '[c', api.node.navigate.git.prev, opts('Prev Git'))
table.insert(new_map, map) vim.keymap.set('n', ']c', api.node.navigate.git.next, opts('Next Git'))
end vim.keymap.set('n', 'd', api.fs.remove, opts('Delete'))
end vim.keymap.set('n', 'D', api.fs.trash, opts('Trash'))
return new_map vim.keymap.set('n', 'E', api.tree.expand_all, opts('Expand All'))
end vim.keymap.set('n', 'e', api.fs.rename_basename, opts('Rename: Basename'))
vim.keymap.set('n', ']e', api.node.navigate.diagnostics.next, opts('Next Diagnostic'))
local function get_keymaps(keys_to_disable) vim.keymap.set('n', '[e', api.node.navigate.diagnostics.prev, opts('Prev Diagnostic'))
if keys_to_disable == true then vim.keymap.set('n', 'F', api.live_filter.clear, opts('Clean Filter'))
return {} vim.keymap.set('n', 'f', api.live_filter.start, opts('Filter'))
end vim.keymap.set('n', 'g?', api.tree.toggle_help, opts('Help'))
vim.keymap.set('n', 'gy', api.fs.copy.absolute_path, opts('Copy Absolute Path'))
if type(keys_to_disable) == "table" and #keys_to_disable > 0 then vim.keymap.set('n', 'H', api.tree.toggle_hidden_filter, opts('Toggle Dotfiles'))
return filter_default_mappings(keys_to_disable) vim.keymap.set('n', 'I', api.tree.toggle_gitignore_filter, opts('Toggle Git Ignore'))
end vim.keymap.set('n', 'J', api.node.navigate.sibling.last, opts('Last Sibling'))
vim.keymap.set('n', 'K', api.node.navigate.sibling.first, opts('First Sibling'))
return DEFAULT_KEYMAPS vim.keymap.set('n', 'm', api.marks.toggle, opts('Toggle Bookmark'))
vim.keymap.set('n', 'o', api.node.open.edit, opts('Open'))
vim.keymap.set('n', 'O', api.node.open.no_window_picker, opts('Open: No Window Picker'))
vim.keymap.set('n', 'p', api.fs.paste, opts('Paste'))
vim.keymap.set('n', 'P', api.node.navigate.parent, opts('Parent Directory'))
vim.keymap.set('n', 'q', api.tree.close, opts('Close'))
vim.keymap.set('n', 'r', api.fs.rename, opts('Rename'))
vim.keymap.set('n', 'R', api.tree.reload, opts('Refresh'))
vim.keymap.set('n', 's', api.node.run.system, opts('Run System'))
vim.keymap.set('n', 'S', api.tree.search_node, opts('Search'))
vim.keymap.set('n', 'U', api.tree.toggle_custom_filter, opts('Toggle Hidden'))
vim.keymap.set('n', 'W', api.tree.collapse_all, opts('Collapse'))
vim.keymap.set('n', 'x', api.fs.cut, opts('Cut'))
vim.keymap.set('n', 'y', api.fs.copy.filename, opts('Copy Name'))
vim.keymap.set('n', 'Y', api.fs.copy.relative_path, opts('Copy Relative Path'))
vim.keymap.set('n', '<2-LeftMouse>', api.node.open.edit, opts('Open'))
vim.keymap.set('n', '<2-RightMouse>', api.tree.change_root_to_node, opts('CD'))
-- END_DEFAULT_ON_ATTACH
end end
-- stylua: ignore end
function M.setup(opts) function M.setup(opts)
M.keymaps = get_keymaps(opts.remove_keymaps) if type(opts.on_attach) ~= "function" then
M.on_attach = M.default_on_attach
else
M.on_attach = opts.on_attach
end
end end
return M return M

View File

@ -1,49 +1,89 @@
local M = {} local M = {}
local function tidy_lhs(lhs)
-- nvim_buf_get_keymap replaces leading "<" with "<lt>" e.g. "<lt>CTRL-v>"
lhs = lhs:gsub("^<lt>", "<")
-- shorten ctrls
if lhs:lower():match "^<ctrl%-" then
lhs = lhs:lower():gsub("^<ctrl%-", "<C%-")
end
-- uppercase ctrls
if lhs:lower():match "^<c%-" then
lhs = lhs:upper()
end
-- space is not escaped
lhs = lhs:gsub(" ", "<Space>")
return lhs
end
--- Remove prefix 'nvim-tree: '
--- Hardcoded to keep default_on_attach simple
--- @param desc string
--- @return string
--- @return number
local function tidy_desc(desc)
return desc:gsub("^nvim%-tree: ", "")
end
-- sort lhs roughly as per :help index
local PAT_MOUSE = "^<.*Mouse"
local PAT_CTRL = "^<C%-"
local PAT_SPECIAL = "^<.+"
local function sort_lhs(a, b)
-- mouse last
if a:match(PAT_MOUSE) and not b:match(PAT_MOUSE) then
return false
elseif not a:match(PAT_MOUSE) and b:match(PAT_MOUSE) then
return true
end
-- ctrl first
if a:match(PAT_CTRL) and not b:match(PAT_CTRL) then
return true
elseif not a:match(PAT_CTRL) and b:match(PAT_CTRL) then
return false
end
-- special next
if a:match(PAT_SPECIAL) and not b:match(PAT_SPECIAL) then
return true
elseif not a:match(PAT_SPECIAL) and b:match(PAT_SPECIAL) then
return false
end
-- lowercase alpha characters only
return a:gsub("[^a-zA-Z]", ""):lower() < b:gsub("[^a-zA-Z]", ""):lower()
end
function M.compute_lines() function M.compute_lines()
local help_lines = { "HELP" } local help_lines = { "HELP" }
local help_hl = { { "NvimTreeRootFolder", 0, 0, #help_lines[1] } } local help_hl = { { "NvimTreeRootFolder", 0, 0, #help_lines[1] } }
local mappings = vim.tbl_filter(function(v)
return (v.cb ~= nil and v.cb ~= "") or (v.action ~= nil and v.action ~= "") local buf_keymaps = vim.api.nvim_buf_get_keymap(vim.api.nvim_get_current_buf(), "")
end, require("nvim-tree.actions").mappings)
local processed = {} local lines = vim.tbl_map(function(bkm)
for _, b in pairs(mappings) do return { lhs = tidy_lhs(bkm.lhs), desc = tidy_desc(bkm.desc) }
local cb = b.cb end, buf_keymaps)
local key = b.key
local name table.sort(lines, function(a, b)
if cb and cb:sub(1, 35) == require("nvim-tree.config").nvim_tree_callback("test"):sub(1, 35) then return sort_lhs(a.lhs, b.lhs)
name = cb:match "'[^']+'[^']*$"
name = name:match "'[^']+'"
elseif b.action then
name = b.action
else
name = (b.name ~= nil) and b.name or cb
name = '"' .. name .. '"'
end
table.insert(processed, { key, name, true })
end
table.sort(processed, function(a, b)
return (a[3] == b[3] and (a[2] < b[2] or (a[2] == b[2] and #a[1] < #b[1]))) or (a[3] and not b[3])
end) end)
local num = 0 local num = 0
for _, val in pairs(processed) do for _, p in pairs(lines) do
local keys = type(val[1]) == "string" and { val[1] } or val[1]
local map_name = val[2]
local builtin = val[3]
for _, key in pairs(keys) do
num = num + 1 num = num + 1
local bind_string = string.format("%6s : %s", key, map_name) local bind_string = string.format("%-5s %s", p.lhs, p.desc)
local hl_len = math.max(5, string.len(p.lhs))
table.insert(help_lines, bind_string) table.insert(help_lines, bind_string)
local hl_len = math.max(6, string.len(key)) + 2
table.insert(help_hl, { "NvimTreeFolderName", num, 0, hl_len }) table.insert(help_hl, { "NvimTreeFolderName", num, 0, hl_len })
if not builtin then
table.insert(help_hl, { "NvimTreeFileRenamed", num, hl_len, -1 }) table.insert(help_hl, { "NvimTreeFileRenamed", num, hl_len, -1 })
end end
end
end
return help_lines, help_hl return help_lines, help_hl
end end

View File

@ -276,8 +276,10 @@ end
function M.key_by(tbl, key) function M.key_by(tbl, key)
local keyed = {} local keyed = {}
for _, val in ipairs(tbl) do for _, val in ipairs(tbl) do
if val[key] then
keyed[val[key]] = val keyed[val[key]] = val
end end
end
return keyed return keyed
end end

View File

@ -93,13 +93,7 @@ local function create_buffer(bufnr)
vim.bo[M.get_bufnr()][option] = value vim.bo[M.get_bufnr()][option] = value
end end
if type(M.on_attach) == "function" then require("nvim-tree.keymap").on_attach(M.get_bufnr())
require("nvim-tree.keymap").set_keymaps(M.get_bufnr())
M.on_attach(M.get_bufnr())
else
require("nvim-tree.actions").apply_mappings(M.get_bufnr())
end
events._dispatch_tree_attached_post(M.get_bufnr())
end end
local function get_size(size) local function get_size(size)

View File

@ -1,84 +0,0 @@
-- luacheck:ignore 113
---@diagnostic disable: undefined-global
-- write DEFAULT_MAPPINGS in various formats
local max_key_help = 0
local max_key_lua = 0
local max_action_help = 0
local outs_help = {}
local outs_lua = {}
for _, m in pairs(DEFAULT_MAPPINGS) do
local out
if type(m.key) == "table" then
local first = true
local keys_lua = "key = {"
for _, sub_key in pairs(m.key) do
-- lua
keys_lua = string.format('%s%s "%s"', keys_lua, first and "" or ",", sub_key)
-- help
out = {}
if first then
out.action = m.action
out.desc = m.desc
first = false
else
out.action = ""
out.desc = ""
end
out.key = string.format("`%s`", sub_key)
max_action_help = math.max(#out.action, max_action_help)
max_key_help = math.max(#out.key, max_key_help)
table.insert(outs_help, out)
end
-- lua
out = {}
out.key = string.format("%s },", keys_lua)
table.insert(outs_lua, out)
else
-- help
out = {}
out.action = m.action
out.desc = m.desc
out.key = string.format("`%s`", m.key)
table.insert(outs_help, out)
max_action_help = math.max(#out.action, max_action_help)
max_key_help = math.max(#out.key, max_key_help)
-- lua
out = {}
out.key = string.format('key = "%s",', m.key)
table.insert(outs_lua, out)
end
--lua
out.action = string.format('action = "%s"', m.action)
max_key_lua = math.max(#out.key, max_key_lua)
end
-- help
local file = io.open("/tmp/DEFAULT_MAPPINGS.help", "w")
io.output(file)
io.write "\n"
local fmt = string.format("%%-%d.%ds %%-%d.%ds %%s\n", max_key_help, max_key_help, max_action_help, max_action_help)
for _, m in pairs(outs_help) do
if m.action == "" then
io.write(string.format("%s\n", m.key))
else
io.write(string.format(fmt, m.key, m.action, m.desc))
end
end
io.write "\n"
io.close(file)
-- lua
file = io.open("/tmp/DEFAULT_MAPPINGS.lua", "w")
io.output(file)
fmt = string.format(" { %%-%d.%ds %%s },\n", max_key_lua, max_key_lua)
for _, m in pairs(outs_lua) do
io.write(string.format(fmt, m.key, m.action))
end
io.close(file)

View File

@ -1,10 +1,13 @@
#!/bin/sh #!/bin/sh
# run after changing nvim-tree.lua DEFAULT_OPTS or nvim-tree/actions/init.lua M.mappings # run after changing nvim-tree.lua DEFAULT_OPTS or keymap.lua M.default_on_attach
# scrapes and updates nvim-tree-lua.txt # scrapes and updates nvim-tree-lua.txt and keymap-legacy.lua
# run from repository root: scripts/update-default-opts.sh # run from repository root: scripts/update-help.sh
#
# DEFAULT_OPTS
#
begin="BEGIN_DEFAULT_OPTS" begin="BEGIN_DEFAULT_OPTS"
end="END_DEFAULT_OPTS" end="END_DEFAULT_OPTS"
@ -18,16 +21,24 @@ sed -e "s/^ / /" /tmp/DEFAULT_OPTS.2.lua > /tmp/DEFAULT_OPTS.6.lua
sed -i -e "/${begin}/,/${end}/{ /${begin}/{p; r /tmp/DEFAULT_OPTS.6.lua sed -i -e "/${begin}/,/${end}/{ /${begin}/{p; r /tmp/DEFAULT_OPTS.6.lua
}; /${end}/p; d; }" doc/nvim-tree-lua.txt }; /${end}/p; d; }" doc/nvim-tree-lua.txt
#
# DEFAULT_ON_ATTACH
#
begin="BEGIN_DEFAULT_MAPPINGS" begin="BEGIN_DEFAULT_ON_ATTACH"
end="END_DEFAULT_MAPPINGS" end="END_DEFAULT_ON_ATTACH"
# generate various DEFAULT_MAPPINGS # scrape DEFAULT_ON_ATTACH, indented at 2
sed -n -e "/${begin}/,/${end}/{ /${begin}/d; /${end}/d; p; }" lua/nvim-tree/actions/init.lua > /tmp/DEFAULT_MAPPINGS.M.lua sed -n -e "/${begin}/,/${end}/{ /${begin}/d; /${end}/d; p; }" lua/nvim-tree/keymap.lua > /tmp/DEFAULT_ON_ATTACH.2.lua
cat /tmp/DEFAULT_MAPPINGS.M.lua scripts/generate_default_mappings.lua | lua
# indent some more
sed -e "s/^ / /" /tmp/DEFAULT_ON_ATTACH.2.lua > /tmp/DEFAULT_ON_ATTACH.4.lua
# help, indented at 4
sed -i -e "/${begin}/,/${end}/{ /${begin}/{p; r /tmp/DEFAULT_ON_ATTACH.4.lua
}; /${end}/p; d; }" doc/nvim-tree-lua.txt
# legacy keymap, indented at 2
sed -i -e "/${begin}/,/${end}/{ /${begin}/{p; r /tmp/DEFAULT_ON_ATTACH.2.lua
}; /${end}/p; d; }" lua/nvim-tree/keymap-legacy.lua
# help
sed -i -e "/${begin}/,/${end}/{ /${begin}/{p; r /tmp/DEFAULT_MAPPINGS.lua
}; /${end}/p; d }" doc/nvim-tree-lua.txt
sed -i -e "/^DEFAULT MAPPINGS/,/^>$/{ /^DEFAULT MAPPINGS/{p; r /tmp/DEFAULT_MAPPINGS.help
}; /^>$/p; d }" doc/nvim-tree-lua.txt