Skip to content

Commit

Permalink
refactor: move natural ordering logic and add config option
Browse files Browse the repository at this point in the history
  • Loading branch information
stevearc committed Mar 12, 2024
1 parent 4176bc7 commit a9a012a
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 29 deletions.
10 changes: 9 additions & 1 deletion lua/oil/columns.lua
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,10 @@ M.register("type", {
end,
})

local function pad_number(int)
return string.format("%012d", int)
end

M.register("name", {
render = function(entry, conf)
error("Do not use the name column. It is for sorting only")
Expand All @@ -289,7 +293,11 @@ M.register("name", {
end,

get_sort_value = function(entry)
return entry[FIELD_NAME]
if config.view_options.natural_order then
return entry[FIELD_NAME]:gsub("%d+", pad_number)
else
return entry[FIELD_NAME]
end
end,
})

Expand Down
3 changes: 3 additions & 0 deletions lua/oil/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ local default_config = {
is_always_hidden = function(name, bufnr)
return false
end,
-- Sort file names in a more intuitive order for humans. Is less performant,
-- so you may want to set to false if you work with large directories.
natural_order = true,
sort = {
-- sort order can be "asc" or "desc"
-- see :help oil-columns to see which columns are sortable
Expand Down
41 changes: 13 additions & 28 deletions lua/oil/view.lua
Original file line number Diff line number Diff line change
Expand Up @@ -515,37 +515,18 @@ M.initialize = function(bufnr)
keymap_util.set_keymaps(config.keymaps, bufnr)
end

--- Compare two strings while also treating multi-digit integers atomically
---@param a_val string
---@param b_val string
---@param order string
---@return boolean
local function natural_sort_compare(a_val, b_val, order)
---This method pads integers with zeroes so that they are always 12 digits long.
---As a result, comparing strings that have integers of different sizes work
---as if we were comparing integers (instead of strings of integers)
---
---Note: if the file name has integers of more than 12 digits, this padding does not work
---@param int integer
local function pad_to_compare(int)
return string.format("%012d", int)
end

local a_val_padded = string.gsub(a_val, "%d+", pad_to_compare)
local b_val_padded = string.gsub(b_val, "%d+", pad_to_compare)

if order == "desc" then
return a_val_padded > b_val_padded
else
return a_val_padded < b_val_padded
end
end

---@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 sort_config = config.view_options.sort

-- If empty, default to type + name sorting
if vim.tbl_isempty(sort_config) then
sort_config = { { "type", "asc" }, { "name", "asc" } }
end

for _, sort_pair in ipairs(sort_config) do
local col_name, order = unpack(sort_pair)
if order ~= "asc" and order ~= "desc" then
vim.notify_once(
Expand Down Expand Up @@ -573,7 +554,11 @@ local function get_sort_function(adapter)
local a_val = get_sort_value(a)
local b_val = get_sort_value(b)
if a_val ~= b_val then
return natural_sort_compare(a_val, b_val, order)
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]
Expand Down

0 comments on commit a9a012a

Please sign in to comment.