WIP: add correct binary search for removed file

Use a C function to compare nested files in project tree to enable
binary search of a file across the project files tree.
This commit is contained in:
Francesco Abbate 2021-07-13 22:23:52 +02:00
parent b2affddf32
commit 79b65014a5
2 changed files with 62 additions and 14 deletions

View File

@ -106,6 +106,18 @@ local function compare_file(a, b)
return a.filename < b.filename
end
-- compute a file's info entry completed with "filename" to be used
-- in project scan or falsy if it shouldn't appear in the list.
local function get_project_file_info(root, file, size_limit)
local info = system.get_file_info(root .. file)
if info then
info.filename = strip_leading_path(file)
end
return info and info.size < size_limit and info
end
-- "root" will by an absolute path without trailing '/'
-- "path" will be a path starting with '/' and without trailing '/'
-- or the empty string.
@ -124,10 +136,8 @@ local function get_directory_files(root, path, t, recursive, begin_hook)
local max_entries = config.max_project_files
for _, file in ipairs(all) do
if not common.match_pattern(file, config.ignore_files) then
local file = path .. PATHSEP .. file
local info = system.get_file_info(root .. file)
if info and info.size < size_limit then
info.filename = strip_leading_path(file)
local info = get_project_file_info(root, path .. PATHSEP .. file, size_limit)
if info then
table.insert(info.type == "dir" and dirs or files, info)
entries_count = entries_count + 1
if recursive and entries_count > max_entries then return nil, entries_count end
@ -283,20 +293,18 @@ function core.project_files_number()
end
local function file_search(files, filepath)
local function file_search(files, fileinfo)
local inf, sup = 1, #files
if false then -- FIXME: skipping binary search / it is broken
while sup - inf > 8 do
local curr = math.floor((inf + sup) / 2)
if filepath < files[curr].filename then
if system.path_compare(fileinfo.filename, fileinfo.type, files[curr].filename, files[curr].type) then
sup = curr - 1
else
inf = curr
end
end
end
for i = inf, sup do
if files[i].filename == filepath then
if files[i].filename == fileinfo.filename then
return i
end
end
@ -310,12 +318,18 @@ local function project_scan_remove_file(watch_id, filepath)
project_dir_entry = core.project_directories[i]
end
end
if not project_dir_entry then return end
print("LOOKING for", filepath, " in", project_dir_entry and project_dir_entry.name)
local index = project_dir_entry and file_search(project_dir_entry.files, filepath)
if index then
print("FOUND", filepath, " at index", index)
table.remove(files, index)
project_dir_entry.is_dirty = true
local fileinfo = { filename = filepath }
for _, filetype in ipairs {"dir", "file"} do
fileinfo.type = filetype
local index = file_search(project_dir_entry.files, fileinfo)
if index then
print("FOUND", filepath, " at index", index)
table.remove(project_dir_entry.files, index)
project_dir_entry.is_dirty = true
return
end
end
end

View File

@ -663,6 +663,39 @@ static int f_watch_dir(lua_State *L) {
return 1;
}
#ifdef _WIN32
#define PATHSEP '\\'
#else
#define PATHSEP '/'
#endif
static int f_path_compare(lua_State *L) {
const char *path1 = luaL_checkstring(L, 1);
const char *type1_s = luaL_checkstring(L, 2);
const char *path2 = luaL_checkstring(L, 3);
const char *type2_s = luaL_checkstring(L, 4);
const int len1 = strlen(path1), len2 = strlen(path2);
int type1 = strcmp(type1_s, "dir") != 0;
int type2 = strcmp(type2_s, "dir") != 0;
int i;
for (i = 0; i < len1 && i < len2; i++) {
if (path1[i] != path2[i]) break;
}
if (strchr(path1 + i, PATHSEP)) {
type1 = 0;
}
if (strchr(path2 + i, PATHSEP)) {
type2 = 0;
}
if (type1 != type2) {
lua_pushboolean(L, type1 < type2);
return 1;
}
lua_pushboolean(L, strcmp(path1 + i, path2 + i) < 0);
return 1;
}
static const luaL_Reg lib[] = {
{ "poll_event", f_poll_event },
@ -691,6 +724,7 @@ static const luaL_Reg lib[] = {
{ "fuzzy_match", f_fuzzy_match },
{ "set_window_opacity", f_set_window_opacity },
{ "watch_dir", f_watch_dir },
{ "path_compare", f_path_compare },
{ NULL, NULL }
};