WIP implementation of project-based schema

Roughly works but need more work and polishing. The workspace plugin
is temporarily disable waiting to be fixed.

Now the application does no longer 'chdir' into the project directory
and we removed the concept of project's directory (core.project_dir)
and project's files (core.project_files). Instead we have always a
project that can contain zero, one or many directories or files.
No directory is special within a project, there is no longer a concept
of project's directory.

WIP adapting open-file command to open a directory

Crash when adding a file into the project
This commit is contained in:
Francesco Abbate 2021-03-01 14:57:28 +01:00
parent e8fd785227
commit 0a53425381
5 changed files with 141 additions and 69 deletions

View File

@ -98,9 +98,20 @@ command.add(nil, {
core.command_view:set_text(text) core.command_view:set_text(text)
end end
end end
core.command_view:enter("Open File", function(text) core.command_view:enter("Open File", function(text, item)
local filename = system.absolute_path(common.home_expand(text)) local filename = common.home_expand(item and item.text or text)
core.root_view:open_doc(core.open_doc(filename)) local info = system.get_file_info(filename)
print('file', filename, common.serialize(info))
if info then
if info.type == "file" then
core.add_project_file(filename)
print('done add_project_file')
core.root_view:open_doc(core.open_doc(filename))
print('done open_doc')
else
core.add_project_directory(filename)
end
end
end, function (text) end, function (text)
return common.home_encode_list(common.path_suggest(common.home_expand(text))) return common.home_encode_list(common.path_suggest(common.home_expand(text)))
end, nil, function(text) end, nil, function(text)
@ -172,8 +183,8 @@ command.add(nil, {
end, end,
["core:add-directory"] = function() ["core:add-directory"] = function()
core.command_view:enter("Add Directory", function(text) core.command_view:enter("Add Directory", function(text, item)
text = common.home_expand(text) text = common.home_expand(item and item.text or text)
local path_stat, err = system.get_file_info(text) local path_stat, err = system.get_file_info(text)
if not path_stat then if not path_stat then
core.error("cannot open %q: %s", text, err) core.error("cannot open %q: %s", text, err)

View File

@ -60,28 +60,14 @@ function core.reschedule_project_scan()
end end
function core.set_project_dir(new_dir, change_project_fn)
local chdir_ok = pcall(system.chdir, new_dir)
if chdir_ok then
if change_project_fn then change_project_fn() end
core.project_dir = common.normalize_path(new_dir)
core.project_directories = {}
core.add_project_directory(new_dir)
core.project_files = {}
core.project_files_limit = false
core.reschedule_project_scan()
return true
end
return false
end
function core.open_folder_project(dir_path_abs) function core.open_folder_project(dir_path_abs)
if core.set_project_dir(dir_path_abs, core.on_quit_project) then -- if core.set_project_dir(dir_path_abs, core.on_quit_project) then
core.root_view:close_all_docviews() core.root_view:close_all_docviews()
update_recents_project("add", dir_path_abs) core.project_entries = {}
core.on_enter_project(dir_path_abs) -- FIXME: check stat info to verify is a directory
end core.add_project_directory(dir_path_abs)
update_recents_project("add", dir_path_abs)
-- core.on_enter_project(dir_path_abs)
end end
@ -162,23 +148,21 @@ local function project_scan_thread()
-- get project files and replace previous table if the new table is -- get project files and replace previous table if the new table is
-- different -- different
local i = 1 local i = 1
while not core.project_files_limit and i <= #core.project_directories do while not core.project_files_limit and i <= #core.project_entries do
local dir = core.project_directories[i] local dir = core.project_entries[i]
local t, entries_count = get_directory_files(dir.name, "", {}, true) if dir.item.type == 'dir' then
if diff_files(dir.files, t) then local t, entries_count = get_directory_files(dir.name, "", {}, true)
if entries_count > config.max_project_files then if diff_files(dir.files, t) then
core.project_files_limit = true if entries_count > config.max_project_files then
core.status_view:show_message("!", style.accent, core.project_files_limit = true
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
dir.files = t
core.redraw = true
end end
dir.files = t
core.redraw = true
end
if dir.name == core.project_dir then
core.project_files = dir.files
end end
i = i + 1 i = i + 1
end end
@ -230,12 +214,12 @@ 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_entries[state.dir_index]
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_entries[state.dir_index]
end end
if not dir then return end if not dir then return end
return dir.name, dir.files[state.file_index] return dir.name, dir.files[state.file_index]
@ -259,8 +243,8 @@ end
function core.project_files_number() function core.project_files_number()
if not core.project_files_limit then 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_entries do
n = n + #core.project_directories[i].files n = n + #core.project_entries[i].files
end end
return n return n
end end
@ -372,12 +356,24 @@ function core.load_user_directory()
end end
function core.add_project_file(path)
path = normalize_path(path)
table.insert(core.project_entries, {
-- type = 'file',
name = path,
item = {filename = common.basename(path), type = "file", topdir = true},
files = {path}
})
end
function core.add_project_directory(path) function core.add_project_directory(path)
-- top directories has a file-like "item" but the item.filename -- top directories has a file-like "item" but the item.filename
-- will be simply the name of the directory, without its path. -- will be simply the name of the directory, without its path.
-- The field item.topdir will identify it as a top level directory. -- The field item.topdir will identify it as a top level directory.
path = common.normalize_path(path) path = common.normalize_path(path)
table.insert(core.project_directories, { table.insert(core.project_entries, {
-- type = 'dir',
name = path, name = path,
item = {filename = common.basename(path), type = "dir", topdir = true}, item = {filename = common.basename(path), type = "dir", topdir = true},
files = {} files = {}
@ -385,12 +381,12 @@ function core.add_project_directory(path)
end end
function core.remove_project_directory(path) function core.remove_project_entry(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_entries do
local dir = core.project_directories[i] local dir = core.project_entries[i]
if dir.name == path then if dir.name == path then
table.remove(core.project_directories, i) table.remove(core.project_entries, i)
return true return true
end end
end end
@ -473,12 +469,18 @@ function core.init()
core.log_items = {} core.log_items = {}
core.docs = {} core.docs = {}
core.window_mode = "normal" core.window_mode = "normal"
core.project_entries = {}
core.threads = setmetatable({}, { __mode = "k" }) core.threads = setmetatable({}, { __mode = "k" })
core.blink_start = system.get_time() core.blink_start = system.get_time()
core.blink_timer = core.blink_start core.blink_timer = core.blink_start
local project_dir_abs = system.absolute_path(project_dir) local project_dir_abs = system.absolute_path(project_dir)
local set_project_ok = project_dir_abs and core.set_project_dir(project_dir_abs) if project_dir_abs then
core.add_project_directory(project_dir_abs)
update_recents_project("add", project_dir_abs)
end
-- FIXME: below, check if project_dir_abs is ok as a project directory
local set_project_ok = project_dir_abs --and core.open_folder_project(project_dir_abs) --core.set_project_dir(project_dir_abs)
if set_project_ok then if set_project_ok then
if project_dir_explicit then if project_dir_explicit then
update_recents_project("add", project_dir_abs) update_recents_project("add", project_dir_abs)
@ -487,11 +489,6 @@ function core.init()
if not project_dir_explicit then if not project_dir_explicit then
update_recents_project("remove", project_dir) update_recents_project("remove", project_dir)
end end
project_dir_abs = system.absolute_path(".")
if not core.set_project_dir(project_dir_abs) then
system.show_fatal_error("Lite XL internal error", "cannot set project directory to cwd")
os.exit(1)
end
end end
core.redraw = true core.redraw = true

View File

@ -138,7 +138,8 @@ function StatusView:get_items()
style.icon_font, "g", style.icon_font, "g",
style.font, style.dim, self.separator2, style.font, style.dim, self.separator2,
#core.docs, style.text, " / ", #core.docs, style.text, " / ",
#core.project_files, " files" "(NYI) files"
--- #core.project_files, " files"
} }
end end

View File

@ -64,19 +64,27 @@ function TreeView:get_cached(item, dirname)
local t = dir_cache[cache_name] local t = dir_cache[cache_name]
if not t then if not t then
t = {} t = {}
local basename = common.basename(item.filename) if item.type == 'file' and item.topdir then
if item.topdir then t.filename = item.filename
t.filename = basename
t.expanded = true
t.depth = 0 t.depth = 0
t.abs_filename = dirname t.abs_filename = dirname
t.name = item.filename
t.type = item.type
else else
t.filename = item.filename local basename = common.basename(item.filename)
t.depth = get_depth(item.filename) if item.topdir then
t.abs_filename = dirname .. PATHSEP .. item.filename t.filename = basename
t.expanded = true
t.depth = 0
t.abs_filename = dirname
else
t.filename = item.filename
t.depth = get_depth(item.filename)
t.abs_filename = dirname .. PATHSEP .. item.filename
end
t.name = basename
t.type = item.type
end end
t.name = basename
t.type = item.type
dir_cache[cache_name] = t dir_cache[cache_name] = t
end end
return t return t
@ -102,8 +110,8 @@ end
function TreeView:check_cache() function TreeView:check_cache()
-- invalidate cache's skip values if project_files has changed -- invalidate cache's skip values if project_files has changed
for i = 1, #core.project_directories do for i = 1, #core.project_entries do
local dir = core.project_directories[i] local dir = core.project_entries[i]
local last_files = self.last[dir.name] local last_files = self.last[dir.name]
if not last_files then if not last_files then
self.last[dir.name] = dir.files self.last[dir.name] = dir.files
@ -126,10 +134,19 @@ function TreeView:each_item()
local w = self.size.x local w = self.size.x
local h = self:get_item_height() local h = self:get_item_height()
for k = 1, #core.project_directories do for k = 1, #core.project_entries do
local dir = core.project_directories[k] local dir = core.project_entries[k]
if dir.item.type == "file" and dir.item.topdir then
print('dir', common.serialize(dir))
end
local dir_cached = self:get_cached(dir.item, dir.name) local dir_cached = self:get_cached(dir.item, dir.name)
if dir.item.type == "file" and dir.item.topdir then
print('cache', common.serialize(dir_cached))
end
coroutine.yield(dir_cached, ox, y, w, h) coroutine.yield(dir_cached, ox, y, w, h)
if dir.item.type == "file" and dir.item.topdir then
print('file topdir yielded')
end
count_lines = count_lines + 1 count_lines = count_lines + 1
y = y + h y = y + h
local i = 1 local i = 1
@ -155,6 +172,9 @@ function TreeView:each_item()
end end
end end
end -- while files end -- while files
if dir.item.type == "file" and dir.item.topdir then
print('loop over files terminated')
end
end -- for directories end -- for directories
self.count_lines = count_lines self.count_lines = count_lines
end) end)
@ -323,6 +343,7 @@ function TreeView:draw()
-- text -- text
x = x + spacing x = x + spacing
print('item.name', item.name)
x = common.draw_text(style.font, color, item.name, nil, x, y, 0, h) x = common.draw_text(style.font, color, item.name, nil, x, y, 0, h)
end end

View File

@ -0,0 +1,42 @@
`core.project_directories` => `core.project_entries`
- use a new `type` field to indicate it is a directory or a file
`core.{project_dir,project_files}` => removed
`core.set_project_dir` => removed
`core.on_enter_project` => decide what to do
No longer use `chdir` command.
## New functions
`core.add_project_file`
## Modified functions
- `core.add_project_directory`
- `project_files_iter` local function in `core/init.lua`
Function `remove_project_directory` is renamed to `remove_project_entry`.
## Broken
workspace plugin is not working for the moment.
Number of files show in statusview.
## To be done
- When using "core:find-file" do not display the full path of the file
- FIX the workspace plugin
- FIX number of files display in statusview
- Add a function to add a file into the project
- Add logic to do not show treeview if it contains only a single file
- Modify "core:open-file" to accept a directory
- Modify "core:open-file" to accept a non-existing file name (new file)
## Misc observations
When performing adding directory, pressing enter does not use the item => to be fixed.
The function `system.chdir` is no longer used and could be removed, in theory.