Skip to content

Commit 3c4958a

Browse files
authored
fix(#1831): remove windows executable functionality due to occasional vim freeze and performance concerns (#1868)
* #1831 exploratory testing: disable file executable checks * fix(#1831): remove windows executable functionality
1 parent 9e4c395 commit 3c4958a

File tree

7 files changed

+44
-97
lines changed

7 files changed

+44
-97
lines changed

doc/nvim-tree-lua.txt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ CONTENTS *nvim-tree*
1515
7. Highlight Groups |nvim-tree-highlight|
1616
8. Events |nvim-tree-events|
1717
9. Bookmarks |nvim-tree-bookmarks|
18+
10. OS Specific Restrictions |nvim-tree-os-specific|
1819

1920
==============================================================================
2021
1. INTRODUCTION *nvim-tree-introduction*
@@ -1580,7 +1581,7 @@ e.g. handler for node renamed: >
15801581
{folder_name} `{string}` Absolute path to the removed folder.
15811582

15821583
==============================================================================
1583-
9. BOOKMARKS *nvim-tree-bookmarks*
1584+
9. BOOKMARKS *nvim-tree-bookmarks*
15841585

15851586
You can toggle marks on files/folders with
15861587
`require("nvim-tree.api").marks.toggle(node)` which is bound to `m` by
@@ -1601,4 +1602,15 @@ vim.keymap.set("n", "<leader>mn", require("nvim-tree.api").marks.navigate.next)
16011602
vim.keymap.set("n", "<leader>mp", require("nvim-tree.api").marks.navigate.prev)
16021603
vim.keymap.set("n", "<leader>ms", require("nvim-tree.api").marks.navigate.select)
16031604

1605+
==============================================================================
1606+
10. OS SPECIFIC RESTRICTIONS *nvim-tree-os-specific*
1607+
1608+
macOS
1609+
- Trash is unavailable
1610+
1611+
Windows WSL and PowerShell
1612+
- Trash is unavailable
1613+
- Executable file detection is disabled as this is non-performant and can
1614+
freeze nvim
1615+
16041616
vim:tw=78:ts=4:sw=4:et:ft=help:norl:

lua/nvim-tree/actions/fs/trash.lua

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
local lib = require "nvim-tree.lib"
22
local notify = require "nvim-tree.notify"
33

4-
local M = {
5-
config = {
6-
is_windows = vim.fn.has "win32" == 1 or vim.fn.has "win32unix" == 1,
7-
is_macos = vim.fn.has "mac" == 1 or vim.fn.has "macunix" == 1,
8-
is_unix = vim.fn.has "unix" == 1,
9-
},
10-
}
4+
local M = {}
115

126
local utils = require "nvim-tree.utils"
137
local events = require "nvim-tree.events"
@@ -34,7 +28,7 @@ function M.fn(node)
3428
end
3529

3630
-- configs
37-
if M.config.is_unix then
31+
if utils.is_unix then
3832
if M.config.trash.cmd == nil then
3933
M.config.trash.cmd = "trash"
4034
end
@@ -108,6 +102,7 @@ function M.fn(node)
108102
end
109103

110104
function M.setup(opts)
105+
M.config = {}
111106
M.config.trash = opts.trash or {}
112107
M.enable_reload = not opts.filesystem_watchers.enable
113108
end

lua/nvim-tree/actions/node/system-open.lua

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
local notify = require "nvim-tree.notify"
2+
local utils = require "nvim-tree.utils"
23

3-
local M = {
4-
config = {
5-
is_windows = vim.fn.has "win32" == 1 or vim.fn.has "win32unix" == 1,
6-
is_macos = vim.fn.has "mac" == 1 or vim.fn.has "macunix" == 1,
7-
is_unix = vim.fn.has "unix" == 1,
8-
},
9-
}
4+
local M = {}
105

116
function M.fn(node)
127
if #M.config.system_open.cmd == 0 then
@@ -50,17 +45,18 @@ function M.fn(node)
5045
end
5146

5247
function M.setup(opts)
48+
M.config = {}
5349
M.config.system_open = opts.system_open or {}
5450

5551
if #M.config.system_open.cmd == 0 then
56-
if M.config.is_windows then
52+
if utils.is_windows then
5753
M.config.system_open = {
5854
cmd = "cmd",
5955
args = { "/c", "start", '""' },
6056
}
61-
elseif M.config.is_macos then
57+
elseif utils.is_macos then
6258
M.config.system_open.cmd = "open"
63-
elseif M.config.is_unix then
59+
elseif utils.is_unix then
6460
M.config.system_open.cmd = "xdg-open"
6561
end
6662
end

lua/nvim-tree/explorer/explore.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ local function populate_children(handle, cwd, node, git_status)
2323
end
2424

2525
local abs = utils.path_join { cwd, name }
26+
27+
local pn = string.format("explore populate_children %s", abs)
28+
local ps = log.profile_start(pn)
29+
2630
t = get_type_from(t, abs)
2731
if not filters.should_filter(abs, filter_status) and not nodes_by_path[abs] then
2832
local child = nil
@@ -42,6 +46,8 @@ local function populate_children(handle, cwd, node, git_status)
4246
explorer_node.update_git_status(child, node_ignored, git_status)
4347
end
4448
end
49+
50+
log.profile_end(ps, pn)
4551
end
4652
end
4753

lua/nvim-tree/explorer/node-builders.lua

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
local utils = require "nvim-tree.utils"
22
local watch = require "nvim-tree.explorer.watch"
33

4-
local M = {
5-
is_windows = vim.fn.has "win32" == 1,
6-
is_wsl = vim.fn.has "wsl" == 1,
7-
}
4+
local M = {}
85

96
function M.folder(parent, absolute_path, name)
107
local handle = utils.fs_scandir_profiled(absolute_path)
@@ -27,21 +24,16 @@ function M.folder(parent, absolute_path, name)
2724
return node
2825
end
2926

30-
function M.is_executable(parent, absolute_path, ext)
31-
if M.is_windows then
32-
return utils.is_windows_exe(ext)
33-
elseif M.is_wsl then
34-
if parent.is_wsl_windows_fs_path == nil then
35-
-- Evaluate lazily when needed and do so only once for each parent
36-
-- as 'wslpath' calls can get expensive in highly populated directories.
37-
parent.is_wsl_windows_fs_path = utils.is_wsl_windows_fs_path(absolute_path)
38-
end
39-
40-
if parent.is_wsl_windows_fs_path then
41-
return utils.is_wsl_windows_fs_exe(ext)
42-
end
27+
--- path is an executable file or directory
28+
--- @param absolute_path string
29+
--- @return boolean
30+
function M.is_executable(absolute_path)
31+
if utils.is_windows or utils.is_wsl then
32+
--- executable detection on windows is buggy and not performant hence it is disabled
33+
return false
34+
else
35+
return vim.loop.fs_access(absolute_path, "X")
4336
end
44-
return vim.loop.fs_access(absolute_path, "X")
4537
end
4638

4739
function M.file(parent, absolute_path, name)
@@ -50,7 +42,7 @@ function M.file(parent, absolute_path, name)
5042
return {
5143
type = "file",
5244
absolute_path = absolute_path,
53-
executable = M.is_executable(parent, absolute_path, ext),
45+
executable = M.is_executable(absolute_path),
5446
extension = ext,
5547
fs_stat = vim.loop.fs_stat(absolute_path),
5648
name = name,

lua/nvim-tree/explorer/reload.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ function M.reload(node, git_status, unloaded_bufnr)
104104
else
105105
local n = nodes_by_path[abs]
106106
if n then
107-
n.executable = builders.is_executable(n.parent, abs, n.extension or "")
107+
n.executable = builders.is_executable(abs)
108108
n.fs_stat = fs_stat_cached(abs)
109109
end
110110
end

lua/nvim-tree/utils.lua

Lines changed: 4 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ local M = {
66
debouncers = {},
77
}
88

9-
M.is_windows = vim.fn.has "win32" == 1 or vim.fn.has "win32unix" == 1
9+
M.is_unix = vim.fn.has "unix" == 1
10+
M.is_macos = vim.fn.has "mac" == 1 or vim.fn.has "macunix" == 1
1011
M.is_wsl = vim.fn.has "wsl" == 1
12+
-- false for WSL
13+
M.is_windows = vim.fn.has "win32" == 1 or vim.fn.has "win32unix" == 1
1114

1215
function M.path_to_matching_str(path)
1316
return path:gsub("(%-)", "(%%-)"):gsub("(%.)", "(%%.)"):gsub("(%_)", "(%%_)")
@@ -152,63 +155,6 @@ function M.get_nodes_by_line(nodes_all, line_start)
152155
return nodes_by_line
153156
end
154157

155-
---Matching executable files in Windows.
156-
---@param ext string
157-
---@return boolean
158-
function M.is_windows_exe(ext)
159-
if not M.pathexts then
160-
if not vim.env.PATHEXT then
161-
return false
162-
end
163-
164-
local wexe = vim.split(vim.env.PATHEXT:gsub("%.", ""), ";")
165-
M.pathexts = {}
166-
for _, v in pairs(wexe) do
167-
M.pathexts[v] = true
168-
end
169-
end
170-
171-
return M.pathexts[ext:upper()]
172-
end
173-
174-
--- Check whether path maps to Windows filesystem mounted by WSL
175-
-- @param path string
176-
-- @return boolean
177-
function M.is_wsl_windows_fs_path(path)
178-
-- Run 'wslpath' command to try translating WSL path to Windows path.
179-
-- Consume stderr output as well because 'wslpath' can produce permission
180-
-- errors on some files (e.g. temporary files in root of system drive).
181-
local handle = io.popen('wslpath -w "' .. path .. '" 2>/dev/null')
182-
if handle then
183-
local output = handle:read "*a"
184-
handle:close()
185-
186-
return string.find(output, "^\\\\wsl$\\") == nil
187-
end
188-
189-
return false
190-
end
191-
192-
--- Check whether extension is Windows executable under WSL
193-
-- @param ext string
194-
-- @return boolean
195-
function M.is_wsl_windows_fs_exe(ext)
196-
if not vim.env.PATHEXT then
197-
-- Extract executable extensions from within WSL.
198-
-- Redirect stderr to null to silence warnings when
199-
-- Windows command is executed from Linux filesystem:
200-
-- > CMD.EXE was started with the above path as the current directory.
201-
-- > UNC paths are not supported. Defaulting to Windows directory.
202-
local handle = io.popen 'cmd.exe /c "echo %PATHEXT%" 2>/dev/null'
203-
if handle then
204-
vim.env.PATHEXT = handle:read "*a"
205-
handle:close()
206-
end
207-
end
208-
209-
return M.is_windows_exe(ext)
210-
end
211-
212158
function M.rename_loaded_buffers(old_path, new_path)
213159
for _, buf in pairs(vim.api.nvim_list_bufs()) do
214160
if vim.api.nvim_buf_is_loaded(buf) then

0 commit comments

Comments
 (0)