From 1685484738377927c4a97a90a4dc031e54c29997 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 2 Aug 2022 21:59:51 +1000 Subject: [PATCH 01/26] doc: reinstate mapping doc, mark on_attach as experimental (#1481) --- doc/nvim-tree-lua.txt | 182 ++++++++++++++++++++++++++++++------------ lua/nvim-tree.lua | 1 - 2 files changed, 132 insertions(+), 51 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index bc6452e0..ea099490 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -174,6 +174,8 @@ 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", -- 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, @@ -628,11 +630,14 @@ Window / buffer setup. Configuration options for |nvim-tree-mappings| *nvim-tree.view.mappings.custom_only* - DEPRECATED: see |nvim-tree.remove_keymaps| - + 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` *nvim-tree.view.mappings.list* - DEPRECATED: see |nvim-tree.on_attach| + A list of keymaps that will extend or override the default keymaps. + Type: `table` + Default: see |nvim-tree-default-mappings| *nvim-tree.renderer* UI rendering setup @@ -1076,55 +1081,132 @@ exists. ============================================================================== 6. MAPPINGS *nvim-tree-mappings* -Setting your own mapping in the configuration is deprecated, see |nvim-tree.on_attach| now. +Setting your own mapping in the configuration will soon be deprecated, see |nvim-tree.on_attach| for experimental replacement. -You can remove default mappings with |nvim-tree.remove_keymaps|. +The `list` option in `view.mappings.list` is a table of -``, `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 2baa9235..44fed7de 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -447,7 +447,6 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS number = false, relativenumber = false, signcolumn = "yes", - -- @deprecated mappings = { custom_only = false, list = { From 7323c81bd6209c247248244b12682cc345630301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Cie=C5=9Bla?= Date: Sat, 6 Aug 2022 07:40:07 +0200 Subject: [PATCH 02/26] feat(view): Floating nvim tree window #1377 (#1462) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Simple mock-up of floating nvim-tree window * Passing whole table to nvim_open_win() * Run update-help.sh * Use vim.api alias * Add comment to float options * Added `anchor` to float options * Enabling float window enforces `actions.open_file.quit_on_open` * Added documentation * add view.float.open_win_config, skipping validation * Made nvim-tree window closes when float is enabled * Close nvim-tree window when out of focus * Update help Co-authored-by: Krzysztof Cieśla Co-authored-by: Alexander Courtis --- doc/nvim-tree-lua.txt | 31 +++++++++++++ lua/nvim-tree.lua | 57 ++++++++++++++++-------- lua/nvim-tree/actions/node/open-file.lua | 2 +- lua/nvim-tree/view.lua | 9 +++- 4 files changed, 78 insertions(+), 21 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index ea099490..2b59d5cc 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -187,12 +187,24 @@ Subsequent calls to setup will replace the previous configuration. number = false, relativenumber = false, signcolumn = "yes", + -- @deprecated mappings = { custom_only = false, list = { -- user mappings go here }, }, + float = { + enable = false, + open_win_config = { + relative = "editor", + border = "rounded", + width = 30, + height = 30, + row = 1, + col = 1, + }, + }, }, renderer = { add_trailing = false, @@ -639,6 +651,25 @@ Window / buffer setup. Type: `table` Default: see |nvim-tree-default-mappings| + *nvim-tree.view.float* + Configuration options for floating window + + *nvim-tree.view.float.enable* + Display nvim-tree window as float (enforces |nvim-tree.actions.open_file.quit_on_open| if set). + Type: `boolean`, Default: `false` + + *nvim-tree.view.float.open_win_config* + Floating window config. See |nvim_open_win| for more details. + Type: `table`, Default: + `{` + `relative = "editor",` + `border = "rounded",` + `width = 30,` + `height = 30,` + `row = 1,` + `col = 1,` + `}` + *nvim-tree.renderer* UI rendering setup diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 44fed7de..8e8c6d04 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -414,6 +414,10 @@ local function setup_autocommands(opts) end, }) end + + if opts.view.float.enable then + create_nvim_tree_autocmd("WinLeave", { pattern = "NvimTree_*", callback = view.close }) + end end local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS @@ -453,6 +457,17 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS -- user mappings go here }, }, + float = { + enable = false, + open_win_config = { + relative = "editor", + border = "rounded", + width = 30, + height = 30, + row = 1, + col = 1, + }, + }, }, renderer = { add_trailing = false, @@ -605,6 +620,10 @@ local function merge_options(conf) return vim.tbl_deep_extend("force", DEFAULT_OPTS, conf or {}) end +local FIELD_SKIP_VALIDATE = { + open_win_config = true, +} + local FIELD_OVERRIDE_TYPECHECK = { width = { string = true, ["function"] = true, number = true }, height = { string = true, ["function"] = true, number = true }, @@ -622,25 +641,27 @@ local function validate_options(conf) end for k, v in pairs(user) do - local invalid - local override_typecheck = FIELD_OVERRIDE_TYPECHECK[k] or {} - if def[k] == nil then - -- option does not exist - invalid = string.format("unknown option: %s%s", prefix, k) - elseif type(v) ~= type(def[k]) and not override_typecheck[type(v)] then - -- option is of the wrong type and is not a function - invalid = string.format("invalid option: %s%s expected: %s actual: %s", prefix, k, type(def[k]), type(v)) - end - - if invalid then - if msg then - msg = string.format("%s | %s", msg, invalid) - else - msg = string.format("%s", invalid) + if not FIELD_SKIP_VALIDATE[k] then + local invalid + local override_typecheck = FIELD_OVERRIDE_TYPECHECK[k] or {} + if def[k] == nil then + -- option does not exist + invalid = string.format("unknown option: %s%s", prefix, k) + elseif type(v) ~= type(def[k]) and not override_typecheck[type(v)] then + -- option is of the wrong type and is not a function + invalid = string.format("invalid option: %s%s expected: %s actual: %s", prefix, k, type(def[k]), type(v)) + end + + if invalid then + if msg then + msg = string.format("%s | %s", msg, invalid) + else + msg = string.format("%s", invalid) + end + user[k] = nil + else + validate(v, def[k], prefix .. k .. ".") end - user[k] = nil - else - validate(v, def[k], prefix .. k .. ".") end end end diff --git a/lua/nvim-tree/actions/node/open-file.lua b/lua/nvim-tree/actions/node/open-file.lua index 8c736b7a..98d1faf8 100644 --- a/lua/nvim-tree/actions/node/open-file.lua +++ b/lua/nvim-tree/actions/node/open-file.lua @@ -280,7 +280,7 @@ function M.fn(mode, filename) end function M.setup(opts) - M.quit_on_open = opts.actions.open_file.quit_on_open + M.quit_on_open = opts.actions.open_file.quit_on_open or opts.view.float.enable M.resize_window = opts.actions.open_file.resize_window if opts.actions.open_file.window_picker.chars then opts.actions.open_file.window_picker.chars = tostring(opts.actions.open_file.window_picker.chars):upper() diff --git a/lua/nvim-tree/view.lua b/lua/nvim-tree/view.lua index 4e5f1c85..dbe880ff 100644 --- a/lua/nvim-tree/view.lua +++ b/lua/nvim-tree/view.lua @@ -134,8 +134,12 @@ local function set_window_options_and_buffer() end local function open_window() - a.nvim_command "vsp" - M.reposition_window() + if M.View.float.enable then + a.nvim_open_win(0, true, M.View.float.open_win_config) + else + a.nvim_command "vsp" + M.reposition_window() + end setup_tabpage(a.nvim_get_current_tabpage()) set_window_options_and_buffer() end @@ -431,6 +435,7 @@ function M.setup(opts) M.View.winopts.number = options.number M.View.winopts.relativenumber = options.relativenumber M.View.winopts.signcolumn = options.signcolumn + M.View.float = options.float M.on_attach = opts.on_attach end From ff6e7966f39a897ac4d1358f4d022cfecdc88ff1 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 7 Aug 2022 12:16:03 +1000 Subject: [PATCH 03/26] fix(#1484): better error handling in git utils get_toplevel --- lua/nvim-tree/git/utils.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lua/nvim-tree/git/utils.lua b/lua/nvim-tree/git/utils.lua index e6451393..1aa48bab 100644 --- a/lua/nvim-tree/git/utils.lua +++ b/lua/nvim-tree/git/utils.lua @@ -14,7 +14,7 @@ function M.get_toplevel(cwd) log.raw("git", toplevel) log.profile_end(ps, "git toplevel %s", cwd) - if not toplevel or #toplevel == 0 or toplevel:match "fatal" then + if vim.v.shell_error ~= 0 or not toplevel or #toplevel == 0 or toplevel:match "fatal" then return nil end @@ -23,6 +23,9 @@ function M.get_toplevel(cwd) -- msys2 git support if has_cygpath then toplevel = vim.fn.system("cygpath -w " .. vim.fn.shellescape(toplevel)) + if vim.v.shell_error ~= 0 then + return nil + end end toplevel = toplevel:gsub("/", "\\") end From a73d0d4800d517f737d5d6d69283426b48bdf7f3 Mon Sep 17 00:00:00 2001 From: Hoang Nguyen Date: Mon, 8 Aug 2022 00:52:14 +0000 Subject: [PATCH 04/26] feat(file-popup): add actions.file_popup.open_win_config * file-popup: add nvim_open_win configuration * docs: update file-popup configuration --- doc/nvim-tree-lua.txt | 25 +++++++++++++++++++++++ lua/nvim-tree.lua | 9 ++++++++ lua/nvim-tree/actions/init.lua | 1 + lua/nvim-tree/actions/node/file-popup.lua | 12 +++++------ 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 2b59d5cc..4007a21d 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -313,6 +313,15 @@ Subsequent calls to setup will replace the previous configuration. max_folder_discovery = 300, exclude = {}, }, + file_popup = { + open_win_config = { + col = 1, + row = 1, + relative = "cursor", + border = "shadow", + style = "minimal", + }, + }, open_file = { quit_on_open = false, resize_window = true, @@ -869,6 +878,22 @@ Configuration for various actions. E.g `{ ".git", "target", "build" }` etc. Type: `table`, Default: `{}` + *nvim-tree.actions.file_popup* + Configuration for file_popup behaviour. + + *nvim-tree.actions.file_popup.open_win_config* + Floating window config for file_popup. See |nvim_open_win| for more details. + You shouldn't define `"width"` and `"height"` values here. They will be + overridden to fit the file_popup content. + Type: `table`, Default: + `{` + `col = 1,` + `row = 1,` + `relative = "cursor",` + `border = "shadow",` + `style = "minimal",` + `}` + *nvim-tree.actions.open_file* Configuration options for opening a file from nvim-tree. diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 8e8c6d04..de903a86 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -576,6 +576,15 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS max_folder_discovery = 300, exclude = {}, }, + file_popup = { + open_win_config = { + col = 1, + row = 1, + relative = "cursor", + border = "shadow", + style = "minimal", + }, + }, open_file = { quit_on_open = false, resize_window = true, diff --git a/lua/nvim-tree/actions/init.lua b/lua/nvim-tree/actions/init.lua index 65e28fef..d755a559 100644 --- a/lua/nvim-tree/actions/init.lua +++ b/lua/nvim-tree/actions/init.lua @@ -389,6 +389,7 @@ local DEFAULT_MAPPING_CONFIG = { function M.setup(opts) require("nvim-tree.actions.fs.trash").setup(opts) require("nvim-tree.actions.node.system-open").setup(opts) + require("nvim-tree.actions.node.file-popup").setup(opts) require("nvim-tree.actions.node.open-file").setup(opts) require("nvim-tree.actions.root.change-dir").setup(opts) require("nvim-tree.actions.fs.create-file").setup(opts) diff --git a/lua/nvim-tree/actions/node/file-popup.lua b/lua/nvim-tree/actions/node/file-popup.lua index ef907575..dded6808 100644 --- a/lua/nvim-tree/actions/node/file-popup.lua +++ b/lua/nvim-tree/actions/node/file-popup.lua @@ -28,16 +28,12 @@ local function setup_window(node) local max_width = vim.fn.max(vim.tbl_map(function(n) return #n end, lines)) - local winnr = a.nvim_open_win(0, false, { - col = 1, - row = 1, - relative = "cursor", + local open_win_config = vim.tbl_extend("force", M.open_win_config, { width = max_width + 1, height = #lines, - border = "shadow", noautocmd = true, - style = "minimal", }) + local winnr = a.nvim_open_win(0, false, open_win_config) current_popup = { winnr = winnr, file_path = node.absolute_path, @@ -78,4 +74,8 @@ function M.toggle_file_info(node) }) end +function M.setup(opts) + M.open_win_config = opts.actions.file_popup.open_win_config +end + return M From 261a5c380c000e23c4a23dcd55b984c856cdb113 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 8 Aug 2022 12:46:09 +1000 Subject: [PATCH 05/26] fix(#1480): break symlink cycle on find-file, search-node (#1482) * fix(#1480): break symlink cycle on find-file * fix(#1480): break symlink cycle on search-node * fix(#1480): break symlink cycle on search-node * fix(#1480): break symlink cycle on find-file --- lua/nvim-tree/actions/finders/find-file.lua | 8 +++ lua/nvim-tree/actions/finders/search-node.lua | 62 +++++++++++-------- 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/lua/nvim-tree/actions/finders/find-file.lua b/lua/nvim-tree/actions/finders/find-file.lua index 6ff67ad1..df55c155 100644 --- a/lua/nvim-tree/actions/finders/find-file.lua +++ b/lua/nvim-tree/actions/finders/find-file.lua @@ -27,12 +27,20 @@ function M.fn(fname) local line = core.get_nodes_starting_line() + local absolute_paths_searched = {} + local found = Iterator.builder(core.get_explorer().nodes) :matcher(function(node) return node.absolute_path == fname_real or node.link_to == fname_real end) :applier(function(node) line = line + 1 + + if vim.tbl_contains(absolute_paths_searched, node.absolute_path) then + return + end + table.insert(absolute_paths_searched, node.absolute_path) + local abs_match = vim.startswith(fname_real, node.absolute_path .. utils.path_separator) local link_match = node.link_to and vim.startswith(fname_real, node.link_to .. utils.path_separator) diff --git a/lua/nvim-tree/actions/finders/search-node.lua b/lua/nvim-tree/actions/finders/search-node.lua index 94f84268..d0b0162c 100644 --- a/lua/nvim-tree/actions/finders/search-node.lua +++ b/lua/nvim-tree/actions/finders/search-node.lua @@ -7,42 +7,54 @@ local find_file = require("nvim-tree.actions.finders.find-file").fn local M = {} -local function search(dir, input_path) - local path, name, stat, handle, _ +local function search(search_dir, input_path) + local realpaths_searched = {} - if not dir then + if not search_dir then return end - handle, _ = uv.fs_scandir(dir) - if not handle then - return - end + local function iter(dir) + local realpath, path, name, stat, handle, _ - name, _ = uv.fs_scandir_next(handle) - while name do - path = dir .. "/" .. name - - stat, _ = uv.fs_stat(path) - if not stat then - break + handle, _ = uv.fs_scandir(dir) + if not handle then + return end - if not filters.should_ignore(path) then - if string.find(path, "/" .. input_path .. "$") then - return path - end - - if stat.type == "directory" then - path = search(path, input_path) - if path then - return path - end - end + realpath, _ = uv.fs_realpath(dir) + if not realpath or vim.tbl_contains(realpaths_searched, realpath) then + return end + table.insert(realpaths_searched, realpath) name, _ = uv.fs_scandir_next(handle) + while name do + path = dir .. "/" .. name + + stat, _ = uv.fs_stat(path) + if not stat then + break + end + + if not filters.should_ignore(path) then + if string.find(path, "/" .. input_path .. "$") then + return path + end + + if stat.type == "directory" then + path = iter(path) + if path then + return path + end + end + end + + name, _ = uv.fs_scandir_next(handle) + end end + + return iter(search_dir) end function M.fn() From b314b3a6992f07f7af5c58521d1e219b032d309e Mon Sep 17 00:00:00 2001 From: Carlos Castillo <47466248+carlosecp@users.noreply.github.com> Date: Sun, 14 Aug 2022 02:00:04 -0300 Subject: [PATCH 06/26] fix(#1500): focusing directories with a trailing slash in their path doesn't work (#1501) --- lua/nvim-tree/actions/fs/create-file.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/nvim-tree/actions/fs/create-file.lua b/lua/nvim-tree/actions/fs/create-file.lua index 06dcb9c6..d5544e8b 100644 --- a/lua/nvim-tree/actions/fs/create-file.lua +++ b/lua/nvim-tree/actions/fs/create-file.lua @@ -108,7 +108,7 @@ function M.fn(node) end -- INFO: defer needed when reload is automatic (watchers) vim.defer_fn(function() - utils.focus_file(new_file_path) + utils.focus_file(utils.path_remove_trailing(new_file_path)) end, 150) end) end From 09a51266bca28dd87febd63c66bdbd74f7764a63 Mon Sep 17 00:00:00 2001 From: axlauri Date: Mon, 15 Aug 2022 00:30:22 -0400 Subject: [PATCH 07/26] fix(#1494): git showUntracked value and log (#1504) * should_show_untracked correctly evaluates status.showUntrackedFiles * git.Runner:_run_git_job removes nils before logging args --- lua/nvim-tree/git/runner.lua | 2 +- lua/nvim-tree/git/utils.lua | 4 ++-- lua/nvim-tree/utils.lua | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lua/nvim-tree/git/runner.lua b/lua/nvim-tree/git/runner.lua index a62043c5..c987af37 100644 --- a/lua/nvim-tree/git/runner.lua +++ b/lua/nvim-tree/git/runner.lua @@ -84,7 +84,7 @@ function Runner:_run_git_job() local opts = self:_getopts(stdout, stderr) log.line("git", "running job with timeout %dms", self.timeout) - log.line("git", "git %s", table.concat(opts.args, " ")) + log.line("git", "git %s", table.concat(utils.array_remove_nils(opts.args), " ")) handle, pid = uv.spawn( "git", diff --git a/lua/nvim-tree/git/utils.lua b/lua/nvim-tree/git/utils.lua index 1aa48bab..d76cbe83 100644 --- a/lua/nvim-tree/git/utils.lua +++ b/lua/nvim-tree/git/utils.lua @@ -41,7 +41,7 @@ function M.should_show_untracked(cwd) return untracked[cwd] end - local cmd = "git -C " .. cwd .. " config --type=bool status.showUntrackedFiles" + local cmd = "git -C " .. cwd .. " config status.showUntrackedFiles" local ps = log.profile_start("git untracked %s", cwd) log.line("git", cmd) @@ -51,7 +51,7 @@ function M.should_show_untracked(cwd) log.raw("git", has_untracked) log.profile_end(ps, "git untracked %s", cwd) - untracked[cwd] = vim.trim(has_untracked) ~= "false" + untracked[cwd] = vim.trim(has_untracked) ~= "no" return untracked[cwd] end diff --git a/lua/nvim-tree/utils.lua b/lua/nvim-tree/utils.lua index ae56815b..02a1a2f5 100644 --- a/lua/nvim-tree/utils.lua +++ b/lua/nvim-tree/utils.lua @@ -408,6 +408,12 @@ function M.array_remove(array, item) end end +function M.array_remove_nils(array) + return vim.tbl_filter(function(v) + return v ~= nil + end, array) +end + function M.inject_node(f) return function() f(require("nvim-tree.lib").get_node_at_cursor()) From d9edddb84931ca73c350922d76f6c6825b694248 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 20 Aug 2022 14:32:28 +1000 Subject: [PATCH 08/26] fix(#1503): focus last win before close (#1509) --- lua/nvim-tree/view.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/nvim-tree/view.lua b/lua/nvim-tree/view.lua index dbe880ff..fb153de7 100644 --- a/lua/nvim-tree/view.lua +++ b/lua/nvim-tree/view.lua @@ -188,11 +188,11 @@ function M.close() local current_win = a.nvim_get_current_win() for _, win in pairs(a.nvim_list_wins()) do if tree_win ~= win and a.nvim_win_get_config(win).relative == "" then - a.nvim_win_close(tree_win, true) local prev_win = vim.fn.winnr "#" -- this tab only if tree_win == current_win and prev_win > 0 then a.nvim_set_current_win(vim.fn.win_getid(prev_win)) end + a.nvim_win_close(tree_win, true) events._dispatch_on_tree_close() return end From 9fd7b7ae2920cc349644b5d45785e2a655ffdfe9 Mon Sep 17 00:00:00 2001 From: Jonathan Gollnick <32113038+cptchuckles@users.noreply.github.com> Date: Fri, 19 Aug 2022 23:37:51 -0500 Subject: [PATCH 09/26] fix(#1514): inverted git navigation keymaps (#1515) --- lua/nvim-tree/keymap.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/nvim-tree/keymap.lua b/lua/nvim-tree/keymap.lua index 74b96d1d..17e180bb 100644 --- a/lua/nvim-tree/keymap.lua +++ b/lua/nvim-tree/keymap.lua @@ -154,7 +154,7 @@ local DEFAULT_KEYMAPS = { desc = "go to next diagnostic item", }, { - key = "[c", + key = "]c", callback = Api.node.navigate.git.next, desc = "go to next git item", }, @@ -164,7 +164,7 @@ local DEFAULT_KEYMAPS = { desc = "go to prev diagnostic item", }, { - key = "]c", + key = "[c", callback = Api.node.navigate.git.prev, desc = "go to prev git item", }, From 81eb718394e489d2aebbffa730d2517d72ec7f9c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 20 Aug 2022 14:40:09 +1000 Subject: [PATCH 10/26] fix: inverted diagnostic navigation keymaps --- lua/nvim-tree/keymap.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/nvim-tree/keymap.lua b/lua/nvim-tree/keymap.lua index 17e180bb..2c26a3a4 100644 --- a/lua/nvim-tree/keymap.lua +++ b/lua/nvim-tree/keymap.lua @@ -149,7 +149,7 @@ local DEFAULT_KEYMAPS = { desc = "copy absolute path to system clipboard", }, { - key = "[e", + key = "]e", callback = Api.node.navigate.diagnostics.next, desc = "go to next diagnostic item", }, @@ -159,7 +159,7 @@ local DEFAULT_KEYMAPS = { desc = "go to next git item", }, { - key = "]e", + key = "[e", callback = Api.node.navigate.diagnostics.prev, desc = "go to prev diagnostic item", }, From c5fba1ec1861525a8d2d9773f7983ecf77b588dc Mon Sep 17 00:00:00 2001 From: Sebastian Volland Date: Mon, 22 Aug 2022 03:41:11 +0200 Subject: [PATCH 11/26] fix(#1520): file type changes are not detected. (#1521) --- lua/nvim-tree/explorer/node-builders.lua | 3 +++ lua/nvim-tree/explorer/reload.lua | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/lua/nvim-tree/explorer/node-builders.lua b/lua/nvim-tree/explorer/node-builders.lua index 48b774c8..d37fdad0 100644 --- a/lua/nvim-tree/explorer/node-builders.lua +++ b/lua/nvim-tree/explorer/node-builders.lua @@ -11,6 +11,7 @@ function M.folder(parent, absolute_path, name) local has_children = handle and uv.fs_scandir_next(handle) ~= nil return { + type = "directory", absolute_path = absolute_path, fs_stat = uv.fs_stat(absolute_path), group_next = nil, -- If node is grouped, this points to the next child dir/link node @@ -34,6 +35,7 @@ function M.file(parent, absolute_path, name) local ext = string.match(name, ".?[^.]+%.(.*)") or "" return { + type = "file", absolute_path = absolute_path, executable = M.is_executable(absolute_path, ext), extension = ext, @@ -61,6 +63,7 @@ function M.link(parent, absolute_path, name) end return { + type = "link", absolute_path = absolute_path, fs_stat = uv.fs_stat(absolute_path), group_next = nil, -- If node is grouped, this points to the next child dir/link node diff --git a/lua/nvim-tree/explorer/reload.lua b/lua/nvim-tree/explorer/reload.lua index 4d4a06bf..b3fc30e9 100644 --- a/lua/nvim-tree/explorer/reload.lua +++ b/lua/nvim-tree/explorer/reload.lua @@ -45,6 +45,18 @@ function M.reload(node, status) t = t or (uv.fs_stat(abs) or {}).type if not filters.should_ignore(abs) and not filters.should_ignore_git(abs, status.files) then child_names[abs] = true + + -- Recreate node if type changes. + if nodes_by_path[abs] then + local n = nodes_by_path[abs] + + if n.type ~= t then + utils.array_remove(node.nodes, n) + common.node_destroy(n) + nodes_by_path[abs] = nil + end + end + if not nodes_by_path[abs] then if t == "directory" and uv.fs_access(abs, "R") then local folder = builders.folder(node, abs, name) From 049cdd3073faab064d93f7d6397c9d292d8a3cab Mon Sep 17 00:00:00 2001 From: Sebastian Volland Date: Mon, 22 Aug 2022 06:19:06 +0200 Subject: [PATCH 12/26] fix(#1518): sort_by=modification_time not reordering on refresh. (#1519) --- lua/nvim-tree/explorer/reload.lua | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/lua/nvim-tree/explorer/reload.lua b/lua/nvim-tree/explorer/reload.lua index b3fc30e9..43590952 100644 --- a/lua/nvim-tree/explorer/reload.lua +++ b/lua/nvim-tree/explorer/reload.lua @@ -41,8 +41,18 @@ function M.reload(node, status) break end + local stat + local function fs_stat_cached(path) + if stat ~= nil then + return stat + end + + stat = uv.fs_stat(path) + return stat + end + local abs = utils.path_join { cwd, name } - t = t or (uv.fs_stat(abs) or {}).type + t = t or (fs_stat_cached(abs) or {}).type if not filters.should_ignore(abs) and not filters.should_ignore_git(abs, status.files) then child_names[abs] = true @@ -73,10 +83,12 @@ function M.reload(node, status) table.insert(node.nodes, link) end end - end - local n = nodes_by_path[abs] - if n then - n.executable = builders.is_executable(abs, n.extension or "") + else + local n = nodes_by_path[abs] + if n then + n.executable = builders.is_executable(abs, n.extension or "") + n.fs_stat = fs_stat_cached(abs) + end end end end From 90dcf42bba4b9c07e1d590592035fdec5d8e07d8 Mon Sep 17 00:00:00 2001 From: Sebastian Volland Date: Mon, 22 Aug 2022 06:24:25 +0200 Subject: [PATCH 13/26] fix(#1533): make `toggle_mark` ignore non-togglable nodes. (#1534) --- lua/nvim-tree/marks/init.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lua/nvim-tree/marks/init.lua b/lua/nvim-tree/marks/init.lua index e65abcf7..5e11c888 100644 --- a/lua/nvim-tree/marks/init.lua +++ b/lua/nvim-tree/marks/init.lua @@ -17,6 +17,10 @@ local function remove_mark(node) end function M.toggle_mark(node) + if node.absolute_path == nil then + return + end + if M.get_mark(node) then remove_mark(node) else From 2bb15fd98f6322e0221b8200b88199b2a01e2c3e Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 22 Aug 2022 16:22:32 +1000 Subject: [PATCH 14/26] doc: add PR tips to contributing --- CONTRIBUTING.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index edf9d0de..f87cccdc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,3 +25,11 @@ When adding new options, you should declare the defaults in the main `nvim-tree. Once you did, you should run the `scripts/update-help.sh`. Documentation for options should also be added, see how this is done after `nvim-tree.disable_netrw` in the `nvim-tree-lua.txt` file. + +## Pull Request + +Please reference any issues in the description e.g. "resolves #1234". + +Please consider adding nvim-tree developers as collaborators on your fork, to quickly allow small changes such as documentation tweaks: +@kyazdani42 and @alex-courtis + From e3353c4cb40baef335e1a21d8b9c21b9cde919be Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 22 Aug 2022 16:58:41 +1000 Subject: [PATCH 15/26] fix(#1529): ensure tree window exists before closing (#1537) --- lua/nvim-tree/view.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/nvim-tree/view.lua b/lua/nvim-tree/view.lua index fb153de7..87aca62c 100644 --- a/lua/nvim-tree/view.lua +++ b/lua/nvim-tree/view.lua @@ -192,7 +192,9 @@ function M.close() if tree_win == current_win and prev_win > 0 then a.nvim_set_current_win(vim.fn.win_getid(prev_win)) end - a.nvim_win_close(tree_win, true) + if a.nvim_win_is_valid(tree_win) then + a.nvim_win_close(tree_win, true) + end events._dispatch_on_tree_close() return end From 259efeee62c7fb51abf299c2570cacbf4806e98a Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 23 Aug 2022 10:29:45 +1000 Subject: [PATCH 16/26] fix(#1540): watcher ignore directories with name exactly '.git' --- lua/nvim-tree/explorer/watch.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/nvim-tree/explorer/watch.lua b/lua/nvim-tree/explorer/watch.lua index 2ce9152d..785a6e0c 100644 --- a/lua/nvim-tree/explorer/watch.lua +++ b/lua/nvim-tree/explorer/watch.lua @@ -19,7 +19,7 @@ local function update_parent_statuses(node, project, root) end local function is_git(path) - return path:match "%.git$" ~= nil or path:match(utils.path_add_trailing ".git") ~= nil + return vim.fn.fnamemodify(path, ":t") == ".git" end local IGNORED_PATHS = { From c3ea264947671f44d836af5b7587e12c4b4611f9 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 23 Aug 2022 17:14:23 +1000 Subject: [PATCH 17/26] feat(view): allow function for view.float.open_win_config (#1538) --- doc/nvim-tree-lua.txt | 2 +- lua/nvim-tree/view.lua | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 4007a21d..59f923a2 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -669,7 +669,7 @@ Window / buffer setup. *nvim-tree.view.float.open_win_config* Floating window config. See |nvim_open_win| for more details. - Type: `table`, Default: + Type: `table` or `function` that returns a table, Default: `{` `relative = "editor",` `border = "rounded",` diff --git a/lua/nvim-tree/view.lua b/lua/nvim-tree/view.lua index 87aca62c..ea749d85 100644 --- a/lua/nvim-tree/view.lua +++ b/lua/nvim-tree/view.lua @@ -133,9 +133,17 @@ local function set_window_options_and_buffer() end end +local function open_win_config() + if type(M.View.float.open_win_config) == "function" then + return M.View.float.open_win_config() + else + return M.View.float.open_win_config + end +end + local function open_window() if M.View.float.enable then - a.nvim_open_win(0, true, M.View.float.open_win_config) + a.nvim_open_win(0, true, open_win_config()) else a.nvim_command "vsp" M.reposition_window() From c272c88dafa5d2e8bf0554f4d687396f843714c5 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 27 Aug 2022 11:58:16 +1000 Subject: [PATCH 18/26] fix(#1551): handle git status TT as staged --- lua/nvim-tree/renderer/components/git.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/nvim-tree/renderer/components/git.lua b/lua/nvim-tree/renderer/components/git.lua index ea07af49..f0b3c354 100644 --- a/lua/nvim-tree/renderer/components/git.lua +++ b/lua/nvim-tree/renderer/components/git.lua @@ -99,6 +99,7 @@ local git_hl = { ["AD"] = "NvimTreeFileStaged", ["MD"] = "NvimTreeFileStaged", ["T "] = "NvimTreeFileStaged", + ["TT"] = "NvimTreeFileStaged", [" M"] = "NvimTreeFileDirty", ["CM"] = "NvimTreeFileDirty", [" C"] = "NvimTreeFileDirty", From ce5d0a6b7ddfec622554943d2ebcc739b1d74567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Cie=C5=9Bla?= Date: Sat, 27 Aug 2022 05:36:26 +0200 Subject: [PATCH 19/26] fix(#1543): Do not resize nvim-tree window if float is enabled (#1556) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Krzysztof Cieśla --- lua/nvim-tree/view.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lua/nvim-tree/view.lua b/lua/nvim-tree/view.lua index ea749d85..423f4fc6 100644 --- a/lua/nvim-tree/view.lua +++ b/lua/nvim-tree/view.lua @@ -246,6 +246,11 @@ function M.grow_from_content() end function M.resize(size) + if M.View.float.enable then + -- float size should be defined in view.float.open_win_config + return + end + if type(size) == "string" then size = vim.trim(size) local first_char = size:sub(1, 1) From 4a725c0ca501d81002aad77418f1edafdd01a0ba Mon Sep 17 00:00:00 2001 From: Piotr Doan Date: Mon, 29 Aug 2022 02:53:23 +0200 Subject: [PATCH 20/26] fix(#1555): incorrect exe highlight in Windows filesystem from WSL (#1557) --- lua/nvim-tree/explorer/node-builders.lua | 15 ++++++-- lua/nvim-tree/explorer/reload.lua | 2 +- lua/nvim-tree/utils.lua | 46 ++++++++++++++++++++++-- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/lua/nvim-tree/explorer/node-builders.lua b/lua/nvim-tree/explorer/node-builders.lua index d37fdad0..606f10c6 100644 --- a/lua/nvim-tree/explorer/node-builders.lua +++ b/lua/nvim-tree/explorer/node-builders.lua @@ -4,6 +4,7 @@ local watch = require "nvim-tree.explorer.watch" local M = { is_windows = vim.fn.has "win32" == 1, + is_wsl = vim.fn.has "wsl" == 1, } function M.folder(parent, absolute_path, name) @@ -24,9 +25,19 @@ function M.folder(parent, absolute_path, name) } end -function M.is_executable(absolute_path, ext) +function M.is_executable(parent, absolute_path, ext) if M.is_windows then return utils.is_windows_exe(ext) + elseif M.is_wsl then + if parent.is_wsl_windows_fs_path == nil then + -- Evaluate lazily when needed and do so only once for each parent + -- as 'wslpath' calls can get expensive in highly populated directories. + parent.is_wsl_windows_fs_path = utils.is_wsl_windows_fs_path(absolute_path) + end + + if parent.is_wsl_windows_fs_path then + return utils.is_wsl_windows_fs_exe(ext) + end end return uv.fs_access(absolute_path, "X") end @@ -37,7 +48,7 @@ function M.file(parent, absolute_path, name) return { type = "file", absolute_path = absolute_path, - executable = M.is_executable(absolute_path, ext), + executable = M.is_executable(parent, absolute_path, ext), extension = ext, fs_stat = uv.fs_stat(absolute_path), name = name, diff --git a/lua/nvim-tree/explorer/reload.lua b/lua/nvim-tree/explorer/reload.lua index 43590952..47c82d39 100644 --- a/lua/nvim-tree/explorer/reload.lua +++ b/lua/nvim-tree/explorer/reload.lua @@ -86,7 +86,7 @@ function M.reload(node, status) else local n = nodes_by_path[abs] if n then - n.executable = builders.is_executable(abs, n.extension or "") + n.executable = builders.is_executable(n.parent, abs, n.extension or "") n.fs_stat = fs_stat_cached(abs) end end diff --git a/lua/nvim-tree/utils.lua b/lua/nvim-tree/utils.lua index 02a1a2f5..37ff8ebe 100644 --- a/lua/nvim-tree/utils.lua +++ b/lua/nvim-tree/utils.lua @@ -10,6 +10,7 @@ local M = { } M.is_windows = vim.fn.has "win32" == 1 or vim.fn.has "win32unix" == 1 +M.is_wsl = vim.fn.has "wsl" == 1 function M.path_to_matching_str(path) return path:gsub("(%-)", "(%%-)"):gsub("(%.)", "(%%.)"):gsub("(%_)", "(%%_)") @@ -171,8 +172,11 @@ end ---@return boolean function M.is_windows_exe(ext) if not M.pathexts then - local PATHEXT = vim.env.PATHEXT or "" - local wexe = vim.split(PATHEXT:gsub("%.", ""), ";") + if not vim.env.PATHEXT then + return false + end + + local wexe = vim.split(vim.env.PATHEXT:gsub("%.", ""), ";") M.pathexts = {} for _, v in pairs(wexe) do M.pathexts[v] = true @@ -182,6 +186,44 @@ function M.is_windows_exe(ext) return M.pathexts[ext:upper()] end +--- Check whether path maps to Windows filesystem mounted by WSL +-- @param path string +-- @return boolean +function M.is_wsl_windows_fs_path(path) + -- Run 'wslpath' command to try translating WSL path to Windows path. + -- Consume stderr output as well because 'wslpath' can produce permission + -- errors on some files (e.g. temporary files in root of system drive). + local handle = io.popen('wslpath -w "' .. path .. '" 2>/dev/null') + if handle then + local output = handle:read "*a" + handle:close() + + return string.find(output, "^\\\\wsl$\\") == nil + end + + return false +end + +--- Check whether extension is Windows executable under WSL +-- @param ext string +-- @return boolean +function M.is_wsl_windows_fs_exe(ext) + if not vim.env.PATHEXT then + -- Extract executable extensions from within WSL. + -- Redirect stderr to null to silence warnings when + -- Windows command is executed from Linux filesystem: + -- > CMD.EXE was started with the above path as the current directory. + -- > UNC paths are not supported. Defaulting to Windows directory. + local handle = io.popen 'cmd.exe /c "echo %PATHEXT%" 2>/dev/null' + if handle then + vim.env.PATHEXT = handle:read "*a" + handle:close() + end + end + + return M.is_windows_exe(ext) +end + function M.rename_loaded_buffers(old_path, new_path) for _, buf in pairs(a.nvim_list_bufs()) do if a.nvim_buf_is_loaded(buf) then From 07f59e7450c767c674cc53f5930b2d73af60b9c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Cie=C5=9Bla?= Date: Tue, 30 Aug 2022 00:47:13 +0200 Subject: [PATCH 21/26] fix(#1539): Fix closing nvim-tree float when file is removed (#1546) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix closing nvim-tree float when file is removed * Revert changes for non-float Co-authored-by: Krzysztof Cieśla --- lua/nvim-tree/actions/fs/remove-file.lua | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lua/nvim-tree/actions/fs/remove-file.lua b/lua/nvim-tree/actions/fs/remove-file.lua index b671bf41..21f1ace6 100644 --- a/lua/nvim-tree/actions/fs/remove-file.lua +++ b/lua/nvim-tree/actions/fs/remove-file.lua @@ -3,10 +3,15 @@ local luv = vim.loop local utils = require "nvim-tree.utils" local events = require "nvim-tree.events" +local view = require "nvim-tree.view" local M = {} local function close_windows(windows) + if view.View.float.enable and #a.nvim_list_wins() == 1 then + return + end + for _, window in ipairs(windows) do if a.nvim_win_is_valid(window) then a.nvim_win_close(window, true) @@ -18,11 +23,13 @@ local function clear_buffer(absolute_path) local bufs = vim.fn.getbufinfo { bufloaded = 1, buflisted = 1 } for _, buf in pairs(bufs) do if buf.name == absolute_path then - if buf.hidden == 0 and #bufs > 1 then + if buf.hidden == 0 and (#bufs > 1 or view.View.float.enable) then local winnr = a.nvim_get_current_win() a.nvim_set_current_win(buf.windows[1]) vim.cmd ":bn" - a.nvim_set_current_win(winnr) + if not view.View.float.enable then + a.nvim_set_current_win(winnr) + end end a.nvim_buf_delete(buf.bufnr, { force = true }) if M.close_window then From 757951ba6b3ee6b0f502c4bd4a23c53b382305c2 Mon Sep 17 00:00:00 2001 From: Bryan Baron <77312939+MrFixThis@users.noreply.github.com> Date: Mon, 29 Aug 2022 17:50:18 -0500 Subject: [PATCH 22/26] feat(view): floating window's optional adaptive size specification (#1559) --- lua/nvim-tree/view.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/nvim-tree/view.lua b/lua/nvim-tree/view.lua index 423f4fc6..17ec841c 100644 --- a/lua/nvim-tree/view.lua +++ b/lua/nvim-tree/view.lua @@ -246,7 +246,8 @@ function M.grow_from_content() end function M.resize(size) - if M.View.float.enable then + if M.View.float.enable and not M.View.adaptive_size then + -- if the floating windows's adaptive size is not desired, then the -- float size should be defined in view.float.open_win_config return end From e8bf3d778a74882d748f55d67af206fa8b321d99 Mon Sep 17 00:00:00 2001 From: Mivort Date: Tue, 30 Aug 2022 02:44:30 +0300 Subject: [PATCH 23/26] feat(renderer): add renderer.indent_width (#1505) * feat: add config option for a tree indent width add 'indent_width' option to configure visible indent for tree nesting levels (default is 2). * add 'bottom' char for a corner extension * apply stylua formatting * provide value constraints in documentation * limit minimal indent width * make marker symbols have one utf8 char width * match stylua formatting * add the commentary regarding utf-8 first symbol match --- doc/nvim-tree-lua.txt | 10 +++- lua/nvim-tree.lua | 2 + lua/nvim-tree/renderer/builder.lua | 4 +- lua/nvim-tree/renderer/components/padding.lua | 52 +++++++++++++------ 4 files changed, 48 insertions(+), 20 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 59f923a2..0c1b714f 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -213,6 +213,7 @@ Subsequent calls to setup will replace the previous configuration. full_name = false, highlight_opened_files = "none", root_folder_modifier = ":~", + indent_width = 2, indent_markers = { enable = false, inline_arrows = true, @@ -220,6 +221,7 @@ Subsequent calls to setup will replace the previous configuration. corner = "└", edge = "│", item = "│", + bottom = "─", none = " ", }, }, @@ -709,6 +711,10 @@ UI rendering setup available options. Type: `string`, Default: `":~"` + *nvim-tree.renderer.indent_width* + Number of spaces for an each tree nesting level. Minimum 1. + Type: `number`, Default: `2` + *nvim-tree.renderer.indent_markers* Configuration options for tree indent markers. @@ -722,8 +728,8 @@ UI rendering setup Type: `boolean`, Default: `true` *nvim-tree.renderer.indent_markers.icons* - Icons shown before the file/directory. - Type: `table`, Default: `{ corner = "└", edge = "│", item = "│", none = " ", }` + Icons shown before the file/directory. Length 1. + Type: `table`, Default: `{ corner = "└", edge = "│", item = "│", bottom = "─", none = " ", }` *nvim-tree.renderer.icons* Configuration options for icons. diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index de903a86..a1a81b5a 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -476,6 +476,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS full_name = false, highlight_opened_files = "none", root_folder_modifier = ":~", + indent_width = 2, indent_markers = { enable = false, inline_arrows = true, @@ -483,6 +484,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS corner = "└", edge = "│", item = "│", + bottom = "─", none = " ", }, }, diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 3c3d6f07..f63be552 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -258,9 +258,9 @@ function Builder:_build_line(node, idx, num_children) self.index = self.index + 1 if node.open then - self.depth = self.depth + 2 + self.depth = self.depth + 1 self:build(node) - self.depth = self.depth - 2 + self.depth = self.depth - 1 end end diff --git a/lua/nvim-tree/renderer/components/padding.lua b/lua/nvim-tree/renderer/components/padding.lua index 5193fb26..e24bb843 100644 --- a/lua/nvim-tree/renderer/components/padding.lua +++ b/lua/nvim-tree/renderer/components/padding.lua @@ -25,30 +25,33 @@ local function get_padding_indent_markers(depth, idx, nodes_number, markers, wit if depth > 0 then local has_folder_sibling = check_siblings_for_folder(node, with_arrows) - local rdepth = depth / 2 - markers[rdepth] = idx ~= nodes_number - for i = 1, rdepth do + local indent = string.rep(" ", M.config.indent_width - 1) + markers[depth] = idx ~= nodes_number + for i = 1, depth do local glyph - if idx == nodes_number and i == rdepth then + if idx == nodes_number and i == depth then + local bottom_width = M.config.indent_width + - 2 + + (with_arrows and not inline_arrows and has_folder_sibling and 2 or 0) glyph = M.config.indent_markers.icons.corner - elseif markers[i] and i == rdepth then - glyph = M.config.indent_markers.icons.item + .. string.rep(M.config.indent_markers.icons.bottom, bottom_width) + .. (M.config.indent_width > 1 and " " or "") + elseif markers[i] and i == depth then + glyph = M.config.indent_markers.icons.item .. indent elseif markers[i] then - glyph = M.config.indent_markers.icons.edge + glyph = M.config.indent_markers.icons.edge .. indent else - glyph = M.config.indent_markers.icons.none + glyph = M.config.indent_markers.icons.none .. indent end - if not with_arrows or (inline_arrows and (rdepth ~= i or not node.nodes)) then - padding = padding .. glyph .. " " + if not with_arrows or (inline_arrows and (depth ~= i or not node.nodes)) then + padding = padding .. glyph elseif inline_arrows then padding = padding - elseif idx == nodes_number and i == rdepth and has_folder_sibling then - padding = padding .. base_padding .. glyph .. "── " - elseif rdepth == i and not node.nodes and has_folder_sibling then - padding = padding .. base_padding .. glyph .. " " .. base_padding + elseif idx ~= nodes_number and depth == i and not node.nodes and has_folder_sibling then + padding = padding .. base_padding .. glyph .. base_padding else - padding = padding .. base_padding .. glyph .. " " + padding = padding .. base_padding .. glyph end end end @@ -71,11 +74,12 @@ function M.get_padding(depth, idx, nodes_number, node, markers) local show_arrows = M.config.icons.show.folder_arrow local show_markers = M.config.indent_markers.enable local inline_arrows = M.config.indent_markers.inline_arrows + local indent_width = M.config.indent_width if show_markers then padding = padding .. get_padding_indent_markers(depth, idx, nodes_number, markers, show_arrows, inline_arrows, node) else - padding = padding .. string.rep(" ", depth) + padding = padding .. string.rep(" ", depth * indent_width) end if show_arrows then @@ -87,6 +91,22 @@ end function M.setup(opts) M.config = opts.renderer + + if M.config.indent_width < 1 then + M.config.indent_width = 1 + end + + local function check_marker(symbol) + if #symbol == 0 then + return " " + end + -- return the first character from the UTF-8 encoded string; we may use utf8.codes from Lua 5.3 when available + return symbol:match "[%z\1-\127\194-\244][\128-\191]*" + end + + for k, v in pairs(M.config.indent_markers.icons) do + M.config.indent_markers.icons[k] = check_marker(v) + end end return M From 011a7816b8ea1b3697687a26804535f24ece70ec Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 30 Aug 2022 16:42:55 +1000 Subject: [PATCH 24/26] doc: add PR tips to contributing --- CONTRIBUTING.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f87cccdc..7a07d13f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,6 +30,4 @@ Documentation for options should also be added, see how this is done after `nvim Please reference any issues in the description e.g. "resolves #1234". -Please consider adding nvim-tree developers as collaborators on your fork, to quickly allow small changes such as documentation tweaks: -@kyazdani42 and @alex-courtis - +Please check "allow edits by maintainers" to allow nvim-tree developers to make small changes such as documentation tweaks. From d753a1da9a58339f1751db96d37e9b318be91825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Cie=C5=9Bla?= Date: Sat, 3 Sep 2022 06:29:18 +0200 Subject: [PATCH 25/26] fix(view): file filter and info popup above floating view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Krzysztof Cieśla --- lua/nvim-tree/actions/node/file-popup.lua | 1 + lua/nvim-tree/live-filter.lua | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lua/nvim-tree/actions/node/file-popup.lua b/lua/nvim-tree/actions/node/file-popup.lua index dded6808..1724127e 100644 --- a/lua/nvim-tree/actions/node/file-popup.lua +++ b/lua/nvim-tree/actions/node/file-popup.lua @@ -32,6 +32,7 @@ local function setup_window(node) width = max_width + 1, height = #lines, noautocmd = true, + zindex = 60, }) local winnr = a.nvim_open_win(0, false, open_win_config) current_popup = { diff --git a/lua/nvim-tree/live-filter.lua b/lua/nvim-tree/live-filter.lua index 64dac5f1..0dd6eea1 100644 --- a/lua/nvim-tree/live-filter.lua +++ b/lua/nvim-tree/live-filter.lua @@ -25,6 +25,15 @@ local overlay_bufnr = nil local overlay_winnr = nil local function remove_overlay() + if view.View.float.enable then + -- return to normal nvim-tree float behaviour when filter window is closed + a.nvim_create_autocmd("WinLeave", { + pattern = "NvimTree_*", + group = a.nvim_create_augroup("NvimTree", { clear = false }), + callback = view.close, + }) + end + a.nvim_win_close(overlay_winnr, { force = true }) overlay_bufnr = nil overlay_winnr = nil @@ -92,12 +101,24 @@ local function configure_buffer_overlay() end local function create_overlay() + local min_width = 20 + if view.View.float.enable then + -- don't close nvim-tree float when focus is changed to filter window + a.nvim_clear_autocmds { + event = "WinLeave", + pattern = "NvimTree_*", + group = a.nvim_create_augroup("NvimTree", { clear = false }), + } + + min_width = min_width - 2 + end + configure_buffer_overlay() overlay_winnr = a.nvim_open_win(overlay_bufnr, true, { col = 1, row = 0, relative = "cursor", - width = math.max(20, a.nvim_win_get_width(view.get_winnr()) - #M.prefix - 2), + width = math.max(min_width, a.nvim_win_get_width(view.get_winnr()) - #M.prefix - 2), height = 1, border = "none", style = "minimal", From 951e10a64e0b03069f0f50ddc79d6a8ed8d23dec Mon Sep 17 00:00:00 2001 From: ADoyle Date: Sun, 4 Sep 2022 10:23:56 +0800 Subject: [PATCH 26/26] fix(#1568): show relative path of symlink destination (#1569) --- lua/nvim-tree/renderer/builder.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index f63be552..acb1d8ea 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -1,4 +1,5 @@ local utils = require "nvim-tree.utils" +local core = require "nvim-tree.core" local git = require "nvim-tree.renderer.components.git" local pad = require "nvim-tree.renderer.components.padding" @@ -114,7 +115,8 @@ function Builder:_build_folder(node, padding, git_hl, git_icons_tbl) local foldername = name .. self.trailing_slash if node.link_to and self.symlink_destination then local arrow = icons.i.symlink_arrow - foldername = foldername .. arrow .. node.link_to + local link_to = utils.path_relative(node.link_to, core.get_cwd()) + foldername = foldername .. arrow .. link_to end local git_icons = self:_unwrap_git_data(git_icons_tbl, offset + #icon + (self.is_git_after and #foldername + 1 or 0)) @@ -160,7 +162,8 @@ function Builder:_build_symlink(node, padding, git_highlight, git_icons_tbl) local arrow = icons.i.symlink_arrow local symlink_formatted = node.name if self.symlink_destination then - symlink_formatted = symlink_formatted .. arrow .. node.link_to + local link_to = utils.path_relative(node.link_to, core.get_cwd()) + symlink_formatted = symlink_formatted .. arrow .. link_to end local link_highlight = git_highlight or "NvimTreeSymlink"