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 c46781dbed
commit 7aca4e6ba2
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
@ -109,8 +99,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
@ -159,48 +149,47 @@ 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) -- FIXME: change the name with core.scan_project_folder
if #a ~= #b then return true end function core.project_scan_topdir(index)
for i, v in ipairs(a) do local dir = core.project_directories[index]
if b[i].filename ~= v.filename local t, entries_count = get_directory_files(dir.name, "", {}, true)
or b[i].modified ~= v.modified then if entries_count > config.max_project_files then
return true dir.files_limit = true
end if core.status_view then -- FIXME
core.status_view:show_message("!", style.accent,
"Too many files in project directory: stopped reading at "..
config.max_project_files.." files. For more information see "..
"usage.md at github.com/franko/lite-xl."
)
end end
end end
dir.files = t
while true do if dir.name == core.project_dir then
-- get project files and replace previous table if the new table is core.project_files = dir.files
-- different
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)
if diff_files(dir.files, t) then
if entries_count > config.max_project_files then
core.project_files_limit = true
core.status_view:show_message("!", style.accent,
"Too many files in project directory: stopped reading at "..
config.max_project_files.." files. For more information see "..
"usage.md at github.com/franko/lite-xl."
)
end
dir.files = t
core.redraw = true
end
if dir.name == core.project_dir then
core.project_files = dir.files
end
i = i + 1
end
-- wait for next scan
coroutine.yield(config.project_scan_rate)
end end
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)
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
function core.is_project_folder(dirname) function core.is_project_folder(dirname)
for _, dir in ipairs(core.project_directories) do for _, dir in ipairs(core.project_directories) do
if dir.name == dirname then if dir.name == dirname then
@ -230,7 +219,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 {}
@ -253,39 +242,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]
state.file_index = state.file_index + 1 if state.co then
while dir and state.file_index > #dir.files do local ok, name, file = coroutine.resume(state.co, dir.name, "")
state.dir_index = state.dir_index + 1 if ok and name then
state.file_index = 1 return name, file
dir = core.project_directories[state.dir_index] 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
while dir and state.file_index > #dir.files do
state.dir_index = state.dir_index + 1
state.file_index = 1
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 local state = { dir_index = 1, file_index = 0 }
return coroutine.wrap(function() return project_files_iter, state
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 }
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
return n
end end
return n
end end
@ -444,22 +440,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
@ -595,7 +575,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.