Merge branch 'project-manager'
This commit is contained in:
commit
1fc0409163
|
@ -62,6 +62,7 @@ lite_build_package_windows () {
|
||||||
local bindir="$pdir"
|
local bindir="$pdir"
|
||||||
local datadir="$pdir/data"
|
local datadir="$pdir/data"
|
||||||
else
|
else
|
||||||
|
echo "WARNING: using non portable option on unix-like system"
|
||||||
local bindir="$pdir/bin"
|
local bindir="$pdir/bin"
|
||||||
local datadir="$pdir/share/lite-xl"
|
local datadir="$pdir/share/lite-xl"
|
||||||
fi
|
fi
|
||||||
|
@ -70,6 +71,9 @@ lite_build_package_windows () {
|
||||||
for module_name in core plugins colors fonts; do
|
for module_name in core plugins colors fonts; do
|
||||||
copy_directory_from_repo --strip-components=1 "data/$module_name" "$datadir"
|
copy_directory_from_repo --strip-components=1 "data/$module_name" "$datadir"
|
||||||
done
|
done
|
||||||
|
for module_name in plugins colors; do
|
||||||
|
cp -r "$build/third/data/$module_name" "$datadir"
|
||||||
|
done
|
||||||
cp "$build/src/lite.exe" "$bindir"
|
cp "$build/src/lite.exe" "$bindir"
|
||||||
strip --strip-all "$bindir/lite.exe"
|
strip --strip-all "$bindir/lite.exe"
|
||||||
pushd ".package-build"
|
pushd ".package-build"
|
||||||
|
@ -100,6 +104,9 @@ lite_build_package_macosx () {
|
||||||
for module_name in core plugins colors fonts; do
|
for module_name in core plugins colors fonts; do
|
||||||
copy_directory_from_repo --strip-components=1 "data/$module_name" "$datadir"
|
copy_directory_from_repo --strip-components=1 "data/$module_name" "$datadir"
|
||||||
done
|
done
|
||||||
|
for module_name in plugins colors; do
|
||||||
|
cp -r "$build/third/data/$module_name" "$datadir"
|
||||||
|
done
|
||||||
cp "$build/src/lite" "$bindir"
|
cp "$build/src/lite" "$bindir"
|
||||||
strip "$bindir/lite"
|
strip "$bindir/lite"
|
||||||
pushd ".package-build"
|
pushd ".package-build"
|
||||||
|
@ -119,6 +126,7 @@ lite_build_package_linux () {
|
||||||
local os="linux"
|
local os="linux"
|
||||||
local pdir=".package-build/lite-xl"
|
local pdir=".package-build/lite-xl"
|
||||||
if [ $portable == "true" ]; then
|
if [ $portable == "true" ]; then
|
||||||
|
echo "WARNING: using portable option on unix-like system"
|
||||||
local bindir="$pdir"
|
local bindir="$pdir"
|
||||||
local datadir="$pdir/data"
|
local datadir="$pdir/data"
|
||||||
else
|
else
|
||||||
|
@ -130,6 +138,9 @@ lite_build_package_linux () {
|
||||||
for module_name in core plugins colors fonts; do
|
for module_name in core plugins colors fonts; do
|
||||||
copy_directory_from_repo --strip-components=1 "data/$module_name" "$datadir"
|
copy_directory_from_repo --strip-components=1 "data/$module_name" "$datadir"
|
||||||
done
|
done
|
||||||
|
for module_name in plugins colors; do
|
||||||
|
cp -r "$build/third/data/$module_name" "$datadir"
|
||||||
|
done
|
||||||
cp "$build/src/lite" "$bindir"
|
cp "$build/src/lite" "$bindir"
|
||||||
strip "$bindir/lite"
|
strip "$bindir/lite"
|
||||||
pushd ".package-build"
|
pushd ".package-build"
|
||||||
|
@ -154,6 +165,15 @@ lite_build_package () {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lite_copy_third_party_modules () {
|
||||||
|
local build="$1"
|
||||||
|
curl --insecure -L "https://github.com/rxi/lite-colors/archive/master.zip" -o "$build/rxi-lite-colors.zip"
|
||||||
|
mkdir -p "$build/third/data/colors" "$build/third/data/plugins"
|
||||||
|
unzip "$build/rxi-lite-colors.zip" -d "$build"
|
||||||
|
mv "$build/lite-colors-master/colors" "$build/third/data"
|
||||||
|
rm -fr "$build/lite-colors-master"
|
||||||
|
}
|
||||||
|
|
||||||
if [[ -z "$1" || -z "$2" ]]; then
|
if [[ -z "$1" || -z "$2" ]]; then
|
||||||
echo "usage: $0 [options] <version> <arch>"
|
echo "usage: $0 [options] <version> <arch>"
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -184,5 +204,6 @@ if [ -z ${pgo+set} ]; then
|
||||||
else
|
else
|
||||||
lite_build_pgo "$portable" "$build_dir"
|
lite_build_pgo "$portable" "$build_dir"
|
||||||
fi
|
fi
|
||||||
|
lite_copy_third_party_modules "$build_dir"
|
||||||
lite_build_package "$portable" "$build_dir" "$version" "$arch"
|
lite_build_package "$portable" "$build_dir" "$version" "$arch"
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,10 @@ command.add(nil, {
|
||||||
core.quit()
|
core.quit()
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
["core:restart"] = function()
|
||||||
|
core.restart()
|
||||||
|
end,
|
||||||
|
|
||||||
["core:force-quit"] = function()
|
["core:force-quit"] = function()
|
||||||
core.quit(true)
|
core.quit(true)
|
||||||
end,
|
end,
|
||||||
|
@ -98,7 +102,15 @@ command.add(nil, {
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["core:open-user-module"] = function()
|
["core:open-user-module"] = function()
|
||||||
core.root_view:open_doc(core.open_doc(USERDIR .. "/init.lua"))
|
local user_module_doc = core.open_doc(USERDIR .. "/init.lua")
|
||||||
|
if not user_module_doc then return end
|
||||||
|
local doc_save = user_module_doc.save
|
||||||
|
user_module_doc.save = function(self)
|
||||||
|
doc_save(self)
|
||||||
|
core.reload_module("core.style")
|
||||||
|
core.load_user_directory()
|
||||||
|
end
|
||||||
|
core.root_view:open_doc(user_module_doc)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["core:open-project-module"] = function()
|
["core:open-project-module"] = function()
|
||||||
|
@ -111,4 +123,32 @@ command.add(nil, {
|
||||||
doc:save(filename)
|
doc:save(filename)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
["core:change-project-folder"] = function()
|
||||||
|
core.command_view:enter("Change Project Folder", function(text)
|
||||||
|
local path_stat = system.get_file_info(text)
|
||||||
|
if not path_stat or path_stat.type ~= 'dir' then
|
||||||
|
core.error("Cannot open folder %q", text)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if core.confirm_close_all() then
|
||||||
|
core.open_folder_project(text)
|
||||||
|
end
|
||||||
|
end, function(text)
|
||||||
|
return text == "" and core.recent_projects or common.dir_path_suggest(text)
|
||||||
|
end)
|
||||||
|
end,
|
||||||
|
|
||||||
|
["core:open-project-folder"] = function()
|
||||||
|
core.command_view:enter("Open Project", function(text)
|
||||||
|
local path_stat = system.get_file_info(text)
|
||||||
|
if not path_stat or path_stat.type ~= 'dir' then
|
||||||
|
core.error("Cannot open folder %q", text)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
system.exec(string.format("%q %q", EXEFILE, text))
|
||||||
|
end, function(text)
|
||||||
|
return text == "" and core.recent_projects or common.dir_path_suggest(text)
|
||||||
|
end)
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
|
@ -102,6 +102,21 @@ function common.path_suggest(text)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function common.dir_path_suggest(text)
|
||||||
|
local path, name = text:match("^(.-)([^/\\]*)$")
|
||||||
|
local files = system.list_dir(path == "" and "." or path) or {}
|
||||||
|
local res = {}
|
||||||
|
for _, file in ipairs(files) do
|
||||||
|
file = path .. file
|
||||||
|
local info = system.get_file_info(file)
|
||||||
|
if info and info.type == "dir" and file:lower():find(text:lower(), nil, true) == 1 then
|
||||||
|
table.insert(res, file)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function common.match_pattern(text, pattern, ...)
|
function common.match_pattern(text, pattern, ...)
|
||||||
if type(pattern) == "string" then
|
if type(pattern) == "string" then
|
||||||
return text:find(pattern, ...)
|
return text:find(pattern, ...)
|
||||||
|
|
|
@ -187,8 +187,14 @@ function DocView:scroll_to_make_visible(line, col)
|
||||||
self.scroll.to.y = math.max(self.scroll.to.y, max)
|
self.scroll.to.y = math.max(self.scroll.to.y, max)
|
||||||
local gw = self:get_gutter_width()
|
local gw = self:get_gutter_width()
|
||||||
local xoffset = self:get_col_x_offset(line, col)
|
local xoffset = self:get_col_x_offset(line, col)
|
||||||
local max = xoffset - self.size.x + gw + self.size.x / 5
|
local xmargin = 3 * self:get_font():get_width(' ')
|
||||||
self.scroll.to.x = math.max(0, max)
|
local xsup = xoffset + gw + xmargin
|
||||||
|
local xinf = xoffset - xmargin
|
||||||
|
if xsup > self.scroll.x + self.size.x then
|
||||||
|
self.scroll.to.x = xsup - self.size.x
|
||||||
|
elseif xinf < self.scroll.x then
|
||||||
|
self.scroll.to.x = math.max(0, xinf)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,53 @@ local Doc
|
||||||
|
|
||||||
local core = {}
|
local core = {}
|
||||||
|
|
||||||
|
local function table_serialize(t)
|
||||||
|
local ls = {"{"}
|
||||||
|
for i = 1, #t do
|
||||||
|
ls[#ls + 1] = string.format(" %q,", t[i])
|
||||||
|
end
|
||||||
|
ls[#ls + 1] = "}"
|
||||||
|
return table.concat(ls, "\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function load_projects()
|
||||||
|
local ok, t = pcall(dofile, USERDIR .. "/recent_projects.lua")
|
||||||
|
core.recent_projects = (ok and t or {})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function add_project_to_recents(dirname)
|
||||||
|
dirname = system.absolute_path(dirname)
|
||||||
|
if not dirname then return end
|
||||||
|
local recents = core.recent_projects
|
||||||
|
local n = #recents
|
||||||
|
for i = 1, n do
|
||||||
|
if dirname == recents[i] then
|
||||||
|
table.remove(recents, i)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.insert(recents, 1, dirname)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function save_projects()
|
||||||
|
local fp = io.open(USERDIR .. "/recent_projects.lua", "w")
|
||||||
|
if fp then
|
||||||
|
fp:write("return ", table_serialize(core.recent_projects), "\n")
|
||||||
|
fp:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function core.open_folder_project(dirname)
|
||||||
|
core.root_view:close_all_docviews()
|
||||||
|
add_project_to_recents(dirname)
|
||||||
|
save_projects()
|
||||||
|
core.switch_project = dirname
|
||||||
|
core.threads[core.project_scan_thread_id].wake = 0
|
||||||
|
end
|
||||||
|
|
||||||
local function project_scan_thread()
|
local function project_scan_thread()
|
||||||
|
local priority_run = true
|
||||||
|
|
||||||
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
|
||||||
for i, v in ipairs(a) do
|
for i, v in ipairs(a) do
|
||||||
|
@ -28,7 +73,7 @@ local function project_scan_thread()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_files(path, t)
|
local function get_files(path, t)
|
||||||
coroutine.yield()
|
if not priority_run then coroutine.yield() end
|
||||||
t = t or {}
|
t = t or {}
|
||||||
local size_limit = config.file_size_limit * 10e5
|
local size_limit = config.file_size_limit * 10e5
|
||||||
local all = system.list_dir(path) or {}
|
local all = system.list_dir(path) or {}
|
||||||
|
@ -78,12 +123,19 @@ local function project_scan_thread()
|
||||||
end
|
end
|
||||||
core.project_files = t
|
core.project_files = t
|
||||||
core.redraw = true
|
core.redraw = true
|
||||||
|
priority_run = false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- wait for next scan
|
-- wait for next scan
|
||||||
|
if core.switch_project then
|
||||||
|
system.chdir(core.switch_project)
|
||||||
|
priority_run = true
|
||||||
|
core.switch_project = nil
|
||||||
|
else
|
||||||
coroutine.yield(config.project_scan_rate)
|
coroutine.yield(config.project_scan_rate)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- create a directory using mkdir but may need to create the parent
|
-- create a directory using mkdir but may need to create the parent
|
||||||
|
@ -121,30 +173,54 @@ local function write_user_init_file(init_filename)
|
||||||
init_file:write([[
|
init_file:write([[
|
||||||
-- put user settings here
|
-- put user settings here
|
||||||
-- this module will be loaded after everything else when the application starts
|
-- this module will be loaded after everything else when the application starts
|
||||||
|
-- it will be automatically reloaded when saved
|
||||||
|
|
||||||
local keymap = require "core.keymap"
|
local keymap = require "core.keymap"
|
||||||
local config = require "core.config"
|
local config = require "core.config"
|
||||||
local style = require "core.style"
|
local style = require "core.style"
|
||||||
|
|
||||||
-- light theme:
|
-- light theme:
|
||||||
-- require "colors.summer"
|
-- style.load("colors.summer")
|
||||||
|
|
||||||
-- key binding:
|
-- key binding:
|
||||||
-- keymap.add { ["ctrl+escape"] = "core:quit" }
|
-- keymap.add { ["ctrl+escape"] = "core:quit" }
|
||||||
|
|
||||||
|
-- customize fonts:
|
||||||
|
-- style.font = renderer.font.load(DATADIR .. "/fonts/font.ttf", 14 * SCALE)
|
||||||
|
-- style.code_font = renderer.font.load(DATADIR .. "/fonts/monospace.ttf", 13.5 * SCALE)
|
||||||
|
--
|
||||||
|
-- fonts used by the editor:
|
||||||
|
-- style.font : user interface
|
||||||
|
-- style.big_font : big text in welcome screen
|
||||||
|
-- style.icon_font : icons
|
||||||
|
-- style.code_font : code
|
||||||
|
--
|
||||||
|
-- the function to load the font accept a 3rd optional argument like:
|
||||||
|
--
|
||||||
|
-- {antialiasing="grayscale", hinting="full"}
|
||||||
|
--
|
||||||
|
-- possible values are:
|
||||||
|
-- antialiasing: grayscale, subpixel
|
||||||
|
-- hinting: none, slight, full
|
||||||
]])
|
]])
|
||||||
init_file:close()
|
init_file:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local function load_user_directory()
|
function core.load_user_directory()
|
||||||
local init_filename = USERDIR .. "/init.lua"
|
return core.try(function()
|
||||||
local info = system.get_file_info(USERDIR)
|
local stat_dir = system.get_file_info(USERDIR)
|
||||||
if not info then
|
if not stat_dir then
|
||||||
create_user_directory()
|
create_user_directory()
|
||||||
|
end
|
||||||
|
local init_filename = USERDIR .. "/init.lua"
|
||||||
|
local stat_file = system.get_file_info(init_filename)
|
||||||
|
if not stat_file then
|
||||||
write_user_init_file(init_filename)
|
write_user_init_file(init_filename)
|
||||||
end
|
end
|
||||||
return dofile(init_filename)
|
dofile(init_filename)
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -156,7 +232,9 @@ function core.init()
|
||||||
CommandView = require "core.commandview"
|
CommandView = require "core.commandview"
|
||||||
Doc = require "core.doc"
|
Doc = require "core.doc"
|
||||||
|
|
||||||
local project_dir = "."
|
load_projects()
|
||||||
|
|
||||||
|
local project_dir = core.recent_projects[1] or "."
|
||||||
local files = {}
|
local files = {}
|
||||||
for i = 2, #ARGS do
|
for i = 2, #ARGS do
|
||||||
local info = system.get_file_info(ARGS[i]) or {}
|
local info = system.get_file_info(ARGS[i]) or {}
|
||||||
|
@ -164,6 +242,8 @@ function core.init()
|
||||||
table.insert(files, system.absolute_path(ARGS[i]))
|
table.insert(files, system.absolute_path(ARGS[i]))
|
||||||
elseif info.type == "dir" then
|
elseif info.type == "dir" then
|
||||||
project_dir = ARGS[i]
|
project_dir = ARGS[i]
|
||||||
|
add_project_to_recents(project_dir)
|
||||||
|
save_projects()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -177,18 +257,25 @@ function core.init()
|
||||||
core.project_files = {}
|
core.project_files = {}
|
||||||
core.redraw = true
|
core.redraw = true
|
||||||
core.visited_files = {}
|
core.visited_files = {}
|
||||||
|
core.restart_request = false
|
||||||
|
|
||||||
core.root_view = RootView()
|
core.root_view = RootView()
|
||||||
core.command_view = CommandView()
|
core.command_view = CommandView()
|
||||||
core.status_view = StatusView()
|
core.status_view = StatusView()
|
||||||
|
|
||||||
|
core.root_view.root_node.is_primary_view = true
|
||||||
core.root_view.root_node:split("down", core.command_view, true)
|
core.root_view.root_node:split("down", core.command_view, true)
|
||||||
core.root_view.root_node.b:split("down", core.status_view, true)
|
core.root_view.root_node.b:split("down", core.status_view, true)
|
||||||
|
|
||||||
core.add_thread(project_scan_thread)
|
core.project_scan_thread_id = core.add_thread(project_scan_thread)
|
||||||
command.add_defaults()
|
command.add_defaults()
|
||||||
local got_plugin_error = not core.load_plugins()
|
local got_plugin_error = not core.load_plugins()
|
||||||
local got_user_error = not core.try(load_user_directory)
|
local got_user_error = not core.load_user_directory()
|
||||||
|
|
||||||
|
do
|
||||||
|
local pdir, pname = system.absolute_path(project_dir):match("(.*)[/\\\\](.*)")
|
||||||
|
core.log("Opening project %q from directory %q", pname, pdir)
|
||||||
|
end
|
||||||
local got_project_error = not core.load_project_module()
|
local got_project_error = not core.load_project_module()
|
||||||
|
|
||||||
for _, filename in ipairs(files) do
|
for _, filename in ipairs(files) do
|
||||||
|
@ -201,6 +288,28 @@ function core.init()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function core.confirm_close_all()
|
||||||
|
local dirty_count = 0
|
||||||
|
local dirty_name
|
||||||
|
for _, doc in ipairs(core.docs) do
|
||||||
|
if doc:is_dirty() then
|
||||||
|
dirty_count = dirty_count + 1
|
||||||
|
dirty_name = doc:get_name()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if dirty_count > 0 then
|
||||||
|
local text
|
||||||
|
if dirty_count == 1 then
|
||||||
|
text = string.format("\"%s\" has unsaved changes. Quit anyway?", dirty_name)
|
||||||
|
else
|
||||||
|
text = string.format("%d docs have unsaved changes. Quit anyway?", dirty_count)
|
||||||
|
end
|
||||||
|
local confirm = system.show_confirm_dialog("Unsaved Changes", text)
|
||||||
|
if not confirm then return false end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
local temp_uid = (system.get_time() * 1000) % 0xffffffff
|
local temp_uid = (system.get_time() * 1000) % 0xffffffff
|
||||||
local temp_file_prefix = string.format(".lite_temp_%08x", temp_uid)
|
local temp_file_prefix = string.format(".lite_temp_%08x", temp_uid)
|
||||||
local temp_file_counter = 0
|
local temp_file_counter = 0
|
||||||
|
@ -225,26 +334,17 @@ function core.quit(force)
|
||||||
delete_temp_files()
|
delete_temp_files()
|
||||||
os.exit()
|
os.exit()
|
||||||
end
|
end
|
||||||
local dirty_count = 0
|
if core.confirm_close_all() then
|
||||||
local dirty_name
|
|
||||||
for _, doc in ipairs(core.docs) do
|
|
||||||
if doc:is_dirty() then
|
|
||||||
dirty_count = dirty_count + 1
|
|
||||||
dirty_name = doc:get_name()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if dirty_count > 0 then
|
|
||||||
local text
|
|
||||||
if dirty_count == 1 then
|
|
||||||
text = string.format("\"%s\" has unsaved changes. Quit anyway?", dirty_name)
|
|
||||||
else
|
|
||||||
text = string.format("%d docs have unsaved changes. Quit anyway?", dirty_count)
|
|
||||||
end
|
|
||||||
local confirm = system.show_confirm_dialog("Unsaved Changes", text)
|
|
||||||
if not confirm then return end
|
|
||||||
end
|
|
||||||
core.quit(true)
|
core.quit(true)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function core.restart()
|
||||||
|
if core.confirm_close_all() then
|
||||||
|
core.restart_request = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function core.load_plugins()
|
function core.load_plugins()
|
||||||
|
@ -317,6 +417,7 @@ function core.add_thread(f, weak_ref)
|
||||||
local key = weak_ref or #core.threads + 1
|
local key = weak_ref or #core.threads + 1
|
||||||
local fn = function() return core.try(f) end
|
local fn = function() return core.try(f) end
|
||||||
core.threads[key] = { cr = coroutine.create(fn), wake = 0 }
|
core.threads[key] = { cr = coroutine.create(fn), wake = 0 }
|
||||||
|
return key
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -544,10 +645,12 @@ end)
|
||||||
|
|
||||||
function core.run()
|
function core.run()
|
||||||
local idle_iterations = 0
|
local idle_iterations = 0
|
||||||
|
local frame_duration = 1 / config.fps
|
||||||
while true do
|
while true do
|
||||||
core.frame_start = system.get_time()
|
core.frame_start = system.get_time()
|
||||||
local did_redraw = core.step()
|
local did_redraw = core.step()
|
||||||
local need_more_work = run_threads()
|
local need_more_work = run_threads()
|
||||||
|
if core.restart_request then break end
|
||||||
if not did_redraw and not need_more_work then
|
if not did_redraw and not need_more_work then
|
||||||
idle_iterations = idle_iterations + 1
|
idle_iterations = idle_iterations + 1
|
||||||
-- do not wait of events at idle_iterations = 1 to give a chance at core.step to run
|
-- do not wait of events at idle_iterations = 1 to give a chance at core.step to run
|
||||||
|
@ -555,16 +658,16 @@ function core.run()
|
||||||
if idle_iterations > 1 then
|
if idle_iterations > 1 then
|
||||||
if system.window_has_focus() then
|
if system.window_has_focus() then
|
||||||
-- keep running even with no events to make the cursor blinks
|
-- keep running even with no events to make the cursor blinks
|
||||||
system.wait_event(1 / config.fps)
|
system.wait_event(frame_duration)
|
||||||
else
|
else
|
||||||
system.wait_event()
|
system.wait_event()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
idle_iterations = 0
|
idle_iterations = 0
|
||||||
end
|
|
||||||
local elapsed = system.get_time() - core.frame_start
|
local elapsed = system.get_time() - core.frame_start
|
||||||
system.sleep(math.max(0, 1 / config.fps - elapsed))
|
system.sleep(math.max(0, frame_duration - elapsed))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,8 @@ keymap.add {
|
||||||
["ctrl+p"] = "core:find-file",
|
["ctrl+p"] = "core:find-file",
|
||||||
["ctrl+o"] = "core:open-file",
|
["ctrl+o"] = "core:open-file",
|
||||||
["ctrl+n"] = "core:new-doc",
|
["ctrl+n"] = "core:new-doc",
|
||||||
|
["ctrl+shift+c"] = "core:change-project-folder",
|
||||||
|
["ctrl+shift+o"] = "core:open-project-folder",
|
||||||
["alt+return"] = "core:toggle-fullscreen",
|
["alt+return"] = "core:toggle-fullscreen",
|
||||||
|
|
||||||
["alt+shift+j"] = "root:split-left",
|
["alt+shift+j"] = "root:split-left",
|
||||||
|
|
|
@ -4,6 +4,7 @@ local style = require "core.style"
|
||||||
local keymap = require "core.keymap"
|
local keymap = require "core.keymap"
|
||||||
local Object = require "core.object"
|
local Object = require "core.object"
|
||||||
local View = require "core.view"
|
local View = require "core.view"
|
||||||
|
local CommandView = require "core.commandview"
|
||||||
local DocView = require "core.docview"
|
local DocView = require "core.docview"
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,9 +19,11 @@ local function draw_text(x, y, color)
|
||||||
local lines = {
|
local lines = {
|
||||||
{ fmt = "%s to run a command", cmd = "core:find-command" },
|
{ fmt = "%s to run a command", cmd = "core:find-command" },
|
||||||
{ fmt = "%s to open a file from the project", cmd = "core:find-file" },
|
{ fmt = "%s to open a file from the project", cmd = "core:find-file" },
|
||||||
|
{ fmt = "%s to change project folder", cmd = "core:change-project-folder" },
|
||||||
|
{ fmt = "%s to open a project folder", cmd = "core:open-project-folder" },
|
||||||
}
|
}
|
||||||
th = style.font:get_height()
|
th = style.font:get_height()
|
||||||
y = y + (dh - th * 2 - style.padding.y) / 2
|
y = y + (dh - (th + style.padding.y) * #lines) / 2
|
||||||
local w = 0
|
local w = 0
|
||||||
for _, line in ipairs(lines) do
|
for _, line in ipairs(lines) do
|
||||||
local text = string.format(line.fmt, keymap.get_binding(line.cmd))
|
local text = string.format(line.fmt, keymap.get_binding(line.cmd))
|
||||||
|
@ -376,6 +379,41 @@ function Node:draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function Node:is_empty()
|
||||||
|
if self.type == "leaf" then
|
||||||
|
return #self.views == 0
|
||||||
|
else
|
||||||
|
return self.a:is_empty() and self.b:is_empty()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function Node:close_all_docviews()
|
||||||
|
if self.type == "leaf" then
|
||||||
|
local i = 1
|
||||||
|
while i <= #self.views do
|
||||||
|
local view = self.views[i]
|
||||||
|
if view:is(DocView) and not view:is(CommandView) then
|
||||||
|
table.remove(self.views, i)
|
||||||
|
else
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #self.views == 0 and self.is_primary_view then
|
||||||
|
self:add_view(EmptyView())
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.a:close_all_docviews()
|
||||||
|
self.b:close_all_docviews()
|
||||||
|
if self.a:is_empty() then
|
||||||
|
self:consume(self.b)
|
||||||
|
elseif self.b:is_empty() then
|
||||||
|
self:consume(self.a)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local RootView = View:extend()
|
local RootView = View:extend()
|
||||||
|
|
||||||
|
@ -396,20 +434,17 @@ function RootView:get_active_node()
|
||||||
return self.root_node:get_node_for_view(core.active_view)
|
return self.root_node:get_node_for_view(core.active_view)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get un unlocked node with at least one view.
|
local function get_primary_view(node)
|
||||||
local function get_node_unlocked(node)
|
if node.is_primary_view then
|
||||||
if not node.locked and #node.views > 0 then
|
|
||||||
return node
|
return node
|
||||||
end
|
end
|
||||||
if node.type ~= "leaf" then
|
if node.type ~= "leaf" then
|
||||||
local a = get_node_unlocked(node.a)
|
return get_primary_view(node.a) or get_primary_view(node.b)
|
||||||
if a then return a end
|
|
||||||
return get_node_unlocked(node.b)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function RootView:get_document_view()
|
function RootView:get_primary_view()
|
||||||
local node = get_node_unlocked(self.root_node)
|
local node = get_primary_view(self.root_node)
|
||||||
if node then
|
if node then
|
||||||
return node.views[1]
|
return node.views[1]
|
||||||
end
|
end
|
||||||
|
@ -418,8 +453,8 @@ end
|
||||||
function RootView:open_doc(doc)
|
function RootView:open_doc(doc)
|
||||||
local node = self:get_active_node()
|
local node = self:get_active_node()
|
||||||
if node.locked then
|
if node.locked then
|
||||||
local default_view = self:get_document_view()
|
local default_view = self:get_primary_view()
|
||||||
assert(default_view, "Cannot find an unlocked node to open the document.")
|
assert(default_view, "internal error: cannot find original document node.")
|
||||||
core.set_active_view(default_view)
|
core.set_active_view(default_view)
|
||||||
node = self:get_active_node()
|
node = self:get_active_node()
|
||||||
end
|
end
|
||||||
|
@ -437,6 +472,11 @@ function RootView:open_doc(doc)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function RootView:close_all_docviews()
|
||||||
|
self.root_node:close_all_docviews()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function RootView:on_mouse_pressed(button, x, y, clicks)
|
function RootView:on_mouse_pressed(button, x, y, clicks)
|
||||||
local div = self.root_node:get_divider_overlapping_point(x, y)
|
local div = self.root_node:get_divider_overlapping_point(x, y)
|
||||||
if div then
|
if div then
|
||||||
|
|
|
@ -53,4 +53,10 @@ style.syntax["string"] = { common.color "#f7c95c" }
|
||||||
style.syntax["operator"] = { common.color "#93DDFA" }
|
style.syntax["operator"] = { common.color "#93DDFA" }
|
||||||
style.syntax["function"] = { common.color "#93DDFA" }
|
style.syntax["function"] = { common.color "#93DDFA" }
|
||||||
|
|
||||||
|
|
||||||
|
style.load = function(module_name)
|
||||||
|
package.loaded[module_name] = nil
|
||||||
|
require(module_name)
|
||||||
|
end
|
||||||
|
|
||||||
return style
|
return style
|
||||||
|
|
|
@ -1,13 +1,31 @@
|
||||||
-- put user settings here
|
-- put user settings here
|
||||||
-- this module will be loaded after everything else when the application starts
|
-- this module will be loaded after everything else when the application starts
|
||||||
|
-- it will be automatically reloaded when saved
|
||||||
|
|
||||||
local keymap = require "core.keymap"
|
local keymap = require "core.keymap"
|
||||||
local config = require "core.config"
|
local config = require "core.config"
|
||||||
local style = require "core.style"
|
local style = require "core.style"
|
||||||
|
|
||||||
-- light theme:
|
-- light theme:
|
||||||
-- require "colors.summer"
|
-- style.load("colors.summer")
|
||||||
|
|
||||||
-- key binding:
|
-- key binding:
|
||||||
-- keymap.add { ["ctrl+escape"] = "core:quit" }
|
-- keymap.add { ["ctrl+escape"] = "core:quit" }
|
||||||
|
|
||||||
|
-- customize fonts:
|
||||||
|
-- style.font = renderer.font.load(DATADIR .. "/fonts/font.ttf", 14 * SCALE)
|
||||||
|
-- style.code_font = renderer.font.load(DATADIR .. "/fonts/monospace.ttf", 13.5 * SCALE)
|
||||||
|
--
|
||||||
|
-- fonts used by the editor:
|
||||||
|
-- style.font : user interface
|
||||||
|
-- style.big_font : big text in welcome screen
|
||||||
|
-- style.icon_font : icons
|
||||||
|
-- style.code_font : code
|
||||||
|
--
|
||||||
|
-- the function to load the font accept a 3rd optional argument like:
|
||||||
|
--
|
||||||
|
-- {antialiasing="grayscale", hinting="full"}
|
||||||
|
--
|
||||||
|
-- possible values are:
|
||||||
|
-- antialiasing: grayscale, subpixel
|
||||||
|
-- hinting: none, slight, full
|
||||||
|
|
|
@ -140,6 +140,13 @@ then be loaded manually as needed by using the `require` function.
|
||||||
Plugins can be downloaded from the [plugins repository](https://github.com/rxi/lite-plugins).
|
Plugins can be downloaded from the [plugins repository](https://github.com/rxi/lite-plugins).
|
||||||
|
|
||||||
|
|
||||||
|
## Restarting the editor
|
||||||
|
|
||||||
|
If you modifies the user configuration file or some of the Lua implementation files you may
|
||||||
|
restart the editor using the command "Core: Restart".
|
||||||
|
All the application will be restarting by keeping the window that is already used.
|
||||||
|
|
||||||
|
|
||||||
## Color Themes
|
## Color Themes
|
||||||
Colors themes in lite are lua modules which overwrite the color fields of lite's
|
Colors themes in lite are lua modules which overwrite the color fields of lite's
|
||||||
`core.style` module.
|
`core.style` module.
|
||||||
|
|
|
@ -81,20 +81,17 @@ public:
|
||||||
void set_font_height(double height) {
|
void set_font_height(double height) {
|
||||||
const double scale_x = (m_prescale_x ? 100.0 : 1.0);
|
const double scale_x = (m_prescale_x ? 100.0 : 1.0);
|
||||||
m_feng.height(height);
|
m_feng.height(height);
|
||||||
if (m_subpixel) {
|
|
||||||
const int subpixel_scale = 3;
|
|
||||||
m_feng.width(height * scale_x * subpixel_scale);
|
|
||||||
} else {
|
|
||||||
m_feng.width(height * scale_x);
|
m_feng.width(height * scale_x);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template<class Rasterizer, class Scanline, class RenSolid>
|
template<class Rasterizer, class Scanline, class RenSolid>
|
||||||
void draw_codepoint(Rasterizer& ras, Scanline& sl,
|
void draw_codepoint(Rasterizer& ras, Scanline& sl,
|
||||||
RenSolid& ren_solid, const color_type color,
|
RenSolid& ren_solid, const color_type color,
|
||||||
int codepoint, double& x, double& y, int subpixel_scale)
|
int codepoint, double& x, double& y, const int subpixel_scale)
|
||||||
{
|
{
|
||||||
const double scale_x = (m_prescale_x ? 100.0 : 1.0);
|
const double scale_x = (m_prescale_x ? 100.0 : 1.0);
|
||||||
|
// Coefficient to scale back the glyph to the final scale.
|
||||||
|
const double cx_inv_scale = subpixel_scale / scale_x;
|
||||||
|
|
||||||
// Represent the delta in x scaled by scale_x.
|
// Represent the delta in x scaled by scale_x.
|
||||||
double x_delta = 0;
|
double x_delta = 0;
|
||||||
|
@ -114,15 +111,15 @@ public:
|
||||||
double ty = m_hinting ? floor(y + 0.5) : y;
|
double ty = m_hinting ? floor(y + 0.5) : y;
|
||||||
ras.reset();
|
ras.reset();
|
||||||
m_mtx.reset();
|
m_mtx.reset();
|
||||||
m_mtx *= agg::trans_affine_scaling(1.0 / scale_x, 1);
|
m_mtx *= agg::trans_affine_scaling(cx_inv_scale, 1);
|
||||||
m_mtx *= agg::trans_affine_translation(start_x + x_delta / scale_x, ty);
|
m_mtx *= agg::trans_affine_translation(start_x + cx_inv_scale * x_delta, ty);
|
||||||
ras.add_path(m_trans);
|
ras.add_path(m_trans);
|
||||||
ren_solid.color(color);
|
ren_solid.color(color);
|
||||||
agg::render_scanlines(ras, sl, ren_solid);
|
agg::render_scanlines(ras, sl, ren_solid);
|
||||||
}
|
}
|
||||||
|
|
||||||
y += glyph->advance_y;
|
y += glyph->advance_y;
|
||||||
x += (x_delta + glyph->advance_x) / scale_x;
|
x += cx_inv_scale * (x_delta + glyph->advance_x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +132,7 @@ public:
|
||||||
void render_codepoint(agg::rendering_buffer& ren_buf,
|
void render_codepoint(agg::rendering_buffer& ren_buf,
|
||||||
const color_type text_color,
|
const color_type text_color,
|
||||||
double& x, double& y,
|
double& x, double& y,
|
||||||
int codepoint, int subpixel_scale)
|
int codepoint, const int subpixel_scale)
|
||||||
{
|
{
|
||||||
if (!m_font_loaded) {
|
if (!m_font_loaded) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -9,6 +9,8 @@ else
|
||||||
datadir="$rundir/share/lite-xl"
|
datadir="$rundir/share/lite-xl"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
userdir="$(realpath "$rundir")"
|
||||||
|
|
||||||
if [ "$#" -lt 1 ]; then
|
if [ "$#" -lt 1 ]; then
|
||||||
echo "usage: $0 <build-dir>"
|
echo "usage: $0 <build-dir>"
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -16,7 +18,7 @@ fi
|
||||||
|
|
||||||
builddir="$1"
|
builddir="$1"
|
||||||
rm -fr "$rundir"
|
rm -fr "$rundir"
|
||||||
mkdir -p "$bindir" "$datadir"
|
mkdir -p "$bindir" "$datadir" "$userdir"
|
||||||
if [ -f "$builddir/src/lite" ]; then
|
if [ -f "$builddir/src/lite" ]; then
|
||||||
cp "$builddir/src/lite" "$bindir"
|
cp "$builddir/src/lite" "$bindir"
|
||||||
elif [ -f "$builddir/src/lite.exe" ]; then
|
elif [ -f "$builddir/src/lite.exe" ]; then
|
||||||
|
@ -28,4 +30,4 @@ fi
|
||||||
for module_name in core plugins colors fonts; do
|
for module_name in core plugins colors fonts; do
|
||||||
cp -r "data/$module_name" "$datadir"
|
cp -r "data/$module_name" "$datadir"
|
||||||
done
|
done
|
||||||
exec "$bindir/lite"
|
HOME="$userdir" USERPROFILE="$userdir" exec "$bindir/lite" "${@:2}"
|
||||||
|
|
19
src/main.c
19
src/main.c
|
@ -89,8 +89,9 @@ int main(int argc, char **argv) {
|
||||||
init_window_icon();
|
init_window_icon();
|
||||||
ren_init(window);
|
ren_init(window);
|
||||||
|
|
||||||
|
lua_State *L;
|
||||||
lua_State *L = luaL_newstate();
|
init_lua:
|
||||||
|
L = luaL_newstate();
|
||||||
luaL_openlibs(L);
|
luaL_openlibs(L);
|
||||||
api_load_libs(L);
|
api_load_libs(L);
|
||||||
|
|
||||||
|
@ -117,7 +118,7 @@ int main(int argc, char **argv) {
|
||||||
lua_setglobal(L, "EXEFILE");
|
lua_setglobal(L, "EXEFILE");
|
||||||
|
|
||||||
|
|
||||||
(void) luaL_dostring(L,
|
const char *init_lite_code = \
|
||||||
"local core\n"
|
"local core\n"
|
||||||
"xpcall(function()\n"
|
"xpcall(function()\n"
|
||||||
" SCALE = tonumber(os.getenv(\"LITE_SCALE\")) or SCALE\n"
|
" SCALE = tonumber(os.getenv(\"LITE_SCALE\")) or SCALE\n"
|
||||||
|
@ -153,8 +154,18 @@ int main(int argc, char **argv) {
|
||||||
" pcall(core.on_error, err)\n"
|
" pcall(core.on_error, err)\n"
|
||||||
" end\n"
|
" end\n"
|
||||||
" os.exit(1)\n"
|
" os.exit(1)\n"
|
||||||
"end)");
|
"end)\n"
|
||||||
|
"return core and core.restart_request\n";
|
||||||
|
|
||||||
|
if (luaL_loadstring(L, init_lite_code)) {
|
||||||
|
fprintf(stderr, "internal error when starting the application\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
lua_pcall(L, 0, 1, 0);
|
||||||
|
if (lua_toboolean(L, -1)) {
|
||||||
|
lua_close(L);
|
||||||
|
goto init_lua;
|
||||||
|
}
|
||||||
|
|
||||||
lua_close(L);
|
lua_close(L);
|
||||||
SDL_DestroyWindow(window);
|
SDL_DestroyWindow(window);
|
||||||
|
|
Loading…
Reference in New Issue