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 ea3a7e81be
commit ac0dba18de
5 changed files with 144 additions and 69 deletions

View File

@ -90,8 +90,20 @@ command.add(nil, {
if view.doc and view.doc.abs_filename then
core.command_view:set_text(common.home_encode(view.doc.abs_filename))
end
core.command_view:enter("Open File", function(text)
core.root_view:open_doc(core.open_doc(common.home_expand(text)))
core.command_view:enter("Open File", function(text, item)
local filename = common.home_expand(item and item.text or text)
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)
return common.home_encode_list(common.path_suggest(common.home_expand(text)))
end, nil, function(text)
@ -163,8 +175,8 @@ command.add(nil, {
end,
["core:add-directory"] = function()
core.command_view:enter("Add Directory", function(text)
text = common.home_expand(text)
core.command_view:enter("Add Directory", function(text, item)
text = common.home_expand(item and item.text or text)
local path_stat, err = system.get_file_info(text)
if not path_stat then
core.error("cannot open %q: %s", text, err)

View File

@ -58,27 +58,14 @@ function core.reschedule_project_scan()
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.reschedule_project_scan()
return true
end
return false
end
function core.open_folder_project(dir_path_abs)
if core.set_project_dir(dir_path_abs, core.on_quit_project) then
core.root_view:close_all_docviews()
update_recents_project("add", dir_path_abs)
core.on_enter_project(dir_path_abs)
end
-- if core.set_project_dir(dir_path_abs, core.on_quit_project) then
core.root_view:close_all_docviews()
core.project_entries = {}
-- FIXME: check stat info to verify is a directory
core.add_project_directory(dir_path_abs)
update_recents_project("add", dir_path_abs)
-- core.on_enter_project(dir_path_abs)
end
@ -158,23 +145,22 @@ local function project_scan_thread()
while true do
-- get project files and replace previous table if the new table is
-- different
for i = 1, #core.project_directories do
local dir = core.project_directories[i]
local t, entries_count = get_files(dir.name, "")
if diff_files(dir.files, t) then
if entries_count > config.max_project_files then
core.status_view:show_message("!", style.accent,
"Too many files in project directory: stopping reading at "..
config.max_project_files.." files according to config.max_project_files. "..
"Either tweak this variable, or ignore certain files/directories by "..
"using the config.ignore_files variable in your user plugin or "..
"project config.")
for i = 1, #core.project_entries do
local dir = core.project_entries[i]
if dir.item.type == 'dir' then
local t, entries_count = get_files(dir.name, "")
if diff_files(dir.files, t) then
if entries_count > config.max_project_files then
core.status_view:show_message("!", style.accent,
"Too many files in project directory: stopping reading at "..
config.max_project_files.." files according to config.max_project_files. "..
"Either tweak this variable, or ignore certain files/directories by "..
"using the config.ignore_files variable in your user plugin or "..
"project config.")
end
dir.files = t
core.redraw = true
end
dir.files = t
core.redraw = true
end
if dir.name == core.project_dir then
core.project_files = dir.files
end
end
@ -185,12 +171,12 @@ end
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
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]
dir = core.project_entries[state.dir_index]
end
if not dir then return end
return dir.name, dir.files[state.file_index]
@ -205,8 +191,8 @@ end
function core.project_files_number()
local n = 0
for i = 1, #core.project_directories do
n = n + #core.project_directories[i].files
for i = 1, #core.project_entries do
n = n + #core.project_entries[i].files
end
return n
end
@ -317,12 +303,24 @@ function core.load_user_directory()
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)
-- 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)
table.insert(core.project_directories, {
table.insert(core.project_entries, {
-- type = 'dir',
name = path,
item = {filename = common.basename(path), type = "dir", topdir = true},
files = {}
@ -330,12 +328,12 @@ function core.add_project_directory(path)
end
function core.remove_project_directory(path)
function core.remove_project_entry(path)
-- skip the fist directory because it is the project's directory
for i = 2, #core.project_directories do
local dir = core.project_directories[i]
for i = 2, #core.project_entries do
local dir = core.project_entries[i]
if dir.name == path then
table.remove(core.project_directories, i)
table.remove(core.project_entries, i)
return true
end
end
@ -402,12 +400,18 @@ function core.init()
core.log_items = {}
core.docs = {}
core.window_mode = "normal"
core.project_entries = {}
core.threads = setmetatable({}, { __mode = "k" })
core.blink_start = system.get_time()
core.blink_timer = core.blink_start
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 project_dir_explicit then
update_recents_project("add", project_dir_abs)
@ -416,11 +420,6 @@ function core.init()
if not project_dir_explicit then
update_recents_project("remove", project_dir)
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
core.redraw = true

View File

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

View File

@ -64,19 +64,27 @@ function TreeView:get_cached(item, dirname)
local t = dir_cache[cache_name]
if not t then
t = {}
local basename = common.basename(item.filename)
if item.topdir then
t.filename = basename
t.expanded = true
if item.type == 'file' and item.topdir then
t.filename = item.filename
t.depth = 0
t.abs_filename = dirname
t.name = item.filename
t.type = item.type
else
t.filename = item.filename
t.depth = get_depth(item.filename)
t.abs_filename = dirname .. PATHSEP .. item.filename
local basename = common.basename(item.filename)
if item.topdir then
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
t.name = basename
t.type = item.type
dir_cache[cache_name] = t
end
return t
@ -95,8 +103,8 @@ end
function TreeView:check_cache()
-- invalidate cache's skip values if project_files has changed
for i = 1, #core.project_directories do
local dir = core.project_directories[i]
for i = 1, #core.project_entries do
local dir = core.project_entries[i]
local last_files = self.last[dir.name]
if not last_files then
self.last[dir.name] = dir.files
@ -121,10 +129,19 @@ function TreeView:each_item()
local w = self.size.x
local h = self:get_item_height()
for k = 1, #core.project_directories do
local dir = core.project_directories[k]
for k = 1, #core.project_entries do
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)
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)
if dir.item.type == "file" and dir.item.topdir then
print('file topdir yielded')
end
count_lines = count_lines + 1
y = y + h
local i = 1
@ -150,6 +167,9 @@ function TreeView:each_item()
end
end
end -- while files
if dir.item.type == "file" and dir.item.topdir then
print('loop over files terminated')
end
end -- for directories
self.count_lines = count_lines
end)
@ -310,6 +330,7 @@ function TreeView:draw()
-- text
x = x + spacing
print('item.name', item.name)
x = common.draw_text(style.font, color, item.name, nil, x, y, 0, h)
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.