feat: api to sort directory contents (#169)

This commit is contained in:
Steven Arcangeli 2023-09-08 18:55:45 -07:00
parent ca2560cae8
commit 879d280617
11 changed files with 256 additions and 54 deletions

View file

@ -100,6 +100,17 @@ M.set_columns = function(cols)
end
end
M.set_sort = function(new_sort)
local any_modified = are_any_modified()
if any_modified then
vim.notify("Cannot change sorting when you have unsaved changes", vim.log.levels.WARN)
else
config.view_options.sort = new_sort
-- TODO only refetch if we don't have all the necessary data for the columns
M.rerender_all_oil_buffers({ refetch = true })
end
end
-- List of bufnrs
local session = {}
@ -351,17 +362,46 @@ M.initialize = function(bufnr)
keymap_util.set_keymaps("", config.keymaps, bufnr)
end
---@param entry oil.InternalEntry
---@return boolean
local function is_entry_directory(entry)
local type = entry[FIELD_TYPE]
if type == "directory" then
return true
elseif type == "link" then
local meta = entry[FIELD_META]
return meta and meta.link_stat and meta.link_stat.type == "directory"
else
return false
---@param adapter oil.Adapter
---@return fun(a: oil.InternalEntry, b: oil.InternalEntry): boolean
local function get_sort_function(adapter)
local idx_funs = {}
for _, sort_pair in ipairs(config.view_options.sort) do
local col_name, order = unpack(sort_pair)
if order ~= "asc" and order ~= "desc" then
vim.notify_once(
string.format(
"Column '%s' has invalid sort order '%s'. Should be either 'asc' or 'desc'",
col_name,
order
),
vim.log.levels.WARN
)
end
local col = columns.get_column(adapter, col_name)
if col and col.get_sort_value then
table.insert(idx_funs, { col.get_sort_value, order })
else
vim.notify_once(
string.format("Column '%s' does not support sorting", col_name),
vim.log.levels.WARN
)
end
end
return function(a, b)
for _, sort_fn in ipairs(idx_funs) do
local get_sort_value, order = unpack(sort_fn)
local a_val = get_sort_value(a)
local b_val = get_sort_value(b)
if a_val ~= b_val then
if order == "desc" then
return a_val > b_val
else
return a_val < b_val
end
end
end
return a[FIELD_NAME] < b[FIELD_NAME]
end
end
@ -390,14 +430,7 @@ local function render_buffer(bufnr, opts)
local entries = cache.list_url(bufname)
local entry_list = vim.tbl_values(entries)
table.sort(entry_list, function(a, b)
local a_isdir = is_entry_directory(a)
local b_isdir = is_entry_directory(b)
if a_isdir ~= b_isdir then
return a_isdir
end
return a[FIELD_NAME] < b[FIELD_NAME]
end)
table.sort(entry_list, get_sort_function(adapter))
local jump_idx
if opts.jump_first then
@ -512,6 +545,21 @@ M.format_entry_cols = function(entry, column_defs, col_width, adapter)
return cols
end
---Get the column names that are used for view and sort
---@return string[]
local function get_used_columns()
local cols = {}
for _, def in ipairs(config.columns) do
local name = util.split_config(def)
table.insert(cols, name)
end
for _, sort_pair in ipairs(config.view_options.sort) do
local name = sort_pair[1]
table.insert(cols, name)
end
return cols
end
---@param bufnr integer
---@param opts nil|table
--- preserve_undo nil|boolean
@ -579,7 +627,7 @@ M.render_buffer_async = function(bufnr, opts, callback)
end
cache.begin_update_url(bufname)
adapter.list(bufname, config.columns, function(err, entries, fetch_more)
adapter.list(bufname, get_used_columns(), function(err, entries, fetch_more)
loading.set_loading(bufnr, false)
if err then
cache.end_update_url(bufname)