Merge pull request #236 from jgmdev/dev-sync
Merge latest master changes to dev branch
This commit is contained in:
commit
76f561a8b5
18
changelog.md
18
changelog.md
|
@ -1,10 +1,14 @@
|
||||||
Lite XL is following closely [rxi/lite](https://github.com/rxi/lite) but with some enhancements.
|
|
||||||
|
|
||||||
This files document the changes done in Lite XL for each release.
|
This files document the changes done in Lite XL for each release.
|
||||||
|
|
||||||
### next release
|
### 1.16.11
|
||||||
|
|
||||||
|
When opening directories with too many files lite-xl now keep diplaying files and directories in the treeview.
|
||||||
|
The application remains functional and the directories can be explored without using too much memory.
|
||||||
|
In this operating mode the files of the project are not indexed so the command "Core: Find File" will act as the "Core: Open File" command.
|
||||||
|
The "Project Search: Find" will work by searching all the files present in the project directory even if they are not indexed.
|
||||||
|
|
||||||
|
Implemented changing fonts per syntax group by @liquidev.
|
||||||
|
|
||||||
[#126](https://github.com/franko/lite-xl/issues/126): Implemented changing fonts per syntax group.
|
|
||||||
Example user module snippet that makes all comments italic:
|
Example user module snippet that makes all comments italic:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
|
@ -15,6 +19,12 @@ local italic = renderer.font.load("italic.ttf", 14)
|
||||||
style.syntax_fonts["comment"] = italic
|
style.syntax_fonts["comment"] = italic
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Improved indentation behavior by @adamharrison.
|
||||||
|
|
||||||
|
Fix bug with close button not working in borderless window mode.
|
||||||
|
|
||||||
|
Fix problem with normalization of filename for opened documents.
|
||||||
|
|
||||||
### 1.16.10
|
### 1.16.10
|
||||||
|
|
||||||
Improved syntax highlight system thanks to @liquidev and @adamharrison.
|
Improved syntax highlight system thanks to @liquidev and @adamharrison.
|
||||||
|
|
|
@ -66,6 +66,9 @@ command.add(nil, {
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["core:find-file"] = function()
|
["core:find-file"] = function()
|
||||||
|
if core.project_files_limit then
|
||||||
|
return command.perform "core:open-file"
|
||||||
|
end
|
||||||
local files = {}
|
local files = {}
|
||||||
for dir, item in core.get_project_files() do
|
for dir, item in core.get_project_files() do
|
||||||
if item.type == "file" then
|
if item.type == "file" then
|
||||||
|
|
|
@ -33,33 +33,6 @@ local function doc_multiline_selection(sort)
|
||||||
return line1, col1, line2, col2, swap
|
return line1, col1, line2, col2, swap
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function insert_at_start_of_selected_lines(text, skip_empty)
|
|
||||||
local line1, col1, line2, col2, swap = doc_multiline_selection(true)
|
|
||||||
for line = line1, line2 do
|
|
||||||
local line_text = doc().lines[line]
|
|
||||||
if (not skip_empty or line_text:find("%S")) then
|
|
||||||
doc():insert(line, 1, text)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
doc():set_selection(line1, col1 + #text, line2, col2 + #text, swap)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function remove_from_start_of_selected_lines(text, skip_empty)
|
|
||||||
local line1, col1, line2, col2, swap = doc_multiline_selection(true)
|
|
||||||
for line = line1, line2 do
|
|
||||||
local line_text = doc().lines[line]
|
|
||||||
if line_text:sub(1, #text) == text
|
|
||||||
and (not skip_empty or line_text:find("%S"))
|
|
||||||
then
|
|
||||||
doc():remove(line, 1, line, #text + 1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
doc():set_selection(line1, col1 - #text, line2, col2 - #text, swap)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function append_line_if_last_line(line)
|
local function append_line_if_last_line(line)
|
||||||
if line >= #doc().lines then
|
if line >= #doc().lines then
|
||||||
doc():insert(line, math.huge, "\n")
|
doc():insert(line, math.huge, "\n")
|
||||||
|
@ -107,7 +80,7 @@ end
|
||||||
-- and remove the appropriate amount of spaces (or a tab).
|
-- and remove the appropriate amount of spaces (or a tab).
|
||||||
local function indent_text(unindent)
|
local function indent_text(unindent)
|
||||||
local text = get_indent_string()
|
local text = get_indent_string()
|
||||||
local line1, col1, line2, col2, swap = doc():get_selection(true)
|
local line1, col1, line2, col2, swap = doc_multiline_selection(true)
|
||||||
local _, se = doc().lines[line1]:find("^[ \t]+")
|
local _, se = doc().lines[line1]:find("^[ \t]+")
|
||||||
local in_beginning_whitespace = col1 == 1 or (se and col1 <= se + 1)
|
local in_beginning_whitespace = col1 == 1 or (se and col1 <= se + 1)
|
||||||
if unindent or doc():has_selection() or in_beginning_whitespace then
|
if unindent or doc():has_selection() or in_beginning_whitespace then
|
||||||
|
@ -286,19 +259,31 @@ local commands = {
|
||||||
["doc:toggle-line-comments"] = function()
|
["doc:toggle-line-comments"] = function()
|
||||||
local comment = doc().syntax.comment
|
local comment = doc().syntax.comment
|
||||||
if not comment then return end
|
if not comment then return end
|
||||||
|
local indentation = get_indent_string()
|
||||||
local comment_text = comment .. " "
|
local comment_text = comment .. " "
|
||||||
local line1, _, line2 = doc():get_selection(true)
|
local line1, _, line2 = doc_multiline_selection(true)
|
||||||
local uncomment = true
|
local uncomment = true
|
||||||
|
local start_offset = math.huge
|
||||||
for line = line1, line2 do
|
for line = line1, line2 do
|
||||||
local text = doc().lines[line]
|
local text = doc().lines[line]
|
||||||
if text:find("%S") and text:find(comment_text, 1, true) ~= 1 then
|
local s = text:find("%S")
|
||||||
|
local cs, ce = text:find(comment_text, s, true)
|
||||||
|
if s and cs ~= s then
|
||||||
uncomment = false
|
uncomment = false
|
||||||
|
start_offset = math.min(start_offset, s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if uncomment then
|
for line = line1, line2 do
|
||||||
remove_from_start_of_selected_lines(comment_text, true)
|
local text = doc().lines[line]
|
||||||
else
|
local s = text:find("%S")
|
||||||
insert_at_start_of_selected_lines(comment_text, true)
|
if uncomment then
|
||||||
|
local cs, ce = text:find(comment_text, s, true)
|
||||||
|
if ce then
|
||||||
|
doc():remove(line, cs, line, ce + 1)
|
||||||
|
end
|
||||||
|
elseif s then
|
||||||
|
doc():insert(line, start_offset, comment_text)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
@ -346,9 +331,10 @@ local commands = {
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["doc:save-as"] = function()
|
["doc:save-as"] = function()
|
||||||
|
local last_doc = core.last_active_view and core.last_active_view.doc
|
||||||
if doc().filename then
|
if doc().filename then
|
||||||
core.command_view:set_text(doc().filename)
|
core.command_view:set_text(doc().filename)
|
||||||
elseif core.last_active_view and core.last_active_view.doc then
|
elseif last_doc and last_doc.filename then
|
||||||
local dirname, filename = core.last_active_view.doc.abs_filename:match("(.*)[/\\](.+)$")
|
local dirname, filename = core.last_active_view.doc.abs_filename:match("(.*)[/\\](.+)$")
|
||||||
core.command_view:set_text(core.normalize_to_project_dir(dirname) .. PATHSEP)
|
core.command_view:set_text(core.normalize_to_project_dir(dirname) .. PATHSEP)
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ local config = {}
|
||||||
config.project_scan_rate = 5
|
config.project_scan_rate = 5
|
||||||
config.fps = 60
|
config.fps = 60
|
||||||
config.max_log_items = 80
|
config.max_log_items = 80
|
||||||
config.message_timeout = 3
|
config.message_timeout = 5
|
||||||
config.mouse_wheel_scroll = 50 * SCALE
|
config.mouse_wheel_scroll = 50 * SCALE
|
||||||
config.file_size_limit = 10
|
config.file_size_limit = 10
|
||||||
config.ignore_files = "^%."
|
config.ignore_files = "^%."
|
||||||
|
|
|
@ -68,6 +68,7 @@ function core.set_project_dir(new_dir, change_project_fn)
|
||||||
core.project_directories = {}
|
core.project_directories = {}
|
||||||
core.add_project_directory(new_dir)
|
core.add_project_directory(new_dir)
|
||||||
core.project_files = {}
|
core.project_files = {}
|
||||||
|
core.project_files_limit = false
|
||||||
core.reschedule_project_scan()
|
core.reschedule_project_scan()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -95,6 +96,57 @@ local function strip_trailing_slash(filename)
|
||||||
return filename
|
return filename
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function compare_file(a, b)
|
||||||
|
return a.filename < b.filename
|
||||||
|
end
|
||||||
|
|
||||||
|
-- "root" will by an absolute path without trailing '/'
|
||||||
|
-- "path" will be a path starting with '/' and without trailing '/'
|
||||||
|
-- or the empty string.
|
||||||
|
-- It will identifies a sub-path within "root.
|
||||||
|
-- The current path location will therefore always be: root .. path.
|
||||||
|
-- When recursing "root" will always be the same, only "path" will change.
|
||||||
|
-- Returns a list of file "items". In eash item the "filename" will be the
|
||||||
|
-- complete file path relative to "root" *without* the trailing '/'.
|
||||||
|
local function get_directory_files(root, path, t, recursive, begin_hook)
|
||||||
|
if begin_hook then begin_hook() end
|
||||||
|
local size_limit = config.file_size_limit * 10e5
|
||||||
|
local all = system.list_dir(root .. 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 .. PATHSEP .. file
|
||||||
|
local info = system.get_file_info(root .. file)
|
||||||
|
if info and info.size < size_limit then
|
||||||
|
info.filename = strip_leading_path(file)
|
||||||
|
table.insert(info.type == "dir" and dirs or files, info)
|
||||||
|
entries_count = entries_count + 1
|
||||||
|
if recursive and entries_count > max_entries then return nil, entries_count end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.sort(dirs, compare_file)
|
||||||
|
for _, f in ipairs(dirs) do
|
||||||
|
table.insert(t, f)
|
||||||
|
if recursive and entries_count <= max_entries then
|
||||||
|
local subdir_t, subdir_count = get_directory_files(root, PATHSEP .. f.filename, t, recursive)
|
||||||
|
entries_count = entries_count + subdir_count
|
||||||
|
f.scanned = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.sort(files, compare_file)
|
||||||
|
for _, f in ipairs(files) do
|
||||||
|
table.insert(t, f)
|
||||||
|
end
|
||||||
|
|
||||||
|
return t, entries_count
|
||||||
|
end
|
||||||
|
|
||||||
local function project_scan_thread()
|
local function project_scan_thread()
|
||||||
local function diff_files(a, b)
|
local function diff_files(a, b)
|
||||||
if #a ~= #b then return true end
|
if #a ~= #b then return true end
|
||||||
|
@ -106,71 +158,21 @@ local function project_scan_thread()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function compare_file(a, b)
|
|
||||||
return a.filename < b.filename
|
|
||||||
end
|
|
||||||
|
|
||||||
-- "root" will by an absolute path without trailing '/'
|
|
||||||
-- "path" will be a path starting with '/' and without trailing '/'
|
|
||||||
-- or the empty string.
|
|
||||||
-- It will identifies a sub-path within "root.
|
|
||||||
-- The current path location will therefore always be: root .. path.
|
|
||||||
-- When recursing "root" will always be the same, only "path" will change.
|
|
||||||
-- Returns a list of file "items". In eash item the "filename" will be the
|
|
||||||
-- complete file path relative to "root" *without* the trailing '/'.
|
|
||||||
local function get_files(root, path, t)
|
|
||||||
coroutine.yield()
|
|
||||||
t = t or {}
|
|
||||||
local size_limit = config.file_size_limit * 10e5
|
|
||||||
local all = system.list_dir(root .. 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 .. PATHSEP .. file
|
|
||||||
local info = system.get_file_info(root .. file)
|
|
||||||
if info and info.size < size_limit then
|
|
||||||
info.filename = strip_leading_path(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
|
|
||||||
|
|
||||||
table.sort(dirs, compare_file)
|
|
||||||
for _, f in ipairs(dirs) do
|
|
||||||
table.insert(t, f)
|
|
||||||
if entries_count <= max_entries then
|
|
||||||
local subdir_t, subdir_count = get_files(root, PATHSEP .. f.filename, t)
|
|
||||||
entries_count = entries_count + subdir_count
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
table.sort(files, compare_file)
|
|
||||||
for _, f in ipairs(files) do
|
|
||||||
table.insert(t, f)
|
|
||||||
end
|
|
||||||
|
|
||||||
return t, entries_count
|
|
||||||
end
|
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
-- 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
|
||||||
for i = 1, #core.project_directories do
|
local i = 1
|
||||||
|
while not core.project_files_limit and i <= #core.project_directories do
|
||||||
local dir = core.project_directories[i]
|
local dir = core.project_directories[i]
|
||||||
local t, entries_count = get_files(dir.name, "")
|
local t, entries_count = get_directory_files(dir.name, "", {}, true)
|
||||||
if diff_files(dir.files, t) then
|
if diff_files(dir.files, t) then
|
||||||
if entries_count > config.max_project_files then
|
if entries_count > config.max_project_files then
|
||||||
|
core.project_files_limit = true
|
||||||
core.status_view:show_message("!", style.accent,
|
core.status_view:show_message("!", style.accent,
|
||||||
"Too many files in project directory: stopping reading at "..
|
"Too many files in project directory: stopped reading at "..
|
||||||
config.max_project_files.." files according to config.max_project_files. "..
|
config.max_project_files.." files. For more information see "..
|
||||||
"Either tweak this variable, or ignore certain files/directories by "..
|
"usage.md at github.com/franko/lite-xl."
|
||||||
"using the config.ignore_files variable in your user plugin or "..
|
)
|
||||||
"project config.")
|
|
||||||
end
|
end
|
||||||
dir.files = t
|
dir.files = t
|
||||||
core.redraw = true
|
core.redraw = true
|
||||||
|
@ -178,6 +180,7 @@ local function project_scan_thread()
|
||||||
if dir.name == core.project_dir then
|
if dir.name == core.project_dir then
|
||||||
core.project_files = dir.files
|
core.project_files = dir.files
|
||||||
end
|
end
|
||||||
|
i = i + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- wait for next scan
|
-- wait for next scan
|
||||||
|
@ -186,6 +189,46 @@ local function project_scan_thread()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function core.scan_project_folder(dirname, filename)
|
||||||
|
for _, dir in ipairs(core.project_directories) do
|
||||||
|
if dir.name == dirname then
|
||||||
|
for i, file in ipairs(dir.files) do
|
||||||
|
local file = dir.files[i]
|
||||||
|
if file.filename == filename then
|
||||||
|
if file.scanned then return end
|
||||||
|
local new_files = get_directory_files(dirname, PATHSEP .. filename, {})
|
||||||
|
for j, new_file in ipairs(new_files) do
|
||||||
|
table.insert(dir.files, i + j, new_file)
|
||||||
|
end
|
||||||
|
file.scanned = true
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function find_project_files_co(root, path)
|
||||||
|
local size_limit = config.file_size_limit * 10e5
|
||||||
|
local all = system.list_dir(root .. path) or {}
|
||||||
|
for _, file in ipairs(all) do
|
||||||
|
if not common.match_pattern(file, config.ignore_files) then
|
||||||
|
local file = path .. PATHSEP .. file
|
||||||
|
local info = system.get_file_info(root .. file)
|
||||||
|
if info and info.size < size_limit then
|
||||||
|
info.filename = strip_leading_path(file)
|
||||||
|
if info.type == "file" then
|
||||||
|
coroutine.yield(root, info)
|
||||||
|
else
|
||||||
|
find_project_files_co(root, PATHSEP .. info.filename)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
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
|
state.file_index = state.file_index + 1
|
||||||
|
@ -200,17 +243,27 @@ end
|
||||||
|
|
||||||
|
|
||||||
function core.get_project_files()
|
function core.get_project_files()
|
||||||
local state = { dir_index = 1, file_index = 0 }
|
if core.project_files_limit then
|
||||||
return project_files_iter, state
|
return coroutine.wrap(function()
|
||||||
|
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()
|
||||||
local n = 0
|
if not core.project_files_limit then
|
||||||
for i = 1, #core.project_directories do
|
local n = 0
|
||||||
n = n + #core.project_directories[i].files
|
for i = 1, #core.project_directories do
|
||||||
|
n = n + #core.project_directories[i].files
|
||||||
|
end
|
||||||
|
return n
|
||||||
end
|
end
|
||||||
return n
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -270,7 +323,7 @@ local style = require "core.style"
|
||||||
------------------------------- Fonts ----------------------------------------
|
------------------------------- Fonts ----------------------------------------
|
||||||
|
|
||||||
-- customize fonts:
|
-- customize fonts:
|
||||||
-- style.font = renderer.font.load(DATADIR .. "/fonts/FiraSans-Medium.ttf", 13 * SCALE)
|
-- style.font = renderer.font.load(DATADIR .. "/fonts/FiraSans-Regular.ttf", 13 * SCALE)
|
||||||
-- style.code_font = renderer.font.load(DATADIR .. "/fonts/JetBrainsMono-Regular.ttf", 13 * SCALE)
|
-- style.code_font = renderer.font.load(DATADIR .. "/fonts/JetBrainsMono-Regular.ttf", 13 * SCALE)
|
||||||
--
|
--
|
||||||
-- font names used by lite:
|
-- font names used by lite:
|
||||||
|
@ -353,6 +406,20 @@ local function whitespace_replacements()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function reload_on_user_module_save()
|
||||||
|
-- auto-realod style when user's module is saved by overriding Doc:Save()
|
||||||
|
local doc_save = Doc.save
|
||||||
|
local user_filename = system.absolute_path(USERDIR .. PATHSEP .. "init.lua")
|
||||||
|
function Doc:save(filename)
|
||||||
|
doc_save(self)
|
||||||
|
if self.abs_filename == user_filename then
|
||||||
|
core.reload_module("core.style")
|
||||||
|
core.load_user_directory()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function core.init()
|
function core.init()
|
||||||
command = require "core.command"
|
command = require "core.command"
|
||||||
keymap = require "core.keymap"
|
keymap = require "core.keymap"
|
||||||
|
@ -374,7 +441,7 @@ function core.init()
|
||||||
local recent_projects, window_position, window_mode = load_session()
|
local recent_projects, window_position, window_mode = load_session()
|
||||||
if window_mode == "normal" then
|
if window_mode == "normal" then
|
||||||
system.set_window_size(table.unpack(window_position))
|
system.set_window_size(table.unpack(window_position))
|
||||||
else
|
elseif window_mode == "maximized" then
|
||||||
system.set_window_mode("maximized")
|
system.set_window_mode("maximized")
|
||||||
end
|
end
|
||||||
core.recent_projects = recent_projects
|
core.recent_projects = recent_projects
|
||||||
|
@ -495,6 +562,8 @@ function core.init()
|
||||||
if item.text == "Exit" then os.exit(1) end
|
if item.text == "Exit" then os.exit(1) end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
reload_on_user_module_save()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -554,13 +623,19 @@ do
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- DEPRECATED function
|
||||||
core.doc_save_hooks = {}
|
core.doc_save_hooks = {}
|
||||||
function core.add_save_hook(fn)
|
function core.add_save_hook(fn)
|
||||||
|
core.error("The function core.add_save_hook is deprecated." ..
|
||||||
|
" Modules should now directly override the Doc:save function.")
|
||||||
core.doc_save_hooks[#core.doc_save_hooks + 1] = fn
|
core.doc_save_hooks[#core.doc_save_hooks + 1] = fn
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- DEPRECATED function
|
||||||
function core.on_doc_save(filename)
|
function core.on_doc_save(filename)
|
||||||
|
-- for backward compatibility in modules. Hooks are deprecated, the function Doc:save
|
||||||
|
-- should be directly overidded.
|
||||||
for _, hook in ipairs(core.doc_save_hooks) do
|
for _, hook in ipairs(core.doc_save_hooks) do
|
||||||
hook(filename)
|
hook(filename)
|
||||||
end
|
end
|
||||||
|
@ -1042,15 +1117,4 @@ function core.on_error(err)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
core.add_save_hook(function(filename)
|
|
||||||
local doc = core.active_view.doc
|
|
||||||
local user_filename = system.absolute_path(USERDIR .. PATHSEP .. "init.lua")
|
|
||||||
if doc and doc:is(Doc) and doc.abs_filename == user_filename then
|
|
||||||
core.reload_module("core.style")
|
|
||||||
core.load_user_directory()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return core
|
return core
|
||||||
|
|
|
@ -272,6 +272,7 @@ end
|
||||||
|
|
||||||
|
|
||||||
function Node:get_scroll_button_index(px, py)
|
function Node:get_scroll_button_index(px, py)
|
||||||
|
if #self.views == 1 then return end
|
||||||
for i = 1, 2 do
|
for i = 1, 2 do
|
||||||
local x, y, w, h = self:get_scroll_button_rect(i)
|
local x, y, w, h = self:get_scroll_button_rect(i)
|
||||||
if px >= x and px < x + w and py >= y and py < y + h then
|
if px >= x and px < x + w and py >= y and py < y + h then
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
-- this file is used by lite-xl to setup the Lua environment
|
-- this file is used by lite-xl to setup the Lua environment when starting
|
||||||
-- when starting
|
VERSION = "1.16.11"
|
||||||
VERSION = "1.16.10"
|
|
||||||
MOD_VERSION = "1"
|
MOD_VERSION = "1"
|
||||||
|
|
||||||
SCALE = tonumber(os.getenv("LITE_SCALE")) or SCALE
|
SCALE = tonumber(os.getenv("LITE_SCALE")) or SCALE
|
||||||
|
|
|
@ -21,8 +21,8 @@ style.tab_width = common.round(170 * SCALE)
|
||||||
--
|
--
|
||||||
-- On High DPI monitor or non RGB monitor you may consider using antialiasing grayscale instead.
|
-- On High DPI monitor or non RGB monitor you may consider using antialiasing grayscale instead.
|
||||||
-- The antialiasing grayscale with full hinting is interesting for crisp font rendering.
|
-- The antialiasing grayscale with full hinting is interesting for crisp font rendering.
|
||||||
style.font = renderer.font.load(DATADIR .. "/fonts/FiraSans-Medium.ttf", 13 * SCALE)
|
style.font = renderer.font.load(DATADIR .. "/fonts/FiraSans-Regular.ttf", 13 * SCALE)
|
||||||
style.big_font = renderer.font.load(DATADIR .. "/fonts/FiraSans-Medium.ttf", 40 * SCALE)
|
style.big_font = renderer.font.load(DATADIR .. "/fonts/FiraSans-Regular.ttf", 40 * SCALE)
|
||||||
style.icon_font = renderer.font.load(DATADIR .. "/fonts/icons.ttf", 14 * SCALE, {antialiasing="grayscale", hinting="full"})
|
style.icon_font = renderer.font.load(DATADIR .. "/fonts/icons.ttf", 14 * SCALE, {antialiasing="grayscale", hinting="full"})
|
||||||
style.icon_big_font = renderer.font.load(DATADIR .. "/fonts/icons.ttf", 20 * SCALE, {antialiasing="grayscale", hinting="full"})
|
style.icon_big_font = renderer.font.load(DATADIR .. "/fonts/icons.ttf", 20 * SCALE, {antialiasing="grayscale", hinting="full"})
|
||||||
style.code_font = renderer.font.load(DATADIR .. "/fonts/JetBrainsMono-Regular.ttf", 13 * SCALE)
|
style.code_font = renderer.font.load(DATADIR .. "/fonts/JetBrainsMono-Regular.ttf", 13 * SCALE)
|
||||||
|
|
Binary file not shown.
|
@ -76,7 +76,7 @@ local function get_non_empty_lines(syntax, lines)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local auto_detect_max_lines = 200
|
local auto_detect_max_lines = 100
|
||||||
|
|
||||||
local function detect_indent_stat(doc)
|
local function detect_indent_stat(doc)
|
||||||
local stat = {}
|
local stat = {}
|
||||||
|
@ -99,29 +99,11 @@ local function detect_indent_stat(doc)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local doc_on_text_change = Doc.on_text_change
|
|
||||||
local adjust_threshold = 4
|
|
||||||
|
|
||||||
local current_on_text_change = nil
|
|
||||||
|
|
||||||
local function update_cache(doc)
|
local function update_cache(doc)
|
||||||
local type, size, score = detect_indent_stat(doc)
|
local type, size, score = detect_indent_stat(doc)
|
||||||
cache[doc] = { type = type, size = size, confirmed = (score >= adjust_threshold) }
|
local score_threshold = 4
|
||||||
|
cache[doc] = { type = type, size = size, confirmed = (score >= score_threshold) }
|
||||||
doc.indent_info = cache[doc]
|
doc.indent_info = cache[doc]
|
||||||
if score < adjust_threshold and doc_on_text_change then
|
|
||||||
current_on_text_change = function(self, ...)
|
|
||||||
update_cache(self)
|
|
||||||
end
|
|
||||||
elseif score >= adjust_threshold and doc_on_text_change then
|
|
||||||
current_on_text_change = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Doc.on_text_change(...)
|
|
||||||
if current_on_text_change then
|
|
||||||
current_on_text_change(...)
|
|
||||||
end
|
|
||||||
doc_on_text_change(...)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -129,6 +111,14 @@ local new = Doc.new
|
||||||
function Doc:new(...)
|
function Doc:new(...)
|
||||||
new(self, ...)
|
new(self, ...)
|
||||||
update_cache(self)
|
update_cache(self)
|
||||||
|
if not cache[self].confirmed then
|
||||||
|
core.add_thread(function ()
|
||||||
|
while not cache[self].confirmed do
|
||||||
|
update_cache(self)
|
||||||
|
coroutine.yield(1)
|
||||||
|
end
|
||||||
|
end, self)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local clean = Doc.clean
|
local clean = Doc.clean
|
||||||
|
|
|
@ -170,12 +170,17 @@ function ResultsView:draw()
|
||||||
local ox, oy = self:get_content_offset()
|
local ox, oy = self:get_content_offset()
|
||||||
local x, y = ox + style.padding.x, oy + style.padding.y
|
local x, y = ox + style.padding.x, oy + style.padding.y
|
||||||
local files_number = core.project_files_number()
|
local files_number = core.project_files_number()
|
||||||
local per = self.last_file_idx / files_number
|
local per = files_number and self.last_file_idx / files_number or 1
|
||||||
local text
|
local text
|
||||||
if self.searching then
|
if self.searching then
|
||||||
text = string.format("Searching %d%% (%d of %d files, %d matches) for %q...",
|
if files_number then
|
||||||
per * 100, self.last_file_idx, files_number,
|
text = string.format("Searching %d%% (%d of %d files, %d matches) for %q...",
|
||||||
#self.results, self.query)
|
per * 100, self.last_file_idx, files_number,
|
||||||
|
#self.results, self.query)
|
||||||
|
else
|
||||||
|
text = string.format("Searching (%d files, %d matches) for %q...",
|
||||||
|
self.last_file_idx, #self.results, self.query)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
text = string.format("Found %d matches for %q",
|
text = string.format("Found %d matches for %q",
|
||||||
#self.results, self.query)
|
#self.results, self.query)
|
||||||
|
|
|
@ -93,6 +93,13 @@ function TreeView:get_item_height()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function TreeView:invalidate_cache(dirname)
|
||||||
|
for _, v in pairs(self.cache[dirname]) do
|
||||||
|
v.skip = nil
|
||||||
|
end
|
||||||
|
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_directories do
|
||||||
|
@ -102,9 +109,7 @@ function TreeView:check_cache()
|
||||||
self.last[dir.name] = dir.files
|
self.last[dir.name] = dir.files
|
||||||
else
|
else
|
||||||
if dir.files ~= last_files then
|
if dir.files ~= last_files then
|
||||||
for _, v in pairs(self.cache[dir.name]) do
|
self:invalidate_cache(dir.name)
|
||||||
v.skip = nil
|
|
||||||
end
|
|
||||||
self.last[dir.name] = dir.files
|
self.last[dir.name] = dir.files
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -208,17 +213,25 @@ function TreeView:on_mouse_pressed(button, x, y, clicks)
|
||||||
if caught then
|
if caught then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if not self.hovered_item then
|
local hovered_item = self.hovered_item
|
||||||
|
if not hovered_item then
|
||||||
return
|
return
|
||||||
elseif self.hovered_item.type == "dir" then
|
elseif hovered_item.type == "dir" then
|
||||||
if keymap.modkeys["ctrl"] and button == "left" then
|
if keymap.modkeys["ctrl"] and button == "left" then
|
||||||
create_directory_in(self.hovered_item)
|
create_directory_in(hovered_item)
|
||||||
else
|
else
|
||||||
self.hovered_item.expanded = not self.hovered_item.expanded
|
if core.project_files_limit and not hovered_item.expanded then
|
||||||
|
local filename, abs_filename = hovered_item.filename, hovered_item.abs_filename
|
||||||
|
local index = string.find(abs_filename, filename, 1, true)
|
||||||
|
local dirname = string.sub(abs_filename, 1, index - 2)
|
||||||
|
core.scan_project_folder(dirname, filename)
|
||||||
|
self:invalidate_cache(dirname)
|
||||||
|
end
|
||||||
|
hovered_item.expanded = not hovered_item.expanded
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
core.try(function()
|
core.try(function()
|
||||||
local doc_filename = common.relative_path(core.project_dir, self.hovered_item.abs_filename)
|
local doc_filename = common.relative_path(core.project_dir, hovered_item.abs_filename)
|
||||||
core.root_view:open_doc(core.open_doc(doc_filename))
|
core.root_view:open_doc(core.open_doc(doc_filename))
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
|
@ -71,6 +71,13 @@ The project module can be edited by running the `core:open-project-module`
|
||||||
command — if the module does not exist for the current project when the
|
command — if the module does not exist for the current project when the
|
||||||
command is run it will be created.
|
command is run it will be created.
|
||||||
|
|
||||||
|
## Big directories
|
||||||
|
Often projects contain compiled, bundled or downloaded files which you don't want to edit. These files can be excluded from projects by configuring `config.ignore_files`. Such a configuration might look like `config.ignore_files = { "^%.", "node_modules" }`. This will exclude the `node_modules` folder and any file starting with `.`. You can add this to a user or project module.
|
||||||
|
|
||||||
|
If a project has more files than the maximum (configured with `config.max_project_files`) lite-xl will switch to a different mode where files are lazily loaded.
|
||||||
|
|
||||||
|
_Note: Because of lazy loading `core:find-file` will open `core:open-file` instead._
|
||||||
|
|
||||||
## Add directories to a project
|
## Add directories to a project
|
||||||
|
|
||||||
In addition to the project directories it is possible to add other directories
|
In addition to the project directories it is possible to add other directories
|
||||||
|
|
Loading…
Reference in New Issue