From 3ee903b16c256acebf8c695e93497275bb45b411 Mon Sep 17 00:00:00 2001 From: Guldoman Date: Wed, 29 Nov 2023 15:55:38 +0100 Subject: [PATCH] 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`. --- data/core/common.lua | 16 ++++++------- data/core/dirwatch.lua | 48 +++++++++++++++++++-------------------- data/core/init.lua | 10 ++++---- data/plugins/treeview.lua | 2 +- src/api/system.c | 3 +-- 5 files changed, 37 insertions(+), 42 deletions(-) diff --git a/data/core/common.lua b/data/core/common.lua index a887c307..82f1ab6f 100644 --- a/data/core/common.lua +++ b/data/core/common.lua @@ -226,7 +226,7 @@ function common.path_suggest(text, root) if root and root:sub(-1) ~= PATHSEP then root = root .. PATHSEP end - local path, name = text:match("^(.-)([^/\\]*)$") + local path, name = text:match("^(.-)([^"..PATHSEP.."]*)$") local clean_dotslash = false -- ignore root if path is absolute local is_absolute = common.is_absolute_path(text) @@ -279,7 +279,7 @@ end ---@param text string The input path. ---@return string[] 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 res = {} for _, file in ipairs(files) do @@ -298,7 +298,7 @@ end ---@param dir_list string[] A list of paths to filter. ---@return string[] function common.dir_list_suggest(text, dir_list) - local path, name = text:match("^(.-)([^/\\]*)$") + local path, name = text:match("^(.-)([^"..PATHSEP.."]*)$") local res = {} for _, dir_path in ipairs(dir_list) do if dir_path:lower():find(text:lower(), nil, true) == 1 then @@ -461,7 +461,7 @@ end function common.basename(path) -- a path should never end by / or \ except if it is '/' (unix root) or -- 'X:\' (windows drive) - return path:match("[^\\/]+$") or path + return path:match("[^"..PATHSEP.."]+$") or path end @@ -470,7 +470,7 @@ end ---@param path string ---@return string|nil function common.dirname(path) - return path:match("(.+)[\\/][^\\/]+$") + return path:match("(.+)["..PATHSEP.."][^"..PATHSEP.."]+$") end @@ -513,10 +513,10 @@ end local function split_on_slash(s, sep_pattern) local t = {} - if s:match("^[/\\]") then + if s:match("^["..PATHSEP.."]") then t[#t + 1] = "" end - for fragment in string.gmatch(s, "([^/\\]+)") do + for fragment in string.gmatch(s, "([^"..PATHSEP.."]+)") do t[#t + 1] = fragment end return t @@ -649,7 +649,7 @@ function common.mkdirp(path) while path and path ~= "" do local success_mkdir = system.mkdir(path) if success_mkdir then break end - local updir, basedir = path:match("(.*)[/\\](.+)$") + local updir, basedir = path:match("(.*)["..PATHSEP.."](.+)$") table.insert(subdirs, 1, basedir or path) path = updir end diff --git a/data/core/dirwatch.lua b/data/core/dirwatch.lua index 3b62fa24..d9ac4523 100644 --- a/data/core/dirwatch.lua +++ b/data/core/dirwatch.lua @@ -190,49 +190,47 @@ end -- "root" will by an absolute path without trailing '/' -- "path" will be a path starting without '/' and without trailing '/' -- 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. --- 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 -- 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 t_elapsed = system.get_time() - t0 - local dirs, files = {}, {} local ignore_compiled = compile_ignore_files() - local all = system.list_dir(root .. PATHSEP .. path) if not all then return nil end - - for _, file in ipairs(all or {}) do + local entries = { } + for _, file in ipairs(all) do local info = get_project_file_info(root, (path ~= "" and (path .. PATHSEP) or "") .. file, ignore_compiled) if info then - table.insert(info.type == "dir" and dirs or files, info) - entries_count = entries_count + 1 + table.insert(entries, info) end end + table.sort(entries, compare_file) local recurse_complete = true - table.sort(dirs, compare_file) - for _, f in ipairs(dirs) do - table.insert(t, f) - if recurse_pred(dir, f.filename, entries_count, t_elapsed) then - local _, complete, n = dirwatch.get_directory_files(dir, root, f.filename, t, entries_count, recurse_pred) - recurse_complete = recurse_complete and complete - if n ~= nil then - entries_count = n + for _, info in ipairs(entries) do + table.insert(t, info) + entries_count = entries_count + 1 + if info.type == "dir" then + 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 + if n ~= nil then + entries_count = n + for _, info_rec in ipairs(t_rec) do + table.insert(t, info_rec) + end + end + else + recurse_complete = false end - else - recurse_complete = false end end - table.sort(files, compare_file) - for _, f in ipairs(files) do - table.insert(t, f) - end - return t, recurse_complete, entries_count end diff --git a/data/core/init.lua b/data/core/init.lua index 61ee9b97..aee11529 100644 --- a/data/core/init.lua +++ b/data/core/init.lua @@ -102,7 +102,7 @@ local function strip_leading_path(filename) end local function strip_trailing_slash(filename) - if filename:match("[^:][/\\]$") then + if filename:match("[^:]["..PATHSEP.."]$") then return filename:sub(1, -2) end return filename @@ -120,9 +120,7 @@ local function show_max_files_warning(dir) "Too many files in project directory: stopped reading at ".. config.max_project_files.." files. For more information see ".. "usage.md at https://github.com/lite-xl/lite-xl." - if core.status_view then - core.status_view:show_message("!", style.accent, message) - end + core.warn(message) end @@ -184,7 +182,7 @@ local function refresh_directory(topdir, target) directory_start_idx = directory_start_idx + 1 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 -- 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" 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 if not complete then topdir.slow_filesystem = not complete and (entries_count <= config.max_project_files) diff --git a/data/plugins/treeview.lua b/data/plugins/treeview.lua index b27ba554..9037d51a 100644 --- a/data/plugins/treeview.lua +++ b/data/plugins/treeview.lua @@ -29,7 +29,7 @@ local tooltip_alpha_rate = 1 local function get_depth(filename) local n = 1 - for sep in filename:gmatch("[\\/]") do + for _ in filename:gmatch(PATHSEP) do n = n + 1 end return n diff --git a/src/api/system.c b/src/api/system.c index 2774a97a..32a06194 100644 --- a/src/api/system.c +++ b/src/api/system.c @@ -1058,7 +1058,7 @@ static int f_load_native_plugin(lua_State *L) { #endif /* 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. */ static int f_path_compare(lua_State *L) { size_t len1, len2; @@ -1072,7 +1072,6 @@ static int f_path_compare(lua_State *L) { size_t offset = 0, i, j; for (i = 0; i < len1 && i < len2; i++) { if (path1[i] != path2[i]) break; - if (isdigit(path1[i])) break; if (path1[i] == PATHSEP) { offset = i + 1; }