Fix `dirmonitor` sorting issues (#1599)
* Use `PATHSEP` in path-related functions * Don't stop on digits when getting the common part in `system.path_compare` * Avoid sorting multiple times in `dirwatch.get_directory_files` This also fixes the timeout detection in `recurse_pred`.
This commit is contained in:
parent
6cd1f96234
commit
5c5c77219b
|
@ -226,7 +226,7 @@ function common.path_suggest(text, root)
|
||||||
if root and root:sub(-1) ~= PATHSEP then
|
if root and root:sub(-1) ~= PATHSEP then
|
||||||
root = root .. PATHSEP
|
root = root .. PATHSEP
|
||||||
end
|
end
|
||||||
local path, name = text:match("^(.-)([^/\\]*)$")
|
local path, name = text:match("^(.-)([^"..PATHSEP.."]*)$")
|
||||||
local clean_dotslash = false
|
local clean_dotslash = false
|
||||||
-- ignore root if path is absolute
|
-- ignore root if path is absolute
|
||||||
local is_absolute = common.is_absolute_path(text)
|
local is_absolute = common.is_absolute_path(text)
|
||||||
|
@ -279,7 +279,7 @@ end
|
||||||
---@param text string The input path.
|
---@param text string The input path.
|
||||||
---@return string[]
|
---@return string[]
|
||||||
function common.dir_path_suggest(text)
|
function common.dir_path_suggest(text)
|
||||||
local path, name = text:match("^(.-)([^/\\]*)$")
|
local path, name = text:match("^(.-)([^"..PATHSEP.."]*)$")
|
||||||
local files = system.list_dir(path == "" and "." or path) or {}
|
local files = system.list_dir(path == "" and "." or path) or {}
|
||||||
local res = {}
|
local res = {}
|
||||||
for _, file in ipairs(files) do
|
for _, file in ipairs(files) do
|
||||||
|
@ -298,7 +298,7 @@ end
|
||||||
---@param dir_list string[] A list of paths to filter.
|
---@param dir_list string[] A list of paths to filter.
|
||||||
---@return string[]
|
---@return string[]
|
||||||
function common.dir_list_suggest(text, dir_list)
|
function common.dir_list_suggest(text, dir_list)
|
||||||
local path, name = text:match("^(.-)([^/\\]*)$")
|
local path, name = text:match("^(.-)([^"..PATHSEP.."]*)$")
|
||||||
local res = {}
|
local res = {}
|
||||||
for _, dir_path in ipairs(dir_list) do
|
for _, dir_path in ipairs(dir_list) do
|
||||||
if dir_path:lower():find(text:lower(), nil, true) == 1 then
|
if dir_path:lower():find(text:lower(), nil, true) == 1 then
|
||||||
|
@ -461,7 +461,7 @@ end
|
||||||
function common.basename(path)
|
function common.basename(path)
|
||||||
-- a path should never end by / or \ except if it is '/' (unix root) or
|
-- a path should never end by / or \ except if it is '/' (unix root) or
|
||||||
-- 'X:\' (windows drive)
|
-- 'X:\' (windows drive)
|
||||||
return path:match("[^\\/]+$") or path
|
return path:match("[^"..PATHSEP.."]+$") or path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -470,7 +470,7 @@ end
|
||||||
---@param path string
|
---@param path string
|
||||||
---@return string|nil
|
---@return string|nil
|
||||||
function common.dirname(path)
|
function common.dirname(path)
|
||||||
return path:match("(.+)[\\/][^\\/]+$")
|
return path:match("(.+)["..PATHSEP.."][^"..PATHSEP.."]+$")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -513,10 +513,10 @@ end
|
||||||
|
|
||||||
local function split_on_slash(s, sep_pattern)
|
local function split_on_slash(s, sep_pattern)
|
||||||
local t = {}
|
local t = {}
|
||||||
if s:match("^[/\\]") then
|
if s:match("^["..PATHSEP.."]") then
|
||||||
t[#t + 1] = ""
|
t[#t + 1] = ""
|
||||||
end
|
end
|
||||||
for fragment in string.gmatch(s, "([^/\\]+)") do
|
for fragment in string.gmatch(s, "([^"..PATHSEP.."]+)") do
|
||||||
t[#t + 1] = fragment
|
t[#t + 1] = fragment
|
||||||
end
|
end
|
||||||
return t
|
return t
|
||||||
|
@ -649,7 +649,7 @@ function common.mkdirp(path)
|
||||||
while path and path ~= "" do
|
while path and path ~= "" do
|
||||||
local success_mkdir = system.mkdir(path)
|
local success_mkdir = system.mkdir(path)
|
||||||
if success_mkdir then break end
|
if success_mkdir then break end
|
||||||
local updir, basedir = path:match("(.*)[/\\](.+)$")
|
local updir, basedir = path:match("(.*)["..PATHSEP.."](.+)$")
|
||||||
table.insert(subdirs, 1, basedir or path)
|
table.insert(subdirs, 1, basedir or path)
|
||||||
path = updir
|
path = updir
|
||||||
end
|
end
|
||||||
|
|
|
@ -190,47 +190,45 @@ end
|
||||||
-- "root" will by an absolute path without trailing '/'
|
-- "root" will by an absolute path without trailing '/'
|
||||||
-- "path" will be a path starting without '/' and without trailing '/'
|
-- "path" will be a path starting without '/' and without trailing '/'
|
||||||
-- or the empty string.
|
-- or the empty string.
|
||||||
-- It will identifies a sub-path within "root.
|
-- It identifies a sub-path within "root".
|
||||||
-- The current path location will therefore always be: root .. path.
|
-- The current path location will therefore always be: root .. path.
|
||||||
-- When recursing "root" will always be the same, only "path" will change.
|
-- When recursing, "root" will always be the same, only "path" will change.
|
||||||
-- Returns a list of file "items". In each item the "filename" will be the
|
-- Returns a list of file "items". In each item the "filename" will be the
|
||||||
-- complete file path relative to "root" *without* the trailing '/', and without the starting '/'.
|
-- complete file path relative to "root" *without* the trailing '/', and without the starting '/'.
|
||||||
function dirwatch.get_directory_files(dir, root, path, t, entries_count, recurse_pred)
|
function dirwatch.get_directory_files(dir, root, path, entries_count, recurse_pred)
|
||||||
|
local t = {}
|
||||||
local t0 = system.get_time()
|
local t0 = system.get_time()
|
||||||
local t_elapsed = system.get_time() - t0
|
|
||||||
local dirs, files = {}, {}
|
|
||||||
local ignore_compiled = compile_ignore_files()
|
local ignore_compiled = compile_ignore_files()
|
||||||
|
|
||||||
|
|
||||||
local all = system.list_dir(root .. PATHSEP .. path)
|
local all = system.list_dir(root .. PATHSEP .. path)
|
||||||
if not all then return nil end
|
if not all then return nil end
|
||||||
|
local entries = { }
|
||||||
for _, file in ipairs(all or {}) do
|
for _, file in ipairs(all) do
|
||||||
local info = get_project_file_info(root, (path ~= "" and (path .. PATHSEP) or "") .. file, ignore_compiled)
|
local info = get_project_file_info(root, (path ~= "" and (path .. PATHSEP) or "") .. file, ignore_compiled)
|
||||||
if info then
|
if info then
|
||||||
table.insert(info.type == "dir" and dirs or files, info)
|
table.insert(entries, info)
|
||||||
entries_count = entries_count + 1
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
table.sort(entries, compare_file)
|
||||||
|
|
||||||
local recurse_complete = true
|
local recurse_complete = true
|
||||||
table.sort(dirs, compare_file)
|
for _, info in ipairs(entries) do
|
||||||
for _, f in ipairs(dirs) do
|
table.insert(t, info)
|
||||||
table.insert(t, f)
|
entries_count = entries_count + 1
|
||||||
if recurse_pred(dir, f.filename, entries_count, t_elapsed) then
|
if info.type == "dir" then
|
||||||
local _, complete, n = dirwatch.get_directory_files(dir, root, f.filename, t, entries_count, recurse_pred)
|
if recurse_pred(dir, info.filename, entries_count, system.get_time() - t0) then
|
||||||
|
local t_rec, complete, n = dirwatch.get_directory_files(dir, root, info.filename, entries_count, recurse_pred)
|
||||||
recurse_complete = recurse_complete and complete
|
recurse_complete = recurse_complete and complete
|
||||||
if n ~= nil then
|
if n ~= nil then
|
||||||
entries_count = n
|
entries_count = n
|
||||||
|
for _, info_rec in ipairs(t_rec) do
|
||||||
|
table.insert(t, info_rec)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
recurse_complete = false
|
recurse_complete = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
table.sort(files, compare_file)
|
|
||||||
for _, f in ipairs(files) do
|
|
||||||
table.insert(t, f)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return t, recurse_complete, entries_count
|
return t, recurse_complete, entries_count
|
||||||
|
|
|
@ -102,7 +102,7 @@ local function strip_leading_path(filename)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function strip_trailing_slash(filename)
|
local function strip_trailing_slash(filename)
|
||||||
if filename:match("[^:][/\\]$") then
|
if filename:match("[^:]["..PATHSEP.."]$") then
|
||||||
return filename:sub(1, -2)
|
return filename:sub(1, -2)
|
||||||
end
|
end
|
||||||
return filename
|
return filename
|
||||||
|
@ -120,9 +120,7 @@ local function show_max_files_warning(dir)
|
||||||
"Too many files in project directory: stopped reading at "..
|
"Too many files in project directory: stopped reading at "..
|
||||||
config.max_project_files.." files. For more information see "..
|
config.max_project_files.." files. For more information see "..
|
||||||
"usage.md at https://github.com/lite-xl/lite-xl."
|
"usage.md at https://github.com/lite-xl/lite-xl."
|
||||||
if core.status_view then
|
core.warn(message)
|
||||||
core.status_view:show_message("!", style.accent, message)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -184,7 +182,7 @@ local function refresh_directory(topdir, target)
|
||||||
directory_start_idx = directory_start_idx + 1
|
directory_start_idx = directory_start_idx + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local files = dirwatch.get_directory_files(topdir, topdir.name, (target or ""), {}, 0, function() return false end)
|
local files = dirwatch.get_directory_files(topdir, topdir.name, (target or ""), 0, function() return false end)
|
||||||
local change = false
|
local change = false
|
||||||
|
|
||||||
-- If this file doesn't exist, we should be calling this on our parent directory, assume we'll do that.
|
-- If this file doesn't exist, we should be calling this on our parent directory, assume we'll do that.
|
||||||
|
@ -265,7 +263,7 @@ function core.add_project_directory(path)
|
||||||
|
|
||||||
local fstype = PLATFORM == "Linux" and system.get_fs_type(topdir.name) or "unknown"
|
local fstype = PLATFORM == "Linux" and system.get_fs_type(topdir.name) or "unknown"
|
||||||
topdir.force_scans = (fstype == "nfs" or fstype == "fuse")
|
topdir.force_scans = (fstype == "nfs" or fstype == "fuse")
|
||||||
local t, complete, entries_count = dirwatch.get_directory_files(topdir, topdir.name, "", {}, 0, timed_max_files_pred)
|
local t, complete, entries_count = dirwatch.get_directory_files(topdir, topdir.name, "", 0, timed_max_files_pred)
|
||||||
topdir.files = t
|
topdir.files = t
|
||||||
if not complete then
|
if not complete then
|
||||||
topdir.slow_filesystem = not complete and (entries_count <= config.max_project_files)
|
topdir.slow_filesystem = not complete and (entries_count <= config.max_project_files)
|
||||||
|
|
|
@ -24,7 +24,7 @@ local tooltip_alpha_rate = 1
|
||||||
|
|
||||||
local function get_depth(filename)
|
local function get_depth(filename)
|
||||||
local n = 1
|
local n = 1
|
||||||
for sep in filename:gmatch("[\\/]") do
|
for _ in filename:gmatch(PATHSEP) do
|
||||||
n = n + 1
|
n = n + 1
|
||||||
end
|
end
|
||||||
return n
|
return n
|
||||||
|
|
|
@ -1043,7 +1043,7 @@ static int f_load_native_plugin(lua_State *L) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Special purpose filepath compare function. Corresponds to the
|
/* Special purpose filepath compare function. Corresponds to the
|
||||||
order used in the TreeView view of the project's files. Returns true iff
|
order used in the TreeView view of the project's files. Returns true if
|
||||||
path1 < path2 in the TreeView order. */
|
path1 < path2 in the TreeView order. */
|
||||||
static int f_path_compare(lua_State *L) {
|
static int f_path_compare(lua_State *L) {
|
||||||
size_t len1, len2;
|
size_t len1, len2;
|
||||||
|
@ -1057,7 +1057,6 @@ static int f_path_compare(lua_State *L) {
|
||||||
size_t offset = 0, i, j;
|
size_t offset = 0, i, j;
|
||||||
for (i = 0; i < len1 && i < len2; i++) {
|
for (i = 0; i < len1 && i < len2; i++) {
|
||||||
if (path1[i] != path2[i]) break;
|
if (path1[i] != path2[i]) break;
|
||||||
if (isdigit(path1[i])) break;
|
|
||||||
if (path1[i] == PATHSEP) {
|
if (path1[i] == PATHSEP) {
|
||||||
offset = i + 1;
|
offset = i + 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue