diff --git a/README.md b/README.md index 7b6a6c0ce9a..b0b535c2940 100644 --- a/README.md +++ b/README.md @@ -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) +## 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 [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 require("nvim-tree").setup({ sort_by = "case_sensitive", - view = { - width = 30, - mappings = { - list = { - { key = "u", action = "dir_up" }, - }, - }, - }, renderer = { 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) -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 @@ -114,10 +110,10 @@ Basic commands: ## 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. +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 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 -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. 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) - -### 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) +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) ## Contributing diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 0d212c62ba9..863e37c794a 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -11,6 +11,8 @@ CONTENTS *nvim-tree* 4. Setup/Configuration |nvim-tree-setup| 5. Api |nvim-tree-api| 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| 8. Events |nvim-tree-events| 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* -|:NvimTreeOpen| +*:NvimTreeOpen* opens the tree. Takes an optional path argument. -|:NvimTreeClose| +*:NvimTreeClose* closes the tree -|:NvimTreeToggle| +*:NvimTreeToggle* 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 -|:NvimTreeRefresh| +*:NvimTreeRefresh* refresh the tree -|:NvimTreeFindFile| +*:NvimTreeFindFile* 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. -|:NvimTreeFindFileToggle| +*:NvimTreeFindFileToggle* close the tree or change the cursor in the tree for the current bufname, 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. -|:NvimTreeClipboard| +*:NvimTreeClipboard* Print clipboard content for both cut and copy -|:NvimTreeResize| +*:NvimTreeResize* 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 @@ -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 `:NvimTreeResize +20` adds the value 20 to the current width. -|:NvimTreeCollapse| +*:NvimTreeCollapse* Collapses the nvim-tree recursively. -|:NvimTreeCollapseKeepBuffers| +*:NvimTreeCollapseKeepBuffers* Collapses the nvim-tree recursively, but keep the directories open, which are 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* @@ -184,7 +192,7 @@ Subsequent calls to setup will replace the previous configuration. sync_root_with_cwd = false, reload_on_bufenter = false, respect_buf_cwd = false, - on_attach = "disable", + on_attach = "default", remove_keymaps = false, select_prompts = false, view = { @@ -682,22 +690,13 @@ performance. Type: {string}, Default: `{}` *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. - Type: `function(bufnr)`, Default: `"disable"` - e.g. > - local api = require("nvim-tree.api") - - local function on_attach(bufnr) - vim.keymap.set("n", "", 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 -< +Runs when creating the nvim-tree buffer. Use this to set your nvim-tree +specific mappings. See |nvim-tree-mappings|. +When on_attach is not a function, |nvim-tree-mappings-default| will be called. + Type: `function(bufnr) | string`, Default: `"default"` + *nvim-tree.remove_keymaps* +Deprecated: please see |nvim-tree-mappings-legacy| This can be used to remove the default mappings in the tree. - Remove specific keys by passing a `string` table of keys eg. {"", "", "o", ""} @@ -774,17 +773,18 @@ Window / buffer setup. Type: `string`, Default: `"yes"` *nvim-tree.view.mappings* - Configuration options for |nvim-tree-mappings| + Deprecated: please see |nvim-tree-mappings-legacy| *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. + Overrides |nvim-tree.remove_keymaps| Type: `boolean`, Default: `false` *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| + Default: see |nvim-tree-mappings-legacy| *nvim-tree.view.float* Configuration options for floating window @@ -1426,15 +1426,16 @@ api.tree.toggle_help() *nvim-tree.api.tree.toggle_help()* - navigate.select api.config.mappings.active() *nvim-tree.api.config.mappings.active()* - Retrieve a clone of the currently active mappings: - |nvim-tree-default-mappings| with |nvim-tree.view.mappings| applied. + Deprecated: only functions when using legacy |nvim-tree.view.mappings| + Retrieve a clone of the currently active mappings: defaults + user. Changing the active mappings will require a call to |nvim-tree-setup| Return: ~ (table) as per |nvim-tree.view.mappings.list| 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: ~ (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* -Setting your own mapping in the configuration will soon be deprecated, see -|nvim-tree.on_attach| for experimental replacement. +Mappings are set via the |nvim-tree.on_attach| function, which is run upon +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 ``. + +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', '', api.tree.change_root_to_node, opts('CD')) + vim.keymap.set('n', '', api.node.open.replace_tree_buffer, opts('Open: In Place')) + vim.keymap.set('n', '', api.node.show_info_popup, opts('Info')) + vim.keymap.set('n', '', api.fs.rename_sub, opts('Rename: Omit Filename')) + vim.keymap.set('n', '', api.node.open.tab, opts('Open: New Tab')) + vim.keymap.set('n', '', api.node.open.vertical, opts('Open: Vertical Split')) + vim.keymap.set('n', '', api.node.open.horizontal, opts('Open: Horizontal Split')) + vim.keymap.set('n', '', api.node.navigate.parent_close, opts('Close Directory')) + vim.keymap.set('n', '', api.node.open.edit, opts('Open')) + vim.keymap.set('n', '', 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: {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 ``. - -Single right / middle mouse mappings will requre changes to |mousemodel| or |mouse|. - -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 -`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 -`` 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 -`` 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 = "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 = "", 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 = "", 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 507855b77cc..689ad42305c 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -14,6 +14,7 @@ local git = require "nvim-tree.git" local filters = require "nvim-tree.explorer.filters" local modified = require "nvim-tree.modified" local notify = require "nvim-tree.notify" +local keymap_legacy = require "nvim-tree.keymap-legacy" local _config = {} @@ -68,9 +69,6 @@ function M.change_root(filepath, bufnr) change_dir.fn(vim.fn.fnamemodify(filepath, ":p:h")) end ----@deprecated -M.on_keypress = require("nvim-tree.actions.dispatch").dispatch - function M.open_replacing_current_buffer(cwd) if view.is_visible() then return @@ -379,6 +377,7 @@ local function setup_vim_commands() vim.api.nvim_create_user_command("NvimTreeCollapseKeepBuffers", function() collapse_all.fn(true) end, { bar = true }) + vim.api.nvim_create_user_command("NvimTreeGenerateOnAttach", keymap_legacy.cmd_generate_on_attach, {}) end function M.change_dir(name) @@ -562,7 +561,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS sync_root_with_cwd = false, reload_on_bufenter = false, respect_buf_cwd = false, - on_attach = "disable", + on_attach = "default", remove_keymaps = false, select_prompts = false, view = { @@ -862,6 +861,7 @@ function M.setup(conf) validate_options(conf) local opts = merge_options(conf) + local netrw_disabled = opts.disable_netrw or opts.hijack_netrw _config.root_dirs = opts.root_dirs @@ -885,6 +885,8 @@ function M.setup(conf) log.raw("config", "%s\n", vim.inspect(opts)) end + keymap_legacy.generate_legacy_on_attach(opts) + require("nvim-tree.actions").setup(opts) require("nvim-tree.keymap").setup(opts) require("nvim-tree.colors").setup() diff --git a/lua/nvim-tree/actions/dispatch.lua b/lua/nvim-tree/actions/dispatch.lua deleted file mode 100644 index a3781f80a81..00000000000 --- a/lua/nvim-tree/actions/dispatch.lua +++ /dev/null @@ -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 diff --git a/lua/nvim-tree/actions/init.lua b/lua/nvim-tree/actions/init.lua index 868ee0a502c..5dab40b1fb7 100644 --- a/lua/nvim-tree/actions/init.lua +++ b/lua/nvim-tree/actions/init.lua @@ -1,415 +1,4 @@ --- @deprecated: new implementation in nvim-tree.keymap. Please do not edit this file. - -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 = { "", "o", "<2-LeftMouse>" }, - action = "edit", - desc = "open a file or folder; root will cd to the above directory", - }, - { - key = "", - 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 = { "", "<2-RightMouse>" }, - action = "cd", - desc = "cd in the directory under the cursor", - }, - { - key = "", - action = "vsplit", - desc = "open the file in a vertical split", - }, - { - key = "", - action = "split", - desc = "open the file in a horizontal split", - }, - { - key = "", - 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 = "", - action = "close_node", - desc = "close current opened directory or parent", - }, - { - key = "", - 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 = "", - 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 = "", - 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 +local M = {} function M.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.copy-paste").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 return M diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index 11f80b2d922..515a415ff90 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -22,7 +22,9 @@ end ---@field find_file 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 ---@field path string|nil @@ -31,7 +33,9 @@ Api.tree.open = require("nvim-tree").open ---@field update_root boolean|nil default false ---@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 @@ -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.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.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) 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.select = require("nvim-tree.marks.navigation").select -Api.config.mappings.active = require("nvim-tree.actions").active_mappings_clone -Api.config.mappings.default = require("nvim-tree.actions").default_mappings_clone +Api.config.mappings.active = function() + 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 diff --git a/lua/nvim-tree/config.lua b/lua/nvim-tree/config.lua deleted file mode 100644 index df87c41d2d6..00000000000 --- a/lua/nvim-tree/config.lua +++ /dev/null @@ -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("lua require'nvim-tree.actions.dispatch'.dispatch('%s')", callback_name) -end - -return M diff --git a/lua/nvim-tree/keymap-legacy.lua b/lua/nvim-tree/keymap-legacy.lua new file mode 100644 index 00000000000..be6727ed7bd --- /dev/null +++ b/lua/nvim-tree/keymap-legacy.lua @@ -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', '', api.tree.change_root_to_node, opts('CD')) + vim.keymap.set('n', '', api.node.open.replace_tree_buffer, opts('Open: In Place')) + vim.keymap.set('n', '', api.node.show_info_popup, opts('Info')) + vim.keymap.set('n', '', api.fs.rename_sub, opts('Rename: Omit Filename')) + vim.keymap.set('n', '', api.node.open.tab, opts('Open: New Tab')) + vim.keymap.set('n', '', api.node.open.vertical, opts('Open: Vertical Split')) + vim.keymap.set('n', '', api.node.open.horizontal, opts('Open: Horizontal Split')) + vim.keymap.set('n', '', api.node.navigate.parent_close, opts('Close Directory')) + vim.keymap.set('n', '', api.node.open.edit, opts('Open')) + vim.keymap.set('n', '', 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 = { "", "o", "<2-LeftMouse>" }, desc = "Open", fn = api.node.open.edit, n = "api.node.open.edit" }, + edit_in_place = { key = "", 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 = { "", "<2-RightMouse>" }, desc = "CD", fn = api.tree.change_root_to_node, n = "api.tree.change_root_to_node" }, + vsplit = { key = "", desc = "Open: Vertical Split", fn = api.node.open.vertical, n = "api.node.open.vertical" }, + split = { key = "", desc = "Open: Horizontal Split", fn = api.node.open.horizontal, n = "api.node.open.horizontal" }, + tabnew = { key = "", 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 = "", desc = "Close Directory", fn = api.node.navigate.parent_close, n = "api.node.navigate.parent_close" }, + preview = { key = "", 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 = "", 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 = "", 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 diff --git a/lua/nvim-tree/keymap.lua b/lua/nvim-tree/keymap.lua index 2c26a3a4d7c..a6fc23f983a 100644 --- a/lua/nvim-tree/keymap.lua +++ b/lua/nvim-tree/keymap.lua @@ -1,290 +1,76 @@ -local Api = require "nvim-tree.api" +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 filter_default_mappings(keys_to_disable) - 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 - -local function get_keymaps(keys_to_disable) - if keys_to_disable == true then - return {} +-- stylua: ignore start +function M.default_on_attach(bufnr) + -- BEGIN_DEFAULT_ON_ATTACH + local opts = function(desc) + return { desc = 'nvim-tree: ' .. desc, buffer = bufnr, noremap = true, silent = true, nowait = true } end - if type(keys_to_disable) == "table" and #keys_to_disable > 0 then - return filter_default_mappings(keys_to_disable) - end - - return DEFAULT_KEYMAPS + vim.keymap.set('n', '', api.tree.change_root_to_node, opts('CD')) + vim.keymap.set('n', '', api.node.open.replace_tree_buffer, opts('Open: In Place')) + vim.keymap.set('n', '', api.node.show_info_popup, opts('Info')) + vim.keymap.set('n', '', api.fs.rename_sub, opts('Rename: Omit Filename')) + vim.keymap.set('n', '', api.node.open.tab, opts('Open: New Tab')) + vim.keymap.set('n', '', api.node.open.vertical, opts('Open: Vertical Split')) + vim.keymap.set('n', '', api.node.open.horizontal, opts('Open: Horizontal Split')) + vim.keymap.set('n', '', api.node.navigate.parent_close, opts('Close Directory')) + vim.keymap.set('n', '', api.node.open.edit, opts('Open')) + vim.keymap.set('n', '', 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 +-- stylua: ignore end 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 return M diff --git a/lua/nvim-tree/renderer/help.lua b/lua/nvim-tree/renderer/help.lua index 61f00eb5827..8a9f4ded788 100644 --- a/lua/nvim-tree/renderer/help.lua +++ b/lua/nvim-tree/renderer/help.lua @@ -1,48 +1,88 @@ local M = {} +local function tidy_lhs(lhs) + -- nvim_buf_get_keymap replaces leading "<" with "" e.g. "CTRL-v>" + lhs = lhs:gsub("^", "<") + + -- shorten ctrls + if lhs:lower():match "^") + + 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 = "^ /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 +# +# DEFAULT_ON_ATTACH +# -begin="BEGIN_DEFAULT_MAPPINGS" -end="END_DEFAULT_MAPPINGS" +begin="BEGIN_DEFAULT_ON_ATTACH" +end="END_DEFAULT_ON_ATTACH" -# generate various DEFAULT_MAPPINGS -sed -n -e "/${begin}/,/${end}/{ /${begin}/d; /${end}/d; p; }" lua/nvim-tree/actions/init.lua > /tmp/DEFAULT_MAPPINGS.M.lua -cat /tmp/DEFAULT_MAPPINGS.M.lua scripts/generate_default_mappings.lua | lua +# scrape DEFAULT_ON_ATTACH, indented at 2 +sed -n -e "/${begin}/,/${end}/{ /${begin}/d; /${end}/d; p; }" lua/nvim-tree/keymap.lua > /tmp/DEFAULT_ON_ATTACH.2.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