refactor: remove overcomplicated meta_fields abstraction
This abstraction is overly generic for what it does. It's only ever used to help us conditionally perform a fs_stat for the local files adapter. We can replace that with a much dumber, much simpler bit of logic.
This commit is contained in:
parent
ba858b6625
commit
1f7da07a3e
2 changed files with 77 additions and 99 deletions
|
|
@ -12,6 +12,7 @@ local uv = vim.uv or vim.loop
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
local FIELD_NAME = constants.FIELD_NAME
|
local FIELD_NAME = constants.FIELD_NAME
|
||||||
|
local FIELD_TYPE = constants.FIELD_TYPE
|
||||||
local FIELD_META = constants.FIELD_META
|
local FIELD_META = constants.FIELD_META
|
||||||
|
|
||||||
local function read_link_data(path, cb)
|
local function read_link_data(path, cb)
|
||||||
|
|
@ -50,17 +51,8 @@ end
|
||||||
|
|
||||||
local file_columns = {}
|
local file_columns = {}
|
||||||
|
|
||||||
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 .. entry[FIELD_NAME])
|
|
||||||
uv.fs_stat(dir, cb)
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
|
|
||||||
file_columns.size = {
|
file_columns.size = {
|
||||||
meta_fields = fs_stat_meta_fields,
|
require_stat = true,
|
||||||
|
|
||||||
render = function(entry, conf)
|
render = function(entry, conf)
|
||||||
local meta = entry[FIELD_META]
|
local meta = entry[FIELD_META]
|
||||||
|
|
@ -97,7 +89,7 @@ file_columns.size = {
|
||||||
-- TODO support file permissions on windows
|
-- TODO support file permissions on windows
|
||||||
if not fs.is_windows then
|
if not fs.is_windows then
|
||||||
file_columns.permissions = {
|
file_columns.permissions = {
|
||||||
meta_fields = fs_stat_meta_fields,
|
require_stat = true,
|
||||||
|
|
||||||
render = function(entry, conf)
|
render = function(entry, conf)
|
||||||
local meta = entry[FIELD_META]
|
local meta = entry[FIELD_META]
|
||||||
|
|
@ -160,7 +152,7 @@ end)
|
||||||
|
|
||||||
for _, time_key in ipairs({ "ctime", "mtime", "atime", "birthtime" }) do
|
for _, time_key in ipairs({ "ctime", "mtime", "atime", "birthtime" }) do
|
||||||
file_columns[time_key] = {
|
file_columns[time_key] = {
|
||||||
meta_fields = fs_stat_meta_fields,
|
require_stat = true,
|
||||||
|
|
||||||
render = function(entry, conf)
|
render = function(entry, conf)
|
||||||
local meta = entry[FIELD_META]
|
local meta = entry[FIELD_META]
|
||||||
|
|
@ -206,6 +198,20 @@ for _, time_key in ipairs({ "ctime", "mtime", "atime", "birthtime" }) do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param column_defs table[]
|
||||||
|
---@return boolean
|
||||||
|
local function columns_require_stat(column_defs)
|
||||||
|
for _, def in ipairs(column_defs) do
|
||||||
|
local name = util.split_config(def)
|
||||||
|
local column = M.get_column(name)
|
||||||
|
---@diagnostic disable-next-line: undefined-field We only put this on the files adapter columns
|
||||||
|
if column and column.require_stat then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
---@param name string
|
---@param name string
|
||||||
---@return nil|oil.ColumnDefinition
|
---@return nil|oil.ColumnDefinition
|
||||||
M.get_column = function(name)
|
M.get_column = function(name)
|
||||||
|
|
@ -283,12 +289,64 @@ M.get_entry_path = function(url, entry, cb)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param parent_dir string
|
||||||
|
---@param entry oil.InternalEntry
|
||||||
|
---@param require_stat boolean
|
||||||
|
---@param cb fun(err?: string)
|
||||||
|
local function fetch_entry_metadata(parent_dir, entry, require_stat, cb)
|
||||||
|
local entry_path = fs.posix_to_os_path(parent_dir .. entry[FIELD_NAME])
|
||||||
|
local meta = entry[FIELD_META]
|
||||||
|
if not meta then
|
||||||
|
meta = {}
|
||||||
|
entry[FIELD_META] = meta
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Make sure we always get fs_stat info for links
|
||||||
|
if entry[FIELD_TYPE] == "link" then
|
||||||
|
read_link_data(entry_path, function(link_err, link, link_stat)
|
||||||
|
if link_err then
|
||||||
|
return cb(link_err)
|
||||||
|
end
|
||||||
|
meta.link = link
|
||||||
|
if link_stat then
|
||||||
|
-- Use the fstat of the linked file as the stat for the link
|
||||||
|
meta.link_stat = link_stat
|
||||||
|
meta.stat = link_stat
|
||||||
|
elseif require_stat then
|
||||||
|
-- The link is broken, so let's use the stat of the link itself
|
||||||
|
uv.fs_lstat(entry_path, function(stat_err, stat)
|
||||||
|
if stat_err then
|
||||||
|
return cb(stat_err)
|
||||||
|
end
|
||||||
|
meta.stat = stat
|
||||||
|
cb()
|
||||||
|
end)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
cb()
|
||||||
|
end)
|
||||||
|
elseif require_stat then
|
||||||
|
uv.fs_stat(entry_path, function(stat_err, stat)
|
||||||
|
if stat_err then
|
||||||
|
return cb(stat_err)
|
||||||
|
end
|
||||||
|
assert(stat)
|
||||||
|
meta.stat = stat
|
||||||
|
cb()
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
cb()
|
||||||
|
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())
|
||||||
local function list_windows_drives(url, column_defs, cb)
|
local function list_windows_drives(url, column_defs, cb)
|
||||||
---@cast M oil.FilesAdapter
|
local _, path = util.parse_url(url)
|
||||||
local fetch_meta = columns.get_metadata_fetcher(M, column_defs)
|
assert(path)
|
||||||
|
local require_stat = columns_require_stat(column_defs)
|
||||||
local stdout = ""
|
local stdout = ""
|
||||||
local jid = vim.fn.jobstart({ "wmic", "logicaldisk", "get", "name" }, {
|
local jid = vim.fn.jobstart({ "wmic", "logicaldisk", "get", "name" }, {
|
||||||
stdout_buffered = true,
|
stdout_buffered = true,
|
||||||
|
|
@ -318,14 +376,8 @@ local function list_windows_drives(url, column_defs, cb)
|
||||||
else
|
else
|
||||||
disk = disk:gsub(":%s*$", "")
|
disk = disk:gsub(":%s*$", "")
|
||||||
local cache_entry = cache.create_entry(url, disk, "directory")
|
local cache_entry = cache.create_entry(url, disk, "directory")
|
||||||
fetch_meta(url, cache_entry, function(err)
|
table.insert(internal_entries, cache_entry)
|
||||||
if err then
|
fetch_entry_metadata(path, cache_entry, require_stat, complete_disk_cb)
|
||||||
complete_disk_cb(err)
|
|
||||||
else
|
|
||||||
table.insert(internal_entries, cache_entry)
|
|
||||||
complete_disk_cb()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
@ -345,8 +397,7 @@ M.list = function(url, column_defs, cb)
|
||||||
return list_windows_drives(url, column_defs, cb)
|
return list_windows_drives(url, column_defs, cb)
|
||||||
end
|
end
|
||||||
local dir = fs.posix_to_os_path(path)
|
local dir = fs.posix_to_os_path(path)
|
||||||
---@cast M oil.Adapter
|
local require_stat = columns_require_stat(column_defs)
|
||||||
local fetch_meta = columns.get_metadata_fetcher(M, column_defs)
|
|
||||||
|
|
||||||
---@diagnostic disable-next-line: param-type-mismatch, discard-returns
|
---@diagnostic disable-next-line: param-type-mismatch, discard-returns
|
||||||
uv.fs_opendir(dir, function(open_err, fd)
|
uv.fs_opendir(dir, function(open_err, fd)
|
||||||
|
|
@ -378,28 +429,8 @@ M.list = function(url, column_defs, cb)
|
||||||
end)
|
end)
|
||||||
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)
|
table.insert(internal_entries, cache_entry)
|
||||||
table.insert(internal_entries, cache_entry)
|
fetch_entry_metadata(path, cache_entry, require_stat, poll)
|
||||||
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()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
else
|
|
||||||
poll()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
uv.fs_closedir(fd, function(close_err)
|
uv.fs_closedir(fd, function(close_err)
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ local all_columns = {}
|
||||||
---@class (exact) oil.ColumnDefinition
|
---@class (exact) oil.ColumnDefinition
|
||||||
---@field render fun(entry: oil.InternalEntry, conf: nil|table): nil|oil.TextChunk
|
---@field render fun(entry: oil.InternalEntry, conf: nil|table): nil|oil.TextChunk
|
||||||
---@field parse fun(line: string, conf: nil|table): nil|string, nil|string
|
---@field parse fun(line: string, conf: nil|table): nil|string, nil|string
|
||||||
---@field meta_fields? table<string, fun(parent_url: string, entry: oil.InternalEntry, cb: fun(err: nil|string))>
|
|
||||||
---@field compare? fun(entry: oil.InternalEntry, parsed_value: any): boolean
|
---@field compare? fun(entry: oil.InternalEntry, parsed_value: any): boolean
|
||||||
---@field render_action? fun(action: oil.ChangeAction): string
|
---@field render_action? fun(action: oil.ChangeAction): string
|
||||||
---@field perform_action? fun(action: oil.ChangeAction, callback: fun(err: nil|string))
|
---@field perform_action? fun(action: oil.ChangeAction, callback: fun(err: nil|string))
|
||||||
|
|
@ -54,46 +53,6 @@ M.get_supported_columns = function(adapter_or_scheme)
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param adapter oil.Adapter
|
|
||||||
---@param column_defs table[]
|
|
||||||
---@return fun(parent_url: string, entry: oil.InternalEntry, cb: fun(err: nil|string))
|
|
||||||
M.get_metadata_fetcher = function(adapter, column_defs)
|
|
||||||
local keyfetches = {}
|
|
||||||
local num_keys = 0
|
|
||||||
for _, def in ipairs(column_defs) do
|
|
||||||
local name = util.split_config(def)
|
|
||||||
local column = M.get_column(adapter, name)
|
|
||||||
if column and column.meta_fields then
|
|
||||||
for k, v in pairs(column.meta_fields) do
|
|
||||||
if not keyfetches[k] then
|
|
||||||
keyfetches[k] = v
|
|
||||||
num_keys = num_keys + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if num_keys == 0 then
|
|
||||||
return function(_, _, cb)
|
|
||||||
cb()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return function(parent_url, entry, cb)
|
|
||||||
cb = util.cb_collect(num_keys, cb)
|
|
||||||
local meta = {}
|
|
||||||
entry[FIELD_META] = meta
|
|
||||||
for k, v in pairs(keyfetches) do
|
|
||||||
v(parent_url, entry, function(err, value)
|
|
||||||
if err then
|
|
||||||
cb(err)
|
|
||||||
else
|
|
||||||
meta[k] = value
|
|
||||||
cb()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local EMPTY = { "-", "Comment" }
|
local EMPTY = { "-", "Comment" }
|
||||||
|
|
||||||
M.EMPTY = EMPTY
|
M.EMPTY = EMPTY
|
||||||
|
|
@ -110,18 +69,6 @@ M.render_col = function(adapter, col_def, entry)
|
||||||
return EMPTY
|
return EMPTY
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Make sure all the required metadata exists before attempting to render
|
|
||||||
if column.meta_fields then
|
|
||||||
local meta = entry[FIELD_META]
|
|
||||||
if not meta then
|
|
||||||
return EMPTY
|
|
||||||
end
|
|
||||||
for k in pairs(column.meta_fields) do
|
|
||||||
if not meta[k] then
|
|
||||||
return EMPTY
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local chunk = column.render(entry, conf)
|
local chunk = column.render(entry, conf)
|
||||||
if type(chunk) == "table" then
|
if type(chunk) == "table" then
|
||||||
if chunk[1]:match("^%s*$") then
|
if chunk[1]:match("^%s*$") then
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue