Skip to content

Commit 4a725c0

Browse files
authored
fix(#1555): incorrect exe highlight in Windows filesystem from WSL (#1557)
1 parent ce5d0a6 commit 4a725c0

File tree

3 files changed

+58
-5
lines changed

3 files changed

+58
-5
lines changed

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ local watch = require "nvim-tree.explorer.watch"
44

55
local M = {
66
is_windows = vim.fn.has "win32" == 1,
7+
is_wsl = vim.fn.has "wsl" == 1,
78
}
89

910
function M.folder(parent, absolute_path, name)
@@ -24,9 +25,19 @@ function M.folder(parent, absolute_path, name)
2425
}
2526
end
2627

27-
function M.is_executable(absolute_path, ext)
28+
function M.is_executable(parent, absolute_path, ext)
2829
if M.is_windows then
2930
return utils.is_windows_exe(ext)
31+
elseif M.is_wsl then
32+
if parent.is_wsl_windows_fs_path == nil then
33+
-- Evaluate lazily when needed and do so only once for each parent
34+
-- as 'wslpath' calls can get expensive in highly populated directories.
35+
parent.is_wsl_windows_fs_path = utils.is_wsl_windows_fs_path(absolute_path)
36+
end
37+
38+
if parent.is_wsl_windows_fs_path then
39+
return utils.is_wsl_windows_fs_exe(ext)
40+
end
3041
end
3142
return uv.fs_access(absolute_path, "X")
3243
end
@@ -37,7 +48,7 @@ function M.file(parent, absolute_path, name)
3748
return {
3849
type = "file",
3950
absolute_path = absolute_path,
40-
executable = M.is_executable(absolute_path, ext),
51+
executable = M.is_executable(parent, absolute_path, ext),
4152
extension = ext,
4253
fs_stat = uv.fs_stat(absolute_path),
4354
name = name,

lua/nvim-tree/explorer/reload.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ function M.reload(node, status)
8686
else
8787
local n = nodes_by_path[abs]
8888
if n then
89-
n.executable = builders.is_executable(abs, n.extension or "")
89+
n.executable = builders.is_executable(n.parent, abs, n.extension or "")
9090
n.fs_stat = fs_stat_cached(abs)
9191
end
9292
end

lua/nvim-tree/utils.lua

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ local M = {
1010
}
1111

1212
M.is_windows = vim.fn.has "win32" == 1 or vim.fn.has "win32unix" == 1
13+
M.is_wsl = vim.fn.has "wsl" == 1
1314

1415
function M.path_to_matching_str(path)
1516
return path:gsub("(%-)", "(%%-)"):gsub("(%.)", "(%%.)"):gsub("(%_)", "(%%_)")
@@ -171,8 +172,11 @@ end
171172
---@return boolean
172173
function M.is_windows_exe(ext)
173174
if not M.pathexts then
174-
local PATHEXT = vim.env.PATHEXT or ""
175-
local wexe = vim.split(PATHEXT:gsub("%.", ""), ";")
175+
if not vim.env.PATHEXT then
176+
return false
177+
end
178+
179+
local wexe = vim.split(vim.env.PATHEXT:gsub("%.", ""), ";")
176180
M.pathexts = {}
177181
for _, v in pairs(wexe) do
178182
M.pathexts[v] = true
@@ -182,6 +186,44 @@ function M.is_windows_exe(ext)
182186
return M.pathexts[ext:upper()]
183187
end
184188

189+
--- Check whether path maps to Windows filesystem mounted by WSL
190+
-- @param path string
191+
-- @return boolean
192+
function M.is_wsl_windows_fs_path(path)
193+
-- Run 'wslpath' command to try translating WSL path to Windows path.
194+
-- Consume stderr output as well because 'wslpath' can produce permission
195+
-- errors on some files (e.g. temporary files in root of system drive).
196+
local handle = io.popen('wslpath -w "' .. path .. '" 2>/dev/null')
197+
if handle then
198+
local output = handle:read "*a"
199+
handle:close()
200+
201+
return string.find(output, "^\\\\wsl$\\") == nil
202+
end
203+
204+
return false
205+
end
206+
207+
--- Check whether extension is Windows executable under WSL
208+
-- @param ext string
209+
-- @return boolean
210+
function M.is_wsl_windows_fs_exe(ext)
211+
if not vim.env.PATHEXT then
212+
-- Extract executable extensions from within WSL.
213+
-- Redirect stderr to null to silence warnings when
214+
-- Windows command is executed from Linux filesystem:
215+
-- > CMD.EXE was started with the above path as the current directory.
216+
-- > UNC paths are not supported. Defaulting to Windows directory.
217+
local handle = io.popen 'cmd.exe /c "echo %PATHEXT%" 2>/dev/null'
218+
if handle then
219+
vim.env.PATHEXT = handle:read "*a"
220+
handle:close()
221+
end
222+
end
223+
224+
return M.is_windows_exe(ext)
225+
end
226+
185227
function M.rename_loaded_buffers(old_path, new_path)
186228
for _, buf in pairs(a.nvim_list_bufs()) do
187229
if a.nvim_buf_is_loaded(buf) then

0 commit comments

Comments
 (0)