diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index ca81303ced3..c4c8645e552 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -542,6 +542,34 @@ performance. Idle milliseconds between filesystem change and action. Type: `number`, Default: `50` (ms) +*nvim-tree.on_attach* +Function ran when creating the nvim-tree buffer. +This can be used to attach keybindings to the tree buffer. +When on_attach is "disabled", it will use the older mapping strategy, otherwise it +will use the newer one. +> + on_attach = function(bufnr) + local inject_node = require("nvim-tree.utils").inject_node + + vim.keymap.set("n", "n", inject_node(function(node) + if node then + print(node.absolute_path) + end + end), { buffer = bufnr, noremap = true }) + + vim.bo[bufnr].path = "/tmp" + end +< + Type: `function(bufnr)`, Default: `"disable"` + +*nvim-tree.remove_keymaps* +This can be used to remove the default mappings in the tree. +- Remove specific keys by passing a `string` table of keys + eg. {"", "", "o", ""} +- Remove all default mappings by passing `true` +- Ignore by passing `false` + Type: `bool` or `{string}`, Default: `false` + *nvim-tree.view* Window / buffer setup. @@ -599,14 +627,11 @@ Window / buffer setup. Configuration options for |nvim-tree-mappings| *nvim-tree.view.mappings.custom_only* - Will use only the provided user mappings and not the default otherwise, - extends the default mappings with the provided user mappings. - Type: `boolean`, Default: `false` + DEPRECATED: see |nvim-tree.remove_keymaps| + *nvim-tree.view.mappings.list* - A list of keymaps that will extend or override the default keymaps. - Type: `table` - Default: see |nvim-tree-default-mappings| + DEPRECATED: see |nvim-tree.on_attach| *nvim-tree.renderer* UI rendering setup @@ -1045,130 +1070,56 @@ exists. ============================================================================== 6. MAPPINGS *nvim-tree-mappings* -The `list` option in `view.mappings.list` is a table of +Setting your own mapping in the configuration is deprecated, see |nvim-tree.on_attach| now. + +You can remove default mappings with |nvim-tree.remove_keymaps|. + +``, `o`, `<2-LeftMouse>` open a file or folder; root will cd to the above directory +`` edit the file in place, effectively replacing the tree explorer +`O` same as (edit) with no window picker +``, `<2-RightMouse>` cd in the directory under the cursor +`` open the file in a vertical split +`` open the file in a horizontal split +`` open the file in a new tab +`<` navigate to the previous sibling of current file/directory +`>` navigate to the next sibling of current file/directory +`P` move cursor to the parent directory +`` close current opened directory or parent +`` open the file as a preview (keeps the cursor in the tree) +`K` navigate to the first sibling of current file/directory +`J` navigate to the last sibling of current file/directory +`I` toggle visibility of files/folders hidden via |git.ignore| option +`H` toggle visibility of dotfiles via |filters.dotfiles| option +`U` toggle visibility of files/folders hidden via |filters.custom| option +`R` refresh the tree +`a` add a file; leaving a trailing `/` will add a directory +`d` delete a file (will prompt for confirmation) +`D` trash a file via |trash| option +`r` rename a file +`` rename a file and omit the filename on input +`x` add/remove file/directory to cut clipboard +`c` add/remove file/directory to copy clipboard +`p` paste from clipboard; cut clipboard has precedence over copy; will prompt for confirmation +`y` copy name to system clipboard +`Y` copy relative path to system clipboard +`gy` copy absolute path to system clipboard +`[e` go to next diagnostic item +`[c` go to next git item +`]e` go to prev diagnostic item +`]c` go to prev git item +`-` navigate up to the parent directory of the current file/directory +`s` open a file with default system application or a folder with default file manager, using |system_open| option +`f` live filter nodes dynamically based on regex matching. +`F` clear live filter +`q` close tree window +`W` collapse the whole tree +`E` 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` prompt the user to enter a path and then expands the tree to match the path +`.` enter vim command mode with the file the cursor is on +`` toggle a popup with file infos about the file under the cursor +`g?` toggle help +`m` Toggle node in bookmarks -- `key` can be either a string or a table of string (lhs) -- `action` is the name of the action, set to `""` to remove default action -- `action_cb` is the function that will be called, it receives the node as a parameter. Optional for default actions -- `mode` is normal by default -> - local tree_cb = require'nvim-tree.config'.nvim_tree_callback - - local function print_node_path(node) { - print(node.absolute_path) - } - - local list = { - { key = {"", "o" }, action = "edit", mode = "n"}, - { key = "p", action = "print_path", action_cb = print_node_path }, - { key = "s", cb = tree_cb("vsplit") }, --tree_cb and the cb property are deprecated - { key = "<2-RightMouse>", action = "" }, -- will remove default cd action - } -< -Mouse support defined in |KeyBindings| - -DEFAULT MAPPINGS *nvim-tree-default-mappings* - -`` edit open a file or folder; root will cd to the above directory -`o` -`<2-LeftMouse>` -`` edit_in_place edit the file in place, effectively replacing the tree explorer -`O` edit_no_picker same as (edit) with no window picker -`` cd cd in the directory under the cursor -`<2-RightMouse>` -`` vsplit open the file in a vertical split -`` split open the file in a horizontal split -`` 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 -`` close_node close current opened directory or parent -`` 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 -`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 -`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 -`` full_rename rename a file and omit the filename on input -`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 -`` 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 = { "", "o", "<2-LeftMouse>" }, action = "edit" }, - { key = "", action = "edit_in_place" }, - { key = "O", action = "edit_no_picker" }, - { key = { "", "<2-RightMouse>" }, action = "cd" }, - { key = "", action = "vsplit" }, - { key = "", action = "split" }, - { key = "", action = "tabnew" }, - { key = "<", action = "prev_sibling" }, - { key = ">", action = "next_sibling" }, - { key = "P", action = "parent_node" }, - { key = "", action = "close_node" }, - { key = "", action = "preview" }, - { key = "K", action = "first_sibling" }, - { key = "J", action = "last_sibling" }, - { key = "I", action = "toggle_git_ignored" }, - { key = "H", action = "toggle_dotfiles" }, - { 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 = "", action = "full_rename" }, - { 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 = "", 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* diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 80ee741d613..9147e8e15d6 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -434,6 +434,8 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS sync_root_with_cwd = false, reload_on_bufenter = false, respect_buf_cwd = false, + on_attach = "disable", -- function(bufnr). If nil, will use the deprecated mapping strategy + remove_keymaps = false, -- boolean (disable totally or not) or list of key (lhs) view = { adaptive_size = false, centralize_selection = false, @@ -445,6 +447,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS number = false, relativenumber = false, signcolumn = "yes", + -- @deprecated mappings = { custom_only = false, list = { @@ -605,6 +608,8 @@ end local FIELD_OVERRIDE_TYPECHECK = { width = { string = true, ["function"] = true, number = true }, height = { string = true, ["function"] = true, number = true }, + remove_keymaps = { boolean = true, table = true }, + on_attach = { ["function"] = true, string = true }, } local function validate_options(conf) @@ -682,6 +687,7 @@ function M.setup(conf) log.raw("config", "%s\n", vim.inspect(opts)) require("nvim-tree.actions").setup(opts) + require("nvim-tree.keymap").setup(opts) require("nvim-tree.colors").setup() require("nvim-tree.diagnostics").setup(opts) require("nvim-tree.explorer").setup(opts) diff --git a/lua/nvim-tree/actions/init.lua b/lua/nvim-tree/actions/init.lua index 943403d0261..e3b9366fccb 100644 --- a/lua/nvim-tree/actions/init.lua +++ b/lua/nvim-tree/actions/init.lua @@ -1,3 +1,5 @@ +-- @deprecated: new implemention in nvim-tree.keymap. Please do not edit this file. + local a = vim.api local log = require "nvim-tree.log" diff --git a/lua/nvim-tree/keymap.lua b/lua/nvim-tree/keymap.lua new file mode 100644 index 00000000000..f8cd5fc6bfd --- /dev/null +++ b/lua/nvim-tree/keymap.lua @@ -0,0 +1,286 @@ +local Api = require "nvim-tree.api" + +local M = {} + +local DEFAULT_KEYMAPS = { + { + key = { "", "o", "<2-LeftMouse>" }, + callback = Api.node.open.edit, + desc = "open a file or folder; root will cd to the above directory", + }, + { + key = "", + 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 = { "", "<2-RightMouse>" }, + callback = Api.tree.change_root_to_node, + desc = "cd in the directory under the cursor", + }, + { + key = "", + callback = Api.node.open.vertical, + desc = "open the file in a vertical split", + }, + { + key = "", + callback = Api.node.open.horizontal, + desc = "open the file in a horizontal split", + }, + { + key = "", + 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 = "", + callback = Api.node.navigate.parent_close, + desc = "close current opened directory or parent", + }, + { + key = "", + 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 = "", + 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 = "", + 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 + +local function get_keymaps(keys_to_disable) + if keys_to_disable == true then + return {} + end + + if type(keys_to_disable) == "table" and #keys_to_disable > 0 then + local new_map = {} + for _, m in pairs(DEFAULT_KEYMAPS) do + local keys = type(m.key) == "table" and m.key or { m.key } + local reminding_keys = {} + for _, key in pairs(keys) do + local found = false + for _, key_to_disable in pairs(keys_to_disable) do + if key_to_disable == key then + found = true + break + end + end + if not found then + table.insert(reminding_keys, key) + end + end + if #reminding_keys > 0 then + local map = vim.deepcopy(m) + map.key = reminding_keys + table.insert(new_map, map) + end + end + return new_map + end + + return DEFAULT_KEYMAPS +end + +function M.setup(opts) + M.keymaps = get_keymaps(opts) +end + +return M diff --git a/lua/nvim-tree/utils.lua b/lua/nvim-tree/utils.lua index 5168af74cec..6ff48111138 100644 --- a/lua/nvim-tree/utils.lua +++ b/lua/nvim-tree/utils.lua @@ -400,4 +400,10 @@ function M.array_remove(array, item) end end +function M.inject_node(f) + return function() + f(require("nvim-tree.lib").get_node_at_cursor()) + end +end + return M diff --git a/lua/nvim-tree/view.lua b/lua/nvim-tree/view.lua index c76fc91427c..4e5f1c85abc 100644 --- a/lua/nvim-tree/view.lua +++ b/lua/nvim-tree/view.lua @@ -92,7 +92,12 @@ local function create_buffer(bufnr) vim.bo[M.get_bufnr()][option] = value end - require("nvim-tree.actions").apply_mappings(M.get_bufnr()) + if type(M.on_attach) == "function" then + 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 end local function get_size() @@ -426,6 +431,7 @@ function M.setup(opts) M.View.winopts.number = options.number M.View.winopts.relativenumber = options.relativenumber M.View.winopts.signcolumn = options.signcolumn + M.on_attach = opts.on_attach end return M