From 126a8a23465312683edf646555b3031bfe56796d Mon Sep 17 00:00:00 2001 From: Steven Arcangeli Date: Sun, 5 Nov 2023 07:27:28 -0800 Subject: [PATCH] fix: can view drives on Windows --- lua/oil/adapters/files.lua | 104 ++++++++++++++++++++++++++++--------- lua/oil/fs.lua | 3 +- lua/oil/init.lua | 20 +++---- lua/oil/pathutil.lua | 8 --- 4 files changed, 92 insertions(+), 43 deletions(-) diff --git a/lua/oil/adapters/files.lua b/lua/oil/adapters/files.lua index ad4ba3c..f8dad85 100644 --- a/lua/oil/adapters/files.lua +++ b/lua/oil/adapters/files.lua @@ -49,8 +49,8 @@ local fs_stat_meta_fields = { stat = function(parent_url, entry, cb) local _, path = util.parse_url(parent_url) assert(path) - local dir = fs.posix_to_os_path(path) - uv.fs_stat(fs.join(dir, entry[FIELD_NAME]), cb) + local dir = fs.posix_to_os_path(path .. entry[FIELD_NAME]) + uv.fs_stat(dir, cb) end, } @@ -208,6 +208,9 @@ end M.normalize_url = function(url, callback) local scheme, path = util.parse_url(url) 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") uv.fs_realpath(os_path, function(err, new_os_path) local realpath = new_os_path or os_path @@ -254,12 +257,66 @@ M.get_entry_path = function(url, entry, cb) 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 column_defs string[] ---@param cb fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun()) M.list = function(url, column_defs, cb) local _, path = util.parse_url(url) 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 fetch_meta = columns.get_metadata_fetcher(M, column_defs) @@ -294,29 +351,25 @@ M.list = function(url, column_defs, cb) for _, entry in ipairs(entries) do local cache_entry = cache.create_entry(url, entry.name, entry.type) fetch_meta(url, cache_entry, function(meta_err) - if err then - poll(meta_err) - else - table.insert(internal_entries, cache_entry) - local meta = cache_entry[FIELD_META] - -- Make sure we always get fs_stat info for links - if entry.type == "link" then - read_link_data(fs.join(dir, entry.name), function(link_err, link, link_stat) - if link_err then - poll(link_err) - else - if not meta then - meta = {} - cache_entry[FIELD_META] = meta - end - meta.link = link - meta.link_stat = link_stat - poll() + table.insert(internal_entries, cache_entry) + local meta = cache_entry[FIELD_META] + -- Make sure we always get fs_stat info for links + if entry.type == "link" then + read_link_data(fs.join(dir, entry.name), function(link_err, link, link_stat) + if link_err then + poll(link_err) + else + if not meta then + meta = {} + cache_entry[FIELD_META] = meta end - end) - else - poll() - end + meta.link = link + meta.link_stat = link_stat + poll() + end + end) + else + poll() end end) end @@ -342,6 +395,9 @@ M.is_modifiable = function(bufnr) local bufname = vim.api.nvim_buf_get_name(bufnr) local _, path = util.parse_url(bufname) assert(path) + if fs.is_windows and path == '/' then + return false + end local dir = fs.posix_to_os_path(path) local stat = uv.fs_stat(dir) if not stat then diff --git a/lua/oil/fs.lua b/lua/oil/fs.lua index 9fd5a1f..4f612a5 100644 --- a/lua/oil/fs.lua +++ b/lua/oil/fs.lua @@ -83,7 +83,8 @@ end M.posix_to_os_path = function(path) if M.is_windows 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("/", "\\")) else local newpath = path:gsub("/", "\\") diff --git a/lua/oil/init.lua b/lua/oil/init.lua index dfa1372..b730044 100644 --- a/lua/oil/init.lua +++ b/lua/oil/init.lua @@ -533,12 +533,12 @@ M.select = function(opts, callback) local child = dir .. entry.name local url = scheme .. child local is_directory = entry.type == "directory" - or ( - entry.type == "link" - and entry.meta - and entry.meta.link_stat - and entry.meta.link_stat.type == "directory" - ) + or ( + entry.type == "link" + and entry.meta + and entry.meta.link_stat + and entry.meta.link_stat.type == "directory" + ) if is_directory then url = url .. "/" -- If this is a new directory BUT we think we already have an entry with this name, disallow @@ -623,9 +623,9 @@ M.select = function(opts, callback) return finish(err) end if - opts.close - and vim.api.nvim_win_is_valid(prev_win) - and prev_win ~= vim.api.nvim_get_current_win() + opts.close + and vim.api.nvim_win_is_valid(prev_win) + and prev_win ~= vim.api.nvim_get_current_win() then vim.api.nvim_win_call(prev_win, function() M.close() @@ -758,7 +758,7 @@ local function restore_alt_buf() -- If we are editing the same buffer that we started oil from, set the alternate to be -- what it was before we opened oil local has_orig_alt, alt_buffer = - pcall(vim.api.nvim_win_get_var, 0, "oil_original_alternate") + pcall(vim.api.nvim_win_get_var, 0, "oil_original_alternate") if has_orig_alt and vim.api.nvim_buf_is_valid(alt_buffer) then vim.fn.setreg("#", alt_buffer) end diff --git a/lua/oil/pathutil.lua b/lua/oil/pathutil.lua index 1c8877c..b030389 100644 --- a/lua/oil/pathutil.lua +++ b/lua/oil/pathutil.lua @@ -1,16 +1,8 @@ -local fs = require("oil.fs") local M = {} ---@param path string ---@return string 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 return "/" elseif path == "" then