Remove the project scan thread

Since the directory monitoring is now basically working we remove the
project scan thread periodically scanning the project directory.

Each project's directory is scanned only once at the beginning when
calling the function `core.add_project_directory` and is updated
incrementally when directory change events are treated.

The config variable `project_scan_rate` is removed as well as the
function `core.reschedule_project_scan`.
This commit is contained in:
Francesco Abbate 2021-07-14 22:57:37 +02:00
parent 09d2c0a325
commit 7ee00c3317
6 changed files with 99 additions and 92 deletions

View File

@ -191,8 +191,6 @@ command.add(nil, {
return return
end end
core.add_project_directory(system.absolute_path(text)) core.add_project_directory(system.absolute_path(text))
-- TODO: add the name of directory to prioritize
core.reschedule_project_scan()
end, suggest_directory) end, suggest_directory)
end, end,

View File

@ -1,6 +1,5 @@
local config = {} local config = {}
config.project_scan_rate = 5
config.fps = 60 config.fps = 60
config.max_log_items = 80 config.max_log_items = 80
config.message_timeout = 5 config.message_timeout = 5

View File

@ -52,13 +52,6 @@ local function update_recents_project(action, dir_path_abs)
end end
function core.reschedule_project_scan()
if core.project_scan_thread_id then
core.threads[core.project_scan_thread_id].wake = 0
end
end
function core.set_project_dir(new_dir, change_project_fn) function core.set_project_dir(new_dir, change_project_fn)
local chdir_ok = pcall(system.chdir, new_dir) local chdir_ok = pcall(system.chdir, new_dir)
if chdir_ok then if chdir_ok then
@ -66,9 +59,6 @@ function core.set_project_dir(new_dir, change_project_fn)
core.project_dir = common.normalize_path(new_dir) core.project_dir = common.normalize_path(new_dir)
core.project_directories = {} core.project_directories = {}
core.add_project_directory(new_dir) core.add_project_directory(new_dir)
core.project_files = {}
core.project_files_limit = false
core.reschedule_project_scan()
return true return true
end end
return false return false
@ -106,8 +96,8 @@ local function get_project_file_info(root, file, size_limit)
local info = system.get_file_info(root .. file) local info = system.get_file_info(root .. file)
if info then if info then
info.filename = strip_leading_path(file) info.filename = strip_leading_path(file)
return info.size < size_limit and info
end end
return info and info.size < size_limit and info
end end
@ -156,45 +146,44 @@ local function get_directory_files(root, path, t, recursive, begin_hook)
return t, entries_count return t, entries_count
end end
local function project_scan_thread()
local function diff_files(a, b)
if #a ~= #b then return true end
for i, v in ipairs(a) do
if b[i].filename ~= v.filename
or b[i].modified ~= v.modified then
return true
end
end
end
while true do -- FIXME: change the name with core.scan_project_folder
-- get project files and replace previous table if the new table is function core.project_scan_topdir(index)
-- different local dir = core.project_directories[index]
local i = 1
while not core.project_files_limit and i <= #core.project_directories do
local dir = core.project_directories[i]
local t, entries_count = get_directory_files(dir.name, "", {}, true) local t, entries_count = get_directory_files(dir.name, "", {}, true)
if diff_files(dir.files, t) then
if entries_count > config.max_project_files then if entries_count > config.max_project_files then
core.project_files_limit = true dir.files_limit = true
if core.status_view then -- FIXME
core.status_view:show_message("!", style.accent, core.status_view:show_message("!", style.accent,
"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 github.com/franko/lite-xl." "usage.md at github.com/franko/lite-xl."
) )
end end
dir.files = t
core.redraw = true
end end
dir.files = t
if dir.name == core.project_dir then if dir.name == core.project_dir then
core.project_files = dir.files core.project_files = dir.files
end end
i = i + 1 end
end
-- wait for next scan
coroutine.yield(config.project_scan_rate) function core.add_project_directory(path)
end -- top directories has a file-like "item" but the item.filename
-- will be simply the name of the directory, without its path.
-- The field item.topdir will identify it as a top level directory.
path = common.normalize_path(path)
local watch_id = system.watch_dir(path)
print("DEBUG watch_id:", watch_id)
table.insert(core.project_directories, {
name = path,
item = {filename = common.basename(path), type = "dir", topdir = true},
files_limit = false,
is_dirty = true,
watch_id = watch_id,
})
core.project_scan_topdir(#core.project_directories)
core.redraw = true
end end
@ -227,7 +216,7 @@ function core.scan_project_folder(dirname, filename)
end end
end end
-- FIXME: rename this function
local function find_project_files_co(root, path) local function find_project_files_co(root, path)
local size_limit = config.file_size_limit * 10e5 local size_limit = config.file_size_limit * 10e5
local all = system.list_dir(root .. path) or {} local all = system.list_dir(root .. path) or {}
@ -250,39 +239,46 @@ end
local function project_files_iter(state) local function project_files_iter(state)
local dir = core.project_directories[state.dir_index] local dir = core.project_directories[state.dir_index]
if state.co then
local ok, name, file = coroutine.resume(state.co, dir.name, "")
if ok and name then
return name, file
else
state.co = false
state.file_index = 1
state.dir_index = state.dir_index + 1
dir = core.project_directories[state.dir_index]
end
else
state.file_index = state.file_index + 1 state.file_index = state.file_index + 1
while dir and state.file_index > #dir.files do while dir and state.file_index > #dir.files do
state.dir_index = state.dir_index + 1 state.dir_index = state.dir_index + 1
state.file_index = 1 state.file_index = 1
dir = core.project_directories[state.dir_index] dir = core.project_directories[state.dir_index]
end end
end
if not dir then return end if not dir then return end
if dir.files_limit then
state.co = coroutine.create(find_project_files_co)
return project_files_iter(state)
end
return dir.name, dir.files[state.file_index] return dir.name, dir.files[state.file_index]
end end
function core.get_project_files() function core.get_project_files()
if core.project_files_limit then
return coroutine.wrap(function()
for _, dir in ipairs(core.project_directories) do
find_project_files_co(dir.name, "")
end
end)
else
local state = { dir_index = 1, file_index = 0 } local state = { dir_index = 1, file_index = 0 }
return project_files_iter, state return project_files_iter, state
end
end end
function core.project_files_number() function core.project_files_number()
if not core.project_files_limit then
local n = 0 local n = 0
for i = 1, #core.project_directories do for i = 1, #core.project_directories do
if core.project_directories[i].files_limit then return end
n = n + #core.project_directories[i].files n = n + #core.project_directories[i].files
end end
return n return n
end
end end
@ -441,22 +437,6 @@ function core.load_user_directory()
end end
function core.add_project_directory(path)
-- top directories has a file-like "item" but the item.filename
-- will be simply the name of the directory, without its path.
-- The field item.topdir will identify it as a top level directory.
path = common.normalize_path(path)
local watch_id = system.watch_dir(path);
table.insert(core.project_directories, {
name = path,
item = {filename = common.basename(path), type = "dir", topdir = true},
files = {},
is_dirty = true,
watch_id = watch_id,
})
end
function core.remove_project_directory(path) function core.remove_project_directory(path)
-- skip the fist directory because it is the project's directory -- skip the fist directory because it is the project's directory
for i = 2, #core.project_directories do for i = 2, #core.project_directories do
@ -592,7 +572,6 @@ function core.init()
cur_node = cur_node:split("down", core.command_view, {y = true}) cur_node = cur_node:split("down", core.command_view, {y = true})
cur_node = cur_node:split("down", core.status_view, {y = true}) cur_node = cur_node:split("down", core.status_view, {y = true})
core.project_scan_thread_id = core.add_thread(project_scan_thread)
command.add_defaults() command.add_defaults()
local got_user_error = not core.load_user_directory() local got_user_error = not core.load_user_directory()
local plugins_success, plugins_refuse_list = core.load_plugins() local plugins_success, plugins_refuse_list = core.load_plugins()

View File

@ -3,9 +3,10 @@ local core = require "core"
local config = require "core.config" local config = require "core.config"
local Doc = require "core.doc" local Doc = require "core.doc"
local times = setmetatable({}, { __mode = "k" }) local times = setmetatable({}, { __mode = "k" })
local autoreload_scan_rate = 5
local function update_time(doc) local function update_time(doc)
local info = system.get_file_info(doc.filename) local info = system.get_file_info(doc.filename)
times[doc] = info.modified times[doc] = info.modified
@ -40,7 +41,7 @@ core.add_thread(function()
end end
-- wait for next scan -- wait for next scan
coroutine.yield(config.project_scan_rate) coroutine.yield(autoreload_scan_rate)
end end
end) end)

View File

@ -207,7 +207,6 @@ local function create_directory_in(item)
core.error("cannot create directory %q: %s", dirname, err) core.error("cannot create directory %q: %s", dirname, err)
end end
item.expanded = true item.expanded = true
core.reschedule_project_scan()
end) end)
end end

View File

@ -0,0 +1,31 @@
`core.scan_project_folder`:
scan a single folder, without recursion. Used when too many files.
`core.add_project_directory`:
Add a new top-level folder to the project.
`core.set_project_dir`:
Set the initial project directory.
`core.project_scan_thread`:
Should disappear now that we use dmon.
`core.project_scan_topdir`:
New function to scan a top level project folder.
`config.project_scan_rate`:
`core.project_scan_thread_id`:
`core.reschedule_project_scan`:
`core.project_files_limit`:
A eliminer.
`core.get_project_files`:
To be fixed. Use `find_project_files_co` for a single directory
In TreeView remove usage of self.last to detect new scan that changed the files list.