fix: can view drives on Windows

This commit is contained in:
Steven Arcangeli 2023-11-05 07:27:28 -08:00
parent 7ea4dda1a5
commit 126a8a2346
4 changed files with 92 additions and 43 deletions

View file

@ -49,8 +49,8 @@ local fs_stat_meta_fields = {
stat = function(parent_url, entry, cb) stat = function(parent_url, entry, cb)
local _, path = util.parse_url(parent_url) local _, path = util.parse_url(parent_url)
assert(path) assert(path)
local dir = fs.posix_to_os_path(path) local dir = fs.posix_to_os_path(path .. entry[FIELD_NAME])
uv.fs_stat(fs.join(dir, entry[FIELD_NAME]), cb) uv.fs_stat(dir, cb)
end, end,
} }
@ -208,6 +208,9 @@ end
M.normalize_url = function(url, callback) M.normalize_url = function(url, callback)
local scheme, path = util.parse_url(url) local scheme, path = util.parse_url(url)
assert(path) assert(path)
if fs.is_windows and path == '/' then
return callback(url)
end
local os_path = vim.fn.fnamemodify(fs.posix_to_os_path(path), ":p") local os_path = vim.fn.fnamemodify(fs.posix_to_os_path(path), ":p")
uv.fs_realpath(os_path, function(err, new_os_path) uv.fs_realpath(os_path, function(err, new_os_path)
local realpath = new_os_path or os_path local realpath = new_os_path or os_path
@ -254,12 +257,66 @@ M.get_entry_path = function(url, entry, cb)
end end
end end
---@param url string
---@param column_defs string[]
---@param cb fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun())
local function list_windows_drives(url, column_defs, cb)
local fetch_meta = columns.get_metadata_fetcher(M, column_defs)
local stdout = ""
local jid = vim.fn.jobstart({ 'wmic', 'logicaldisk', 'get', 'name' }, {
stdout_buffered = true,
on_stdout = function(_, data)
stdout = table.concat(data, '\n')
end,
on_exit = function(_, code)
if code ~= 0 then
return cb("Error listing windows devices")
end
local lines = vim.split(stdout, '\n', { plain = true, trimempty = true })
-- Remove the "Name" header
table.remove(lines, 1)
local internal_entries = {}
local complete_disk_cb = util.cb_collect(#lines, function(err)
if err then
cb(err)
else
cb(nil, internal_entries)
end
end)
for _, disk in ipairs(lines) do
if disk:match("^%s*$") then
-- Skip empty line
complete_disk_cb()
else
disk = disk:gsub(":%s*$", "")
local cache_entry = cache.create_entry(url, disk, "directory")
fetch_meta(url, cache_entry, function(err)
if err then
complete_disk_cb(err)
else
table.insert(internal_entries, cache_entry)
complete_disk_cb()
end
end)
end
end
end
})
if jid <= 0 then
cb("Could not list windows devices")
end
end
---@param url string ---@param url string
---@param column_defs string[] ---@param column_defs string[]
---@param cb fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun()) ---@param cb fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun())
M.list = function(url, column_defs, cb) M.list = function(url, column_defs, cb)
local _, path = util.parse_url(url) local _, path = util.parse_url(url)
assert(path) assert(path)
if fs.is_windows and path == '/' then
return list_windows_drives(url, column_defs, cb)
end
local dir = fs.posix_to_os_path(path) local dir = fs.posix_to_os_path(path)
local fetch_meta = columns.get_metadata_fetcher(M, column_defs) local fetch_meta = columns.get_metadata_fetcher(M, column_defs)
@ -294,9 +351,6 @@ M.list = function(url, column_defs, cb)
for _, entry in ipairs(entries) do for _, entry in ipairs(entries) do
local cache_entry = cache.create_entry(url, entry.name, entry.type) local cache_entry = cache.create_entry(url, entry.name, entry.type)
fetch_meta(url, cache_entry, function(meta_err) fetch_meta(url, cache_entry, function(meta_err)
if err then
poll(meta_err)
else
table.insert(internal_entries, cache_entry) table.insert(internal_entries, cache_entry)
local meta = cache_entry[FIELD_META] local meta = cache_entry[FIELD_META]
-- Make sure we always get fs_stat info for links -- Make sure we always get fs_stat info for links
@ -317,7 +371,6 @@ M.list = function(url, column_defs, cb)
else else
poll() poll()
end end
end
end) end)
end end
else else
@ -342,6 +395,9 @@ M.is_modifiable = function(bufnr)
local bufname = vim.api.nvim_buf_get_name(bufnr) local bufname = vim.api.nvim_buf_get_name(bufnr)
local _, path = util.parse_url(bufname) local _, path = util.parse_url(bufname)
assert(path) assert(path)
if fs.is_windows and path == '/' then
return false
end
local dir = fs.posix_to_os_path(path) local dir = fs.posix_to_os_path(path)
local stat = uv.fs_stat(dir) local stat = uv.fs_stat(dir)
if not stat then if not stat then

View file

@ -83,7 +83,8 @@ end
M.posix_to_os_path = function(path) M.posix_to_os_path = function(path)
if M.is_windows then if M.is_windows then
if vim.startswith(path, "/") then if vim.startswith(path, "/") then
local drive, rem = path:match("^/([^/]+)/(.*)$") local drive = path:match("^/(%a+)")
local rem = path:sub(drive:len() + 2)
return string.format("%s:\\%s", drive, rem:gsub("/", "\\")) return string.format("%s:\\%s", drive, rem:gsub("/", "\\"))
else else
local newpath = path:gsub("/", "\\") local newpath = path:gsub("/", "\\")

View file

@ -1,16 +1,8 @@
local fs = require("oil.fs")
local M = {} local M = {}
---@param path string ---@param path string
---@return string ---@return string
M.parent = function(path) M.parent = function(path)
-- Do I love this hack? No I do not.
-- Does it work? Yes. Mostly. For now.
if fs.is_windows then
if path:match("^/%a+/?$") then
return path
end
end
if path == "/" then if path == "/" then
return "/" return "/"
elseif path == "" then elseif path == "" then