diff --git a/.gitignore b/.gitignore index 59cabbb5..ffbfd6ac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +build* .build* +*.zip +.lite-debug.log +subprojects/lua subprojects/libagg sybprojects/lua diff --git a/data/core/commands/core.lua b/data/core/commands/core.lua index dbe08a41..870a2117 100644 --- a/data/core/commands/core.lua +++ b/data/core/commands/core.lua @@ -55,17 +55,30 @@ command.add(nil, { end, ["core:find-file"] = function() + local files = {} + for _, item in pairs(core.project_files) do + if item.type == "file" then + table.insert(files, item.filename) + end + end core.command_view:enter("Open File From Project", function(text, item) text = item and item.text or text core.root_view:open_doc(core.open_doc(text)) end, function(text) - local files = {} - for _, item in pairs(core.project_files) do - if item.type == "file" then - table.insert(files, item.filename) + if text == "" then + local recent_files = {} + for i = 2, #core.visited_files do + table.insert(recent_files, core.visited_files[i]) end + table.insert(recent_files, core.visited_files[1]) + local other_files = common.fuzzy_match(files, "") + for i = 1, #other_files do + table.insert(recent_files, other_files[i]) + end + return recent_files + else + return common.fuzzy_match(files, text) end - return common.fuzzy_match(files, text) end) end, diff --git a/data/core/commands/doc.lua b/data/core/commands/doc.lua index 0a4ee42c..a877225d 100644 --- a/data/core/commands/doc.lua +++ b/data/core/commands/doc.lua @@ -26,6 +26,10 @@ end local function insert_at_start_of_selected_lines(text, skip_empty) local line1, col1, line2, col2, swap = doc():get_selection(true) + if line2 > line1 and col2 == 1 then + line2 = line2 - 1 + col2 = #doc().lines[line2] + end for line = line1, line2 do local line_text = doc().lines[line] if (not skip_empty or line_text:find("%S")) then diff --git a/data/core/config.lua b/data/core/config.lua index a9f106f6..4f58f825 100644 --- a/data/core/config.lua +++ b/data/core/config.lua @@ -16,5 +16,7 @@ config.line_height = 1.2 config.indent_size = 2 config.tab_type = "soft" config.line_limit = 80 +config.max_symbols = 2000 +config.max_project_files = 2000 return config diff --git a/data/core/init.lua b/data/core/init.lua index fe74b344..5d023055 100644 --- a/data/core/init.lua +++ b/data/core/init.lua @@ -34,6 +34,8 @@ local function project_scan_thread() local all = system.list_dir(path) or {} local dirs, files = {}, {} + local entries_count = 0 + local max_entries = config.max_project_files for _, file in ipairs(all) do if not common.match_pattern(file, config.ignore_files) then local file = (path ~= "." and path .. PATHSEP or "") .. file @@ -41,6 +43,8 @@ local function project_scan_thread() if info and info.size < size_limit then info.filename = file table.insert(info.type == "dir" and dirs or files, info) + entries_count = entries_count + 1 + if entries_count > max_entries then break end end end end @@ -48,7 +52,10 @@ local function project_scan_thread() table.sort(dirs, compare_file) for _, f in ipairs(dirs) do table.insert(t, f) - get_files(f.filename, t) + if entries_count <= max_entries then + local subdir_t, subdir_count = get_files(f.filename, t) + entries_count = entries_count + subdir_count + end end table.sort(files, compare_file) @@ -56,14 +63,19 @@ local function project_scan_thread() table.insert(t, f) end - return t + return t, entries_count end while true do -- get project files and replace previous table if the new table is -- different - local t = get_files(".") + local t, entries_count = get_files(".") if diff_files(core.project_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.") + end core.project_files = t core.redraw = true end @@ -102,6 +114,7 @@ function core.init() core.threads = setmetatable({}, { __mode = "k" }) core.project_files = {} core.redraw = true + core.visited_files = {} core.root_view = RootView() core.command_view = CommandView() @@ -213,9 +226,23 @@ function core.reload_module(name) end +function core.set_visited(filename) + for i = 1, #core.visited_files do + if core.visited_files[i] == filename then + table.remove(core.visited_files, i) + break + end + end + table.insert(core.visited_files, 1, filename) +end + + function core.set_active_view(view) assert(view, "Tried to set active view to nil") if view ~= core.active_view then + if view.doc and view.doc.filename then + core.set_visited(view.doc.filename) + end core.last_active_view = core.active_view core.active_view = view end @@ -450,12 +477,20 @@ end) function core.run() + local idle_iterations = 0 while true do core.frame_start = system.get_time() local did_redraw = core.step() local need_more_work = run_threads() if not did_redraw and not need_more_work then - system.wait_event() + idle_iterations = idle_iterations + 1 + -- do not wait of events at idle_iterations = 1 to give a chance at core.step to run + -- and set "redraw" flag. + if idle_iterations > 1 then + system.wait_event() + end + else + idle_iterations = 0 end local elapsed = system.get_time() - core.frame_start system.sleep(math.max(0, 1 / config.fps - elapsed)) diff --git a/data/core/rootview.lua b/data/core/rootview.lua index 389525f6..8bcc03da 100644 --- a/data/core/rootview.lua +++ b/data/core/rootview.lua @@ -396,14 +396,33 @@ function RootView:get_active_node() return self.root_node:get_node_for_view(core.active_view) end +-- Get un unlocked node with at least one view. +local function get_node_unlocked(node) + if not node.locked and #node.views > 0 then + return node + end + if node.type ~= "leaf" then + local a = get_node_unlocked(node.a) + if a then return a end + return get_node_unlocked(node.b) + end +end + +function RootView:get_document_view() + local node = get_node_unlocked(self.root_node) + if node then + return node.views[1] + end +end function RootView:open_doc(doc) local node = self:get_active_node() - if node.locked and core.last_active_view then - core.set_active_view(core.last_active_view) + if node.locked then + local default_view = self:get_document_view() + assert(default_view, "Cannot find an unlocked node to open the document.") + core.set_active_view(default_view) node = self:get_active_node() end - assert(not node.locked, "Cannot open doc on locked node") for i, view in ipairs(node.views) do if view.doc == doc then node:set_active_view(node.views[i]) diff --git a/data/plugins/autocomplete.lua b/data/plugins/autocomplete.lua index 79e45133..7a43fd17 100644 --- a/data/plugins/autocomplete.lua +++ b/data/plugins/autocomplete.lua @@ -25,16 +25,28 @@ function autocomplete.add(t) autocomplete.map[t.name] = { files = t.files or ".*", items = items } end +local max_symbols = config.max_symbols or 2000 core.add_thread(function() local cache = setmetatable({}, { __mode = "k" }) local function get_symbols(doc) + if doc.disable_symbols then return {} end local i = 1 local s = {} + local symbols_count = 0 while i < #doc.lines do for sym in doc.lines[i]:gmatch(config.symbol_pattern) do - s[sym] = true + if not s[sym] then + symbols_count = symbols_count + 1 + if symbols_count > max_symbols then + s = nil + doc.disable_symbols = true + collectgarbage('collect') + return {} + end + s[sym] = true + end end i = i + 1 if i % 100 == 0 then coroutine.yield() end