From ac0dba18de16c6027d25fe505bdabfb0ef3f1516 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Mon, 1 Mar 2021 14:57:28 +0100 Subject: [PATCH] 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 --- data/core/commands/core.lua | 20 ++++-- data/core/init.lua | 101 ++++++++++++++-------------- data/core/statusview.lua | 3 +- data/plugins/treeview.lua | 47 +++++++++---- doc/notes-project-implementation.md | 42 ++++++++++++ 5 files changed, 144 insertions(+), 69 deletions(-) create mode 100644 doc/notes-project-implementation.md diff --git a/data/core/commands/core.lua b/data/core/commands/core.lua index 18b76bc9..d818c391 100644 --- a/data/core/commands/core.lua +++ b/data/core/commands/core.lua @@ -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) diff --git a/data/core/init.lua b/data/core/init.lua index f008004c..8f0e8f53 100644 --- a/data/core/init.lua +++ b/data/core/init.lua @@ -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 diff --git a/data/core/statusview.lua b/data/core/statusview.lua index 58421c31..168ff6d9 100644 --- a/data/core/statusview.lua +++ b/data/core/statusview.lua @@ -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 diff --git a/data/plugins/treeview.lua b/data/plugins/treeview.lua index 73f4708c..bc88fdaf 100644 --- a/data/plugins/treeview.lua +++ b/data/plugins/treeview.lua @@ -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 diff --git a/doc/notes-project-implementation.md b/doc/notes-project-implementation.md new file mode 100644 index 00000000..3b52f0f1 --- /dev/null +++ b/doc/notes-project-implementation.md @@ -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.