Merge branch 'master' into master-2.1
This commit is contained in:
commit
6229f74ccd
|
@ -149,7 +149,7 @@ command.add(nil, {
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["core:open-log"] = function()
|
["core:open-log"] = function()
|
||||||
local node = core.root_view:get_active_node()
|
local node = core.root_view:get_active_node_default()
|
||||||
node:add_view(LogView())
|
node:add_view(LogView())
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ function CommandView:new()
|
||||||
self.suggestions_height = 0
|
self.suggestions_height = 0
|
||||||
self.show_suggestions = true
|
self.show_suggestions = true
|
||||||
self.last_change_id = 0
|
self.last_change_id = 0
|
||||||
|
self.last_text = ""
|
||||||
self.gutter_width = 0
|
self.gutter_width = 0
|
||||||
self.gutter_text_brightness = 0
|
self.gutter_text_brightness = 0
|
||||||
self.selection_offset = 0
|
self.selection_offset = 0
|
||||||
|
@ -80,6 +81,7 @@ end
|
||||||
|
|
||||||
|
|
||||||
function CommandView:set_text(text, select)
|
function CommandView:set_text(text, select)
|
||||||
|
self.last_text = text
|
||||||
self.doc:remove(1, 1, math.huge, math.huge)
|
self.doc:remove(1, 1, math.huge, math.huge)
|
||||||
self.doc:text_input(text)
|
self.doc:text_input(text)
|
||||||
if select then
|
if select then
|
||||||
|
@ -161,6 +163,7 @@ function CommandView:exit(submitted, inexplicit)
|
||||||
if not submitted then cancel(not inexplicit) end
|
if not submitted then cancel(not inexplicit) end
|
||||||
self.show_suggestions = true
|
self.show_suggestions = true
|
||||||
self.save_suggestion = nil
|
self.save_suggestion = nil
|
||||||
|
self.last_text = ""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -198,35 +201,45 @@ function CommandView:update()
|
||||||
-- update suggestions if text has changed
|
-- update suggestions if text has changed
|
||||||
if self.last_change_id ~= self.doc:get_change_id() then
|
if self.last_change_id ~= self.doc:get_change_id() then
|
||||||
self:update_suggestions()
|
self:update_suggestions()
|
||||||
|
if self.suggestions[self.suggestion_idx] then
|
||||||
|
local current_text = self:get_text()
|
||||||
|
local suggested_text = self.suggestions[self.suggestion_idx].text or ""
|
||||||
|
if #self.last_text < #current_text and
|
||||||
|
string.find(suggested_text, current_text, 1, true) == 1 then
|
||||||
|
self:set_text(suggested_text)
|
||||||
|
self.doc:set_selection(1, #current_text + 1, 1, math.huge)
|
||||||
|
end
|
||||||
|
self.last_text = current_text
|
||||||
|
end
|
||||||
self.last_change_id = self.doc:get_change_id()
|
self.last_change_id = self.doc:get_change_id()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- update gutter text color brightness
|
-- update gutter text color brightness
|
||||||
self:move_towards("gutter_text_brightness", 0, 0.1)
|
self:move_towards("gutter_text_brightness", 0, 0.1, "commandview")
|
||||||
|
|
||||||
-- update gutter width
|
-- update gutter width
|
||||||
local dest = self:get_font():get_width(self.label) + style.padding.x
|
local dest = self:get_font():get_width(self.label) + style.padding.x
|
||||||
if self.size.y <= 0 then
|
if self.size.y <= 0 then
|
||||||
self.gutter_width = dest
|
self.gutter_width = dest
|
||||||
else
|
else
|
||||||
self:move_towards("gutter_width", dest)
|
self:move_towards("gutter_width", dest, nil, "commandview")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- update suggestions box height
|
-- update suggestions box height
|
||||||
local lh = self:get_suggestion_line_height()
|
local lh = self:get_suggestion_line_height()
|
||||||
local dest = self.show_suggestions and math.min(#self.suggestions, max_suggestions) * lh or 0
|
local dest = self.show_suggestions and math.min(#self.suggestions, max_suggestions) * lh or 0
|
||||||
self:move_towards("suggestions_height", dest)
|
self:move_towards("suggestions_height", dest, nil, "commandview")
|
||||||
|
|
||||||
-- update suggestion cursor offset
|
-- update suggestion cursor offset
|
||||||
local dest = math.min(self.suggestion_idx, max_suggestions) * self:get_suggestion_line_height()
|
local dest = math.min(self.suggestion_idx, max_suggestions) * self:get_suggestion_line_height()
|
||||||
self:move_towards("selection_offset", dest)
|
self:move_towards("selection_offset", dest, nil, "commandview")
|
||||||
|
|
||||||
-- update size based on whether this is the active_view
|
-- update size based on whether this is the active_view
|
||||||
local dest = 0
|
local dest = 0
|
||||||
if self == core.active_view then
|
if self == core.active_view then
|
||||||
dest = style.font:get_height() + style.padding.y * 2
|
dest = style.font:get_height() + style.padding.y * 2
|
||||||
end
|
end
|
||||||
self:move_towards(self.size, "y", dest)
|
self:move_towards(self.size, "y", dest, nil, "commandview")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -222,19 +222,58 @@ function common.bench(name, fn, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function common.serialize(val)
|
local function serialize(val, pretty, indent_str, escape, sort, limit, level)
|
||||||
|
local space = pretty and " " or ""
|
||||||
|
local indent = pretty and string.rep(indent_str, level) or ""
|
||||||
|
local newline = pretty and "\n" or ""
|
||||||
if type(val) == "string" then
|
if type(val) == "string" then
|
||||||
return string.format("%q", val)
|
local out = string.format("%q", val)
|
||||||
|
if escape then
|
||||||
|
out = string.gsub(out, "\\\n", "\\n")
|
||||||
|
out = string.gsub(out, "\\7", "\\a")
|
||||||
|
out = string.gsub(out, "\\8", "\\b")
|
||||||
|
out = string.gsub(out, "\\9", "\\t")
|
||||||
|
out = string.gsub(out, "\\11", "\\v")
|
||||||
|
out = string.gsub(out, "\\12", "\\f")
|
||||||
|
out = string.gsub(out, "\\13", "\\r")
|
||||||
|
end
|
||||||
|
return out
|
||||||
elseif type(val) == "table" then
|
elseif type(val) == "table" then
|
||||||
|
-- early exit
|
||||||
|
if level >= limit then return tostring(val) end
|
||||||
|
local next_indent = pretty and (indent .. indent_str) or ""
|
||||||
local t = {}
|
local t = {}
|
||||||
for k, v in pairs(val) do
|
for k, v in pairs(val) do
|
||||||
table.insert(t, "[" .. common.serialize(k) .. "]=" .. common.serialize(v))
|
table.insert(t,
|
||||||
|
next_indent .. "[" ..
|
||||||
|
serialize(k, pretty, indent_str, escape, sort, limit, level + 1) ..
|
||||||
|
"]" .. space .. "=" .. space .. serialize(v, pretty, indent_str, escape, sort, limit, level + 1))
|
||||||
end
|
end
|
||||||
return "{" .. table.concat(t, ",") .. "}"
|
if #t == 0 then return "{}" end
|
||||||
|
if sort then table.sort(t) end
|
||||||
|
return "{" .. newline .. table.concat(t, "," .. newline) .. newline .. indent .. "}"
|
||||||
end
|
end
|
||||||
return tostring(val)
|
return tostring(val)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Serialize `val` into a parsable string.
|
||||||
|
-- Available options
|
||||||
|
-- * pretty: enable pretty printing
|
||||||
|
-- * indent_str: indent to use (" " by default)
|
||||||
|
-- * escape: use normal escape characters instead of the ones used by string.format("%q", ...)
|
||||||
|
-- * sort: sort the keys inside tables
|
||||||
|
-- * limit: limit how deep to serialize
|
||||||
|
-- * initial_indent: the initial indentation level
|
||||||
|
function common.serialize(val, opts)
|
||||||
|
opts = opts or {}
|
||||||
|
local indent_str = opts.indent_str or " "
|
||||||
|
local initial_indent = opts.initial_indent or 0
|
||||||
|
local indent = opts.pretty and string.rep(indent_str, initial_indent) or ""
|
||||||
|
local limit = (opts.limit or math.huge) + initial_indent
|
||||||
|
return indent .. serialize(val, opts.pretty, indent_str,
|
||||||
|
opts.escape, opts.sort, limit, initial_indent)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function common.basename(path)
|
function common.basename(path)
|
||||||
-- a path should never end by / or \ except if it is '/' (unix root) or
|
-- a path should never end by / or \ except if it is '/' (unix root) or
|
||||||
|
|
|
@ -4,6 +4,7 @@ config.fps = 60
|
||||||
config.max_log_items = 80
|
config.max_log_items = 80
|
||||||
config.message_timeout = 5
|
config.message_timeout = 5
|
||||||
config.mouse_wheel_scroll = 50 * SCALE
|
config.mouse_wheel_scroll = 50 * SCALE
|
||||||
|
config.animate_drag_scroll = false
|
||||||
config.scroll_past_end = true
|
config.scroll_past_end = true
|
||||||
config.file_size_limit = 10
|
config.file_size_limit = 10
|
||||||
config.ignore_files = { "^%." }
|
config.ignore_files = { "^%." }
|
||||||
|
@ -21,6 +22,16 @@ config.tab_type = "soft"
|
||||||
config.line_limit = 80
|
config.line_limit = 80
|
||||||
config.max_project_files = 2000
|
config.max_project_files = 2000
|
||||||
config.transitions = true
|
config.transitions = true
|
||||||
|
config.disabled_transitions = {
|
||||||
|
scroll = false,
|
||||||
|
commandview = false,
|
||||||
|
contextmenu = false,
|
||||||
|
logview = false,
|
||||||
|
nagbar = false,
|
||||||
|
tabs = false,
|
||||||
|
tab_drag = false,
|
||||||
|
statusbar = false,
|
||||||
|
}
|
||||||
config.animation_rate = 1.0
|
config.animation_rate = 1.0
|
||||||
config.blink_period = 0.8
|
config.blink_period = 0.8
|
||||||
config.disable_blink = false
|
config.disable_blink = false
|
||||||
|
|
|
@ -5,6 +5,7 @@ local config = require "core.config"
|
||||||
local keymap = require "core.keymap"
|
local keymap = require "core.keymap"
|
||||||
local style = require "core.style"
|
local style = require "core.style"
|
||||||
local Object = require "core.object"
|
local Object = require "core.object"
|
||||||
|
local View = require "core.view"
|
||||||
|
|
||||||
local border_width = 1
|
local border_width = 1
|
||||||
local divider_width = 1
|
local divider_width = 1
|
||||||
|
@ -170,47 +171,30 @@ function ContextMenu:call_selected_item()
|
||||||
end
|
end
|
||||||
|
|
||||||
function ContextMenu:on_mouse_pressed(button, px, py, clicks)
|
function ContextMenu:on_mouse_pressed(button, px, py, clicks)
|
||||||
local selected = self:get_item_selected()
|
|
||||||
local caught = false
|
local caught = false
|
||||||
|
|
||||||
self:hide()
|
if self.show_context_menu then
|
||||||
if button == "left" then
|
if button == "left" then
|
||||||
if selected then
|
local selected = self:get_item_selected()
|
||||||
self:on_selected(selected)
|
if selected then
|
||||||
caught = true
|
self:on_selected(selected)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self:hide()
|
||||||
|
caught = true
|
||||||
|
else
|
||||||
|
if button == "right" then
|
||||||
|
caught = self:show(px, py)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
if button == "right" then
|
|
||||||
caught = self:show(px, py)
|
|
||||||
end
|
end
|
||||||
return caught
|
return caught
|
||||||
end
|
end
|
||||||
|
|
||||||
-- copied from core.docview
|
ContextMenu.move_towards = View.move_towards
|
||||||
function ContextMenu:move_towards(t, k, dest, rate)
|
|
||||||
if type(t) ~= "table" then
|
|
||||||
return self:move_towards(self, t, k, dest, rate)
|
|
||||||
end
|
|
||||||
local val = t[k]
|
|
||||||
if not config.transitions or math.abs(val - dest) < 0.5 then
|
|
||||||
t[k] = dest
|
|
||||||
else
|
|
||||||
rate = rate or 0.5
|
|
||||||
if config.fps ~= 60 or config.animation_rate ~= 1 then
|
|
||||||
local dt = 60 / config.fps
|
|
||||||
rate = 1 - common.clamp(1 - rate, 1e-8, 1 - 1e-8)^(config.animation_rate * dt)
|
|
||||||
end
|
|
||||||
t[k] = common.lerp(val, dest, rate)
|
|
||||||
end
|
|
||||||
if val ~= dest then
|
|
||||||
core.redraw = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ContextMenu:update()
|
function ContextMenu:update()
|
||||||
if self.show_context_menu then
|
if self.show_context_menu then
|
||||||
self:move_towards("height", self.items.height)
|
self:move_towards("height", self.items.height, nil, "contextmenu")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -294,7 +294,7 @@ end
|
||||||
|
|
||||||
-- The function below is needed to reload the project directories
|
-- The function below is needed to reload the project directories
|
||||||
-- when the project's module changes.
|
-- when the project's module changes.
|
||||||
local function rescan_project_directories()
|
function core.rescan_project_directories()
|
||||||
local save_project_dirs = {}
|
local save_project_dirs = {}
|
||||||
local n = #core.project_directories
|
local n = #core.project_directories
|
||||||
for i = 1, n do
|
for i = 1, n do
|
||||||
|
@ -574,7 +574,7 @@ function core.remove_project_directory(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function configure_borderless_window()
|
function core.configure_borderless_window()
|
||||||
system.set_window_bordered(not config.borderless)
|
system.set_window_bordered(not config.borderless)
|
||||||
core.title_view:configure_hit_test(config.borderless)
|
core.title_view:configure_hit_test(config.borderless)
|
||||||
core.title_view.visible = config.borderless
|
core.title_view.visible = config.borderless
|
||||||
|
@ -590,8 +590,8 @@ local function add_config_files_hooks()
|
||||||
doc_save(self, filename, abs_filename)
|
doc_save(self, filename, abs_filename)
|
||||||
if self.abs_filename == user_filename or self.abs_filename == module_filename then
|
if self.abs_filename == user_filename or self.abs_filename == module_filename then
|
||||||
reload_customizations()
|
reload_customizations()
|
||||||
rescan_project_directories()
|
core.rescan_project_directories()
|
||||||
configure_borderless_window()
|
core.configure_borderless_window()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -752,7 +752,7 @@ function core.init()
|
||||||
command.perform("core:open-log")
|
command.perform("core:open-log")
|
||||||
end
|
end
|
||||||
|
|
||||||
configure_borderless_window()
|
core.configure_borderless_window()
|
||||||
|
|
||||||
if #plugins_refuse_list.userdir.plugins > 0 or #plugins_refuse_list.datadir.plugins > 0 then
|
if #plugins_refuse_list.userdir.plugins > 0 or #plugins_refuse_list.datadir.plugins > 0 then
|
||||||
local opt = {
|
local opt = {
|
||||||
|
@ -815,7 +815,7 @@ local temp_file_counter = 0
|
||||||
|
|
||||||
function core.delete_temp_files(dir)
|
function core.delete_temp_files(dir)
|
||||||
dir = type(dir) == "string" and common.normalize_path(dir) or USERDIR
|
dir = type(dir) == "string" and common.normalize_path(dir) or USERDIR
|
||||||
for _, filename in ipairs(system.list_dir(dir)) do
|
for _, filename in ipairs(system.list_dir(dir) or {}) do
|
||||||
if filename:find(temp_file_prefix, 1, true) == 1 then
|
if filename:find(temp_file_prefix, 1, true) == 1 then
|
||||||
os.remove(dir .. PATHSEP .. filename)
|
os.remove(dir .. PATHSEP .. filename)
|
||||||
end
|
end
|
||||||
|
@ -905,6 +905,8 @@ function core.load_plugins()
|
||||||
end
|
end
|
||||||
table.sort(ordered)
|
table.sort(ordered)
|
||||||
|
|
||||||
|
|
||||||
|
local load_start = system.get_time()
|
||||||
for _, filename in ipairs(ordered) do
|
for _, filename in ipairs(ordered) do
|
||||||
local plugin_dir, basename = files[filename], filename:match("(.-)%.lua$") or filename
|
local plugin_dir, basename = files[filename], filename:match("(.-)%.lua$") or filename
|
||||||
local is_lua_file, version_match = check_plugin_version(plugin_dir .. '/' .. filename)
|
local is_lua_file, version_match = check_plugin_version(plugin_dir .. '/' .. filename)
|
||||||
|
@ -914,14 +916,16 @@ function core.load_plugins()
|
||||||
local list = refused_list[plugin_dir:find(USERDIR, 1, true) == 1 and 'userdir' or 'datadir'].plugins
|
local list = refused_list[plugin_dir:find(USERDIR, 1, true) == 1 and 'userdir' or 'datadir'].plugins
|
||||||
table.insert(list, filename)
|
table.insert(list, filename)
|
||||||
elseif config.plugins[basename] ~= false then
|
elseif config.plugins[basename] ~= false then
|
||||||
|
local start = system.get_time()
|
||||||
local ok = core.try(require, "plugins." .. basename)
|
local ok = core.try(require, "plugins." .. basename)
|
||||||
if ok then core.log_quiet("Loaded plugin %q from %s", basename, plugin_dir) end
|
if ok then core.log_quiet("Loaded plugin %q from %s in %.1fms", basename, plugin_dir, (system.get_time() - start)*1000) end
|
||||||
if not ok then
|
if not ok then
|
||||||
no_errors = false
|
no_errors = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
core.log_quiet("Loaded all plugins in %.1fms", (system.get_time() - load_start)*1000)
|
||||||
return no_errors, refused_list
|
return no_errors, refused_list
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1136,6 +1140,8 @@ function core.on_event(type, ...)
|
||||||
end
|
end
|
||||||
elseif type == "mousereleased" then
|
elseif type == "mousereleased" then
|
||||||
core.root_view:on_mouse_released(...)
|
core.root_view:on_mouse_released(...)
|
||||||
|
elseif type == "mouseleft" then
|
||||||
|
core.root_view:on_mouse_left()
|
||||||
elseif type == "mousewheel" then
|
elseif type == "mousewheel" then
|
||||||
if not core.root_view:on_mouse_wheel(...) then
|
if not core.root_view:on_mouse_wheel(...) then
|
||||||
did_keymap = keymap.on_mouse_wheel(...)
|
did_keymap = keymap.on_mouse_wheel(...)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
local core = require "core"
|
||||||
local command = require "core.command"
|
local command = require "core.command"
|
||||||
local config = require "core.config"
|
local config = require "core.config"
|
||||||
local keymap = {}
|
local keymap = {}
|
||||||
|
@ -42,7 +43,7 @@ function keymap.add(map, overwrite)
|
||||||
if macos then
|
if macos then
|
||||||
stroke = stroke:gsub("%f[%a]ctrl%f[%A]", "cmd")
|
stroke = stroke:gsub("%f[%a]ctrl%f[%A]", "cmd")
|
||||||
end
|
end
|
||||||
if type(commands) == "string" then
|
if type(commands) == "string" or type(commands) == "function" then
|
||||||
commands = { commands }
|
commands = { commands }
|
||||||
end
|
end
|
||||||
if overwrite then
|
if overwrite then
|
||||||
|
@ -103,7 +104,16 @@ function keymap.on_key_pressed(k, ...)
|
||||||
local commands, performed = keymap.map[stroke]
|
local commands, performed = keymap.map[stroke]
|
||||||
if commands then
|
if commands then
|
||||||
for _, cmd in ipairs(commands) do
|
for _, cmd in ipairs(commands) do
|
||||||
performed = command.perform(cmd, ...)
|
if type(cmd) == "function" then
|
||||||
|
local ok, res = core.try(cmd, ...)
|
||||||
|
if ok then
|
||||||
|
performed = not (res == false)
|
||||||
|
else
|
||||||
|
performed = true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
performed = command.perform(cmd, ...)
|
||||||
|
end
|
||||||
if performed then break end
|
if performed then break end
|
||||||
end
|
end
|
||||||
return performed
|
return performed
|
||||||
|
|
|
@ -118,13 +118,13 @@ function LogView:update()
|
||||||
|
|
||||||
local expanding = self.expanding[1]
|
local expanding = self.expanding[1]
|
||||||
if expanding then
|
if expanding then
|
||||||
self:move_towards(expanding, "current", expanding.target)
|
self:move_towards(expanding, "current", expanding.target, nil, "logview")
|
||||||
if expanding.current == expanding.target then
|
if expanding.current == expanding.target then
|
||||||
table.remove(self.expanding, 1)
|
table.remove(self.expanding, 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:move_towards("yoffset", 0)
|
self:move_towards("yoffset", 0, nil, "logview")
|
||||||
|
|
||||||
LogView.super.update(self)
|
LogView.super.update(self)
|
||||||
end
|
end
|
||||||
|
|
|
@ -170,10 +170,10 @@ function NagView:update()
|
||||||
NagView.super.update(self)
|
NagView.super.update(self)
|
||||||
|
|
||||||
if self.visible and core.active_view == self and self.title then
|
if self.visible and core.active_view == self and self.title then
|
||||||
self:move_towards(self, "show_height", self:get_target_height())
|
self:move_towards(self, "show_height", self:get_target_height(), nil, "nagbar")
|
||||||
self:move_towards(self, "underline_progress", 1)
|
self:move_towards(self, "underline_progress", 1, nil, "nagbar")
|
||||||
else
|
else
|
||||||
self:move_towards(self, "show_height", 0)
|
self:move_towards(self, "show_height", 0, nil, "nagbar")
|
||||||
if self.show_height <= 0 then
|
if self.show_height <= 0 then
|
||||||
self.title = nil
|
self.title = nil
|
||||||
self.message = nil
|
self.message = nil
|
||||||
|
|
|
@ -51,6 +51,15 @@ function Node:on_mouse_released(...)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function Node:on_mouse_left()
|
||||||
|
if self.type == "leaf" then
|
||||||
|
self.active_view:on_mouse_left()
|
||||||
|
else
|
||||||
|
self:propagate("on_mouse_left")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function Node:consume(node)
|
function Node:consume(node)
|
||||||
for k, _ in pairs(self) do self[k] = nil end
|
for k, _ in pairs(self) do self[k] = nil end
|
||||||
for k, v in pairs(node) do self[k] = v end
|
for k, v in pairs(node) do self[k] = v end
|
||||||
|
@ -160,8 +169,12 @@ end
|
||||||
|
|
||||||
function Node:set_active_view(view)
|
function Node:set_active_view(view)
|
||||||
assert(self.type == "leaf", "Tried to set active view on non-leaf node")
|
assert(self.type == "leaf", "Tried to set active view on non-leaf node")
|
||||||
|
local last_active_view = self.active_view
|
||||||
self.active_view = view
|
self.active_view = view
|
||||||
core.set_active_view(view)
|
core.set_active_view(view)
|
||||||
|
if last_active_view and last_active_view ~= view then
|
||||||
|
last_active_view:on_mouse_left()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -468,8 +481,8 @@ function Node:update()
|
||||||
end
|
end
|
||||||
self:tab_hovered_update(self.hovered.x, self.hovered.y)
|
self:tab_hovered_update(self.hovered.x, self.hovered.y)
|
||||||
local tab_width = self:target_tab_width()
|
local tab_width = self:target_tab_width()
|
||||||
self:move_towards("tab_shift", tab_width * (self.tab_offset - 1))
|
self:move_towards("tab_shift", tab_width * (self.tab_offset - 1), nil, "tabs")
|
||||||
self:move_towards("tab_width", tab_width)
|
self:move_towards("tab_width", tab_width, nil, "tabs")
|
||||||
else
|
else
|
||||||
self.a:update()
|
self.a:update()
|
||||||
self.b:update()
|
self.b:update()
|
||||||
|
|
|
@ -256,8 +256,13 @@ function RootView:on_mouse_moved(x, y, dx, dy)
|
||||||
|
|
||||||
self.root_node:on_mouse_moved(x, y, dx, dy)
|
self.root_node:on_mouse_moved(x, y, dx, dy)
|
||||||
|
|
||||||
|
local last_overlapping_node = self.overlapping_node
|
||||||
self.overlapping_node = self.root_node:get_child_overlapping_point(x, y)
|
self.overlapping_node = self.root_node:get_child_overlapping_point(x, y)
|
||||||
|
|
||||||
|
if last_overlapping_node and last_overlapping_node ~= self.overlapping_node then
|
||||||
|
last_overlapping_node:on_mouse_left()
|
||||||
|
end
|
||||||
|
|
||||||
local div = self.root_node:get_divider_overlapping_point(x, y)
|
local div = self.root_node:get_divider_overlapping_point(x, y)
|
||||||
local tab_index = self.overlapping_node and self.overlapping_node:get_tab_overlapping_point(x, y)
|
local tab_index = self.overlapping_node and self.overlapping_node:get_tab_overlapping_point(x, y)
|
||||||
if self.overlapping_node and self.overlapping_node:get_scroll_button_index(x, y) then
|
if self.overlapping_node and self.overlapping_node:get_scroll_button_index(x, y) then
|
||||||
|
@ -272,6 +277,13 @@ function RootView:on_mouse_moved(x, y, dx, dy)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function RootView:on_mouse_left()
|
||||||
|
if self.overlapping_node then
|
||||||
|
self.overlapping_node:on_mouse_left()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function RootView:on_file_dropped(filename, x, y)
|
function RootView:on_file_dropped(filename, x, y)
|
||||||
local node = self.root_node:get_child_overlapping_point(x, y)
|
local node = self.root_node:get_child_overlapping_point(x, y)
|
||||||
return node and node.active_view:on_file_dropped(filename, x, y)
|
return node and node.active_view:on_file_dropped(filename, x, y)
|
||||||
|
@ -297,12 +309,12 @@ end
|
||||||
|
|
||||||
|
|
||||||
function RootView:interpolate_drag_overlay(overlay)
|
function RootView:interpolate_drag_overlay(overlay)
|
||||||
self:move_towards(overlay, "x", overlay.to.x)
|
self:move_towards(overlay, "x", overlay.to.x, nil, "tab_drag")
|
||||||
self:move_towards(overlay, "y", overlay.to.y)
|
self:move_towards(overlay, "y", overlay.to.y, nil, "tab_drag")
|
||||||
self:move_towards(overlay, "w", overlay.to.w)
|
self:move_towards(overlay, "w", overlay.to.w, nil, "tab_drag")
|
||||||
self:move_towards(overlay, "h", overlay.to.h)
|
self:move_towards(overlay, "h", overlay.to.h, nil, "tab_drag")
|
||||||
|
|
||||||
self:move_towards(overlay, "opacity", overlay.visible and 100 or 0)
|
self:move_towards(overlay, "opacity", overlay.visible and 100 or 0, nil, "tab_drag")
|
||||||
overlay.color[4] = overlay.base_color[4] * overlay.opacity / 100
|
overlay.color[4] = overlay.base_color[4] * overlay.opacity / 100
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ table.unpack = table.unpack or unpack
|
||||||
|
|
||||||
bit32 = bit32 or require "core.bit"
|
bit32 = bit32 or require "core.bit"
|
||||||
|
|
||||||
|
require "core.utf8string"
|
||||||
|
|
||||||
-- Because AppImages change the working directory before running the executable,
|
-- Because AppImages change the working directory before running the executable,
|
||||||
-- we need to change it back to the original one.
|
-- we need to change it back to the original one.
|
||||||
-- https://github.com/AppImage/AppImageKit/issues/172
|
-- https://github.com/AppImage/AppImageKit/issues/172
|
||||||
|
|
|
@ -1042,14 +1042,14 @@ function StatusView:update()
|
||||||
if not self.visible and self.size.y <= 0 then
|
if not self.visible and self.size.y <= 0 then
|
||||||
return
|
return
|
||||||
elseif not self.visible and self.size.y > 0 then
|
elseif not self.visible and self.size.y > 0 then
|
||||||
self:move_towards(self.size, "y", 0)
|
self:move_towards(self.size, "y", 0, nil, "statusbar")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local height = style.font:get_height() + style.padding.y * 2;
|
local height = style.font:get_height() + style.padding.y * 2;
|
||||||
|
|
||||||
if self.size.y + 1 < height then
|
if self.size.y + 1 < height then
|
||||||
self:move_towards(self.size, "y", height)
|
self:move_towards(self.size, "y", height, nil, "statusbar")
|
||||||
else
|
else
|
||||||
self.size.y = height
|
self.size.y = height
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,7 +6,7 @@ local tokenizer = {}
|
||||||
local function push_token(t, type, text)
|
local function push_token(t, type, text)
|
||||||
local prev_type = t[#t-1]
|
local prev_type = t[#t-1]
|
||||||
local prev_text = t[#t]
|
local prev_text = t[#t]
|
||||||
if prev_type and (prev_type == type or prev_text:find("^%s*$")) then
|
if prev_type and (prev_type == type or prev_text:ufind("^%s*$")) then
|
||||||
t[#t-1] = type
|
t[#t-1] = type
|
||||||
t[#t] = prev_text .. text
|
t[#t] = prev_text .. text
|
||||||
else
|
else
|
||||||
|
@ -38,12 +38,12 @@ local function push_tokens(t, syn, pattern, full_text, find_results)
|
||||||
local fin = find_results[i + 1] - 1
|
local fin = find_results[i + 1] - 1
|
||||||
local type = pattern.type[i - 2]
|
local type = pattern.type[i - 2]
|
||||||
-- ↑ (i - 2) to convert from [3; n] to [1; n]
|
-- ↑ (i - 2) to convert from [3; n] to [1; n]
|
||||||
local text = full_text:sub(start, fin)
|
local text = full_text:usub(start, fin)
|
||||||
push_token(t, syn.symbols[text] or type, text)
|
push_token(t, syn.symbols[text] or type, text)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local start, fin = find_results[1], find_results[2]
|
local start, fin = find_results[1], find_results[2]
|
||||||
local text = full_text:sub(start, fin)
|
local text = full_text:usub(start, fin)
|
||||||
push_token(t, syn.symbols[text] or pattern.type, text)
|
push_token(t, syn.symbols[text] or pattern.type, text)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -52,12 +52,12 @@ end
|
||||||
-- State is a 32-bit number that is four separate bytes, illustrating how many
|
-- State is a 32-bit number that is four separate bytes, illustrating how many
|
||||||
-- differnet delimiters we have open, and which subsyntaxes we have active.
|
-- differnet delimiters we have open, and which subsyntaxes we have active.
|
||||||
-- At most, there are 3 subsyntaxes active at the same time. Beyond that,
|
-- At most, there are 3 subsyntaxes active at the same time. Beyond that,
|
||||||
-- does not support further highlighting.
|
-- does not support further highlighting.
|
||||||
|
|
||||||
-- You can think of it as a maximum 4 integer (0-255) stack. It always has
|
-- You can think of it as a maximum 4 integer (0-255) stack. It always has
|
||||||
-- 1 integer in it. Calling `push_subsyntax` increases the stack depth. Calling
|
-- 1 integer in it. Calling `push_subsyntax` increases the stack depth. Calling
|
||||||
-- `pop_subsyntax` decreases it. The integers represent the index of a pattern
|
-- `pop_subsyntax` decreases it. The integers represent the index of a pattern
|
||||||
-- that we're following in the syntax. The top of the stack can be any valid
|
-- that we're following in the syntax. The top of the stack can be any valid
|
||||||
-- pattern index, any integer lower in the stack must represent a pattern that
|
-- pattern index, any integer lower in the stack must represent a pattern that
|
||||||
-- specifies a subsyntax.
|
-- specifies a subsyntax.
|
||||||
|
|
||||||
|
@ -92,6 +92,9 @@ local function retrieve_syntax_state(incoming_syntax, state)
|
||||||
return current_syntax, subsyntax_info, current_pattern_idx, current_level
|
return current_syntax, subsyntax_info, current_pattern_idx, current_level
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param incoming_syntax table
|
||||||
|
---@param text string
|
||||||
|
---@param state integer
|
||||||
function tokenizer.tokenize(incoming_syntax, text, state)
|
function tokenizer.tokenize(incoming_syntax, text, state)
|
||||||
local res = {}
|
local res = {}
|
||||||
local i = 1
|
local i = 1
|
||||||
|
@ -102,22 +105,22 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
||||||
|
|
||||||
state = state or 0
|
state = state or 0
|
||||||
-- incoming_syntax : the parent syntax of the file.
|
-- incoming_syntax : the parent syntax of the file.
|
||||||
-- state : a 32-bit number representing syntax state (see above)
|
-- state : a 32-bit number representing syntax state (see above)
|
||||||
|
|
||||||
-- current_syntax : the syntax we're currently in.
|
-- current_syntax : the syntax we're currently in.
|
||||||
-- subsyntax_info : info about the delimiters of this subsyntax.
|
-- subsyntax_info : info about the delimiters of this subsyntax.
|
||||||
-- current_pattern_idx: the index of the pattern we're on for this syntax.
|
-- current_pattern_idx: the index of the pattern we're on for this syntax.
|
||||||
-- current_level : how many subsyntaxes deep we are.
|
-- current_level : how many subsyntaxes deep we are.
|
||||||
local current_syntax, subsyntax_info, current_pattern_idx, current_level =
|
local current_syntax, subsyntax_info, current_pattern_idx, current_level =
|
||||||
retrieve_syntax_state(incoming_syntax, state)
|
retrieve_syntax_state(incoming_syntax, state)
|
||||||
|
|
||||||
-- Should be used to set the state variable. Don't modify it directly.
|
-- Should be used to set the state variable. Don't modify it directly.
|
||||||
local function set_subsyntax_pattern_idx(pattern_idx)
|
local function set_subsyntax_pattern_idx(pattern_idx)
|
||||||
current_pattern_idx = pattern_idx
|
current_pattern_idx = pattern_idx
|
||||||
state = bit32.replace(state, pattern_idx, current_level*8, 8)
|
state = bit32.replace(state, pattern_idx, current_level*8, 8)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function push_subsyntax(entering_syntax, pattern_idx)
|
local function push_subsyntax(entering_syntax, pattern_idx)
|
||||||
set_subsyntax_pattern_idx(pattern_idx)
|
set_subsyntax_pattern_idx(pattern_idx)
|
||||||
current_level = current_level + 1
|
current_level = current_level + 1
|
||||||
|
@ -126,15 +129,15 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
||||||
entering_syntax.syntax or syntax.get(entering_syntax.syntax)
|
entering_syntax.syntax or syntax.get(entering_syntax.syntax)
|
||||||
current_pattern_idx = 0
|
current_pattern_idx = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
local function pop_subsyntax()
|
local function pop_subsyntax()
|
||||||
set_subsyntax_pattern_idx(0)
|
set_subsyntax_pattern_idx(0)
|
||||||
current_level = current_level - 1
|
current_level = current_level - 1
|
||||||
set_subsyntax_pattern_idx(0)
|
set_subsyntax_pattern_idx(0)
|
||||||
current_syntax, subsyntax_info, current_pattern_idx, current_level =
|
current_syntax, subsyntax_info, current_pattern_idx, current_level =
|
||||||
retrieve_syntax_state(incoming_syntax, state)
|
retrieve_syntax_state(incoming_syntax, state)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function find_text(text, p, offset, at_start, close)
|
local function find_text(text, p, offset, at_start, close)
|
||||||
local target, res = p.pattern or p.regex, { 1, offset - 1 }
|
local target, res = p.pattern or p.regex, { 1, offset - 1 }
|
||||||
local p_idx = close and 2 or 1
|
local p_idx = close and 2 or 1
|
||||||
|
@ -143,14 +146,14 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
||||||
if p.whole_line == nil then p.whole_line = { } end
|
if p.whole_line == nil then p.whole_line = { } end
|
||||||
if p.whole_line[p_idx] == nil then
|
if p.whole_line[p_idx] == nil then
|
||||||
-- Match patterns that start with '^'
|
-- Match patterns that start with '^'
|
||||||
p.whole_line[p_idx] = code:match("^%^") and true or false
|
p.whole_line[p_idx] = code:umatch("^%^") and true or false
|
||||||
if p.whole_line[p_idx] then
|
if p.whole_line[p_idx] then
|
||||||
-- Remove '^' from the beginning of the pattern
|
-- Remove '^' from the beginning of the pattern
|
||||||
if type(target) == "table" then
|
if type(target) == "table" then
|
||||||
target[p_idx] = code:sub(2)
|
target[p_idx] = code:usub(2)
|
||||||
else
|
else
|
||||||
p.pattern = p.pattern and code:sub(2)
|
p.pattern = p.pattern and code:usub(2)
|
||||||
p.regex = p.regex and code:sub(2)
|
p.regex = p.regex and code:usub(2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -170,7 +173,7 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
||||||
while text:byte(next) and common.is_utf8_cont(text, next) do
|
while text:byte(next) and common.is_utf8_cont(text, next) do
|
||||||
next = next + 1
|
next = next + 1
|
||||||
end
|
end
|
||||||
res = p.pattern and { text:find((at_start or p.whole_line[p_idx]) and "^" .. code or code, next) }
|
res = p.pattern and { text:ufind((at_start or p.whole_line[p_idx]) and "^" .. code or code, next) }
|
||||||
or { regex.match(code, text, next, (at_start or p.whole_line[p_idx]) and regex.ANCHORED or 0) }
|
or { regex.match(code, text, next, (at_start or p.whole_line[p_idx]) and regex.ANCHORED or 0) }
|
||||||
if res[1] and close and target[3] then
|
if res[1] and close and target[3] then
|
||||||
local count = 0
|
local count = 0
|
||||||
|
@ -185,7 +188,7 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
||||||
until not res[1] or not close or not target[3]
|
until not res[1] or not close or not target[3]
|
||||||
return table.unpack(res)
|
return table.unpack(res)
|
||||||
end
|
end
|
||||||
|
|
||||||
while i <= #text do
|
while i <= #text do
|
||||||
-- continue trying to match the end pattern of a pair if we have a state set
|
-- continue trying to match the end pattern of a pair if we have a state set
|
||||||
if current_pattern_idx > 0 then
|
if current_pattern_idx > 0 then
|
||||||
|
@ -198,12 +201,12 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
||||||
-- precedence over ending the delimiter in the subsyntax.
|
-- precedence over ending the delimiter in the subsyntax.
|
||||||
if subsyntax_info then
|
if subsyntax_info then
|
||||||
local ss, se = find_text(text, subsyntax_info, i, false, true)
|
local ss, se = find_text(text, subsyntax_info, i, false, true)
|
||||||
-- If we find that we end the subsyntax before the
|
-- If we find that we end the subsyntax before the
|
||||||
-- delimiter, push the token, and signal we shouldn't
|
-- delimiter, push the token, and signal we shouldn't
|
||||||
-- treat the bit after as a token to be normally parsed
|
-- treat the bit after as a token to be normally parsed
|
||||||
-- (as it's the syntax delimiter).
|
-- (as it's the syntax delimiter).
|
||||||
if ss and (s == nil or ss < s) then
|
if ss and (s == nil or ss < s) then
|
||||||
push_token(res, p.type, text:sub(i, ss - 1))
|
push_token(res, p.type, text:usub(i, ss - 1))
|
||||||
i = ss
|
i = ss
|
||||||
cont = false
|
cont = false
|
||||||
end
|
end
|
||||||
|
@ -212,11 +215,11 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
||||||
-- continue on as normal.
|
-- continue on as normal.
|
||||||
if cont then
|
if cont then
|
||||||
if s then
|
if s then
|
||||||
push_token(res, p.type, text:sub(i, e))
|
push_token(res, p.type, text:usub(i, e))
|
||||||
set_subsyntax_pattern_idx(0)
|
set_subsyntax_pattern_idx(0)
|
||||||
i = e + 1
|
i = e + 1
|
||||||
else
|
else
|
||||||
push_token(res, p.type, text:sub(i))
|
push_token(res, p.type, text:usub(i))
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -227,7 +230,7 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
||||||
if subsyntax_info then
|
if subsyntax_info then
|
||||||
local s, e = find_text(text, subsyntax_info, i, true, true)
|
local s, e = find_text(text, subsyntax_info, i, true, true)
|
||||||
if s then
|
if s then
|
||||||
push_token(res, subsyntax_info.type, text:sub(i, e))
|
push_token(res, subsyntax_info.type, text:usub(i, e))
|
||||||
-- On finding unescaped delimiter, pop it.
|
-- On finding unescaped delimiter, pop it.
|
||||||
pop_subsyntax()
|
pop_subsyntax()
|
||||||
i = e + 1
|
i = e + 1
|
||||||
|
@ -246,7 +249,7 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
||||||
-- If we have a subsyntax, push that onto the subsyntax stack.
|
-- If we have a subsyntax, push that onto the subsyntax stack.
|
||||||
if p.syntax then
|
if p.syntax then
|
||||||
push_subsyntax(p, n)
|
push_subsyntax(p, n)
|
||||||
else
|
else
|
||||||
set_subsyntax_pattern_idx(n)
|
set_subsyntax_pattern_idx(n)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -264,7 +267,7 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
||||||
while text:byte(i + n + 1) and common.is_utf8_cont(text, i + n + 1) do
|
while text:byte(i + n + 1) and common.is_utf8_cont(text, i + n + 1) do
|
||||||
n = n + 1
|
n = n + 1
|
||||||
end
|
end
|
||||||
push_token(res, "normal", text:sub(i, i + n))
|
push_token(res, "normal", text:usub(i, i + n))
|
||||||
i = i + n + 1
|
i = i + n + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- inject utf8 functions to strings
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
string.ubyte = utf8.byte
|
||||||
|
string.uchar = utf8.char
|
||||||
|
string.ufind = utf8.find
|
||||||
|
string.ugmatch = utf8.gmatch
|
||||||
|
string.ugsub = utf8.gsub
|
||||||
|
string.ulen = utf8.len
|
||||||
|
string.ulower = utf8.lower
|
||||||
|
string.umatch = utf8.match
|
||||||
|
string.ureverse = utf8.reverse
|
||||||
|
string.usub = utf8.sub
|
||||||
|
string.uupper = utf8.upper
|
||||||
|
|
||||||
|
string.uescape = utf8.escape
|
||||||
|
string.ucharpos = utf8.charpos
|
||||||
|
string.unext = utf8.next
|
||||||
|
string.uinsert = utf8.insert
|
||||||
|
string.uremove = utf8.remove
|
||||||
|
string.uwidth = utf8.width
|
||||||
|
string.uwidthindex = utf8.widthindex
|
||||||
|
string.utitle = utf8.title
|
||||||
|
string.ufold = utf8.fold
|
||||||
|
string.uncasecmp = utf8.ncasecmp
|
||||||
|
|
||||||
|
string.uoffset = utf8.offset
|
||||||
|
string.ucodepoint = utf8.codepoint
|
||||||
|
string.ucodes = utf8.codes
|
|
@ -27,13 +27,13 @@ function View:new()
|
||||||
self.scrollbar_alpha = { value = 0, to = 0 }
|
self.scrollbar_alpha = { value = 0, to = 0 }
|
||||||
end
|
end
|
||||||
|
|
||||||
function View:move_towards(t, k, dest, rate)
|
function View:move_towards(t, k, dest, rate, name)
|
||||||
if type(t) ~= "table" then
|
if type(t) ~= "table" then
|
||||||
return self:move_towards(self, t, k, dest, rate)
|
return self:move_towards(self, t, k, dest, rate, name)
|
||||||
end
|
end
|
||||||
local val = t[k]
|
local val = t[k]
|
||||||
local diff = math.abs(val - dest)
|
local diff = math.abs(val - dest)
|
||||||
if not config.transitions or diff < 0.5 then
|
if not config.transitions or diff < 0.5 or config.disabled_transitions[name] then
|
||||||
t[k] = dest
|
t[k] = dest
|
||||||
else
|
else
|
||||||
rate = rate or 0.5
|
rate = rate or 0.5
|
||||||
|
@ -134,12 +134,22 @@ function View:on_mouse_moved(x, y, dx, dy)
|
||||||
if self.dragging_scrollbar then
|
if self.dragging_scrollbar then
|
||||||
local delta = self:get_scrollable_size() / self.size.y * dy
|
local delta = self:get_scrollable_size() / self.size.y * dy
|
||||||
self.scroll.to.y = self.scroll.to.y + delta
|
self.scroll.to.y = self.scroll.to.y + delta
|
||||||
|
if not config.animate_drag_scroll then
|
||||||
|
self:clamp_scroll_position()
|
||||||
|
self.scroll.y = self.scroll.to.y
|
||||||
|
end
|
||||||
end
|
end
|
||||||
self.hovered_scrollbar = self:scrollbar_overlaps_point(x, y)
|
self.hovered_scrollbar = self:scrollbar_overlaps_point(x, y)
|
||||||
self.hovered_scrollbar_track = self.hovered_scrollbar or self:scrollbar_track_overlaps_point(x, y)
|
self.hovered_scrollbar_track = self.hovered_scrollbar or self:scrollbar_track_overlaps_point(x, y)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function View:on_mouse_left()
|
||||||
|
self.hovered_scrollbar = false
|
||||||
|
self.hovered_scrollbar_track = false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function View:on_file_dropped(filename, x, y)
|
function View:on_file_dropped(filename, x, y)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
@ -176,28 +186,28 @@ end
|
||||||
function View:update_scrollbar()
|
function View:update_scrollbar()
|
||||||
local x, y, w, h = self:get_scrollbar_rect()
|
local x, y, w, h = self:get_scrollbar_rect()
|
||||||
self.scrollbar.w.to.thumb = w
|
self.scrollbar.w.to.thumb = w
|
||||||
self:move_towards(self.scrollbar.w, "thumb", self.scrollbar.w.to.thumb, 0.3)
|
self:move_towards(self.scrollbar.w, "thumb", self.scrollbar.w.to.thumb, 0.3, "scroll")
|
||||||
self.scrollbar.x.thumb = x + w - self.scrollbar.w.thumb
|
self.scrollbar.x.thumb = x + w - self.scrollbar.w.thumb
|
||||||
self.scrollbar.y.thumb = y
|
self.scrollbar.y.thumb = y
|
||||||
self.scrollbar.h.thumb = h
|
self.scrollbar.h.thumb = h
|
||||||
|
|
||||||
local x, y, w, h = self:get_scrollbar_track_rect()
|
local x, y, w, h = self:get_scrollbar_track_rect()
|
||||||
self.scrollbar.w.to.track = w
|
self.scrollbar.w.to.track = w
|
||||||
self:move_towards(self.scrollbar.w, "track", self.scrollbar.w.to.track, 0.3)
|
self:move_towards(self.scrollbar.w, "track", self.scrollbar.w.to.track, 0.3, "scroll")
|
||||||
self.scrollbar.x.track = x + w - self.scrollbar.w.track
|
self.scrollbar.x.track = x + w - self.scrollbar.w.track
|
||||||
self.scrollbar.y.track = y
|
self.scrollbar.y.track = y
|
||||||
self.scrollbar.h.track = h
|
self.scrollbar.h.track = h
|
||||||
|
|
||||||
-- we use 100 for a smoother transition
|
-- we use 100 for a smoother transition
|
||||||
self.scrollbar_alpha.to = (self.hovered_scrollbar_track or self.dragging_scrollbar) and 100 or 0
|
self.scrollbar_alpha.to = (self.hovered_scrollbar_track or self.dragging_scrollbar) and 100 or 0
|
||||||
self:move_towards(self.scrollbar_alpha, "value", self.scrollbar_alpha.to, 0.3)
|
self:move_towards(self.scrollbar_alpha, "value", self.scrollbar_alpha.to, 0.3, "scroll")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function View:update()
|
function View:update()
|
||||||
self:clamp_scroll_position()
|
self:clamp_scroll_position()
|
||||||
self:move_towards(self.scroll, "x", self.scroll.to.x, 0.3)
|
self:move_towards(self.scroll, "x", self.scroll.to.x, 0.3, "scroll")
|
||||||
self:move_towards(self.scroll, "y", self.scroll.to.y, 0.3)
|
self:move_towards(self.scroll, "y", self.scroll.to.y, 0.3, "scroll")
|
||||||
|
|
||||||
self:update_scrollbar()
|
self:update_scrollbar()
|
||||||
end
|
end
|
||||||
|
|
|
@ -242,14 +242,14 @@ function TreeView:update()
|
||||||
self.size.x = dest
|
self.size.x = dest
|
||||||
self.init_size = false
|
self.init_size = false
|
||||||
else
|
else
|
||||||
self:move_towards(self.size, "x", dest)
|
self:move_towards(self.size, "x", dest, nil, "treeview")
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self.visible then return end
|
if not self.visible then return end
|
||||||
|
|
||||||
local duration = system.get_time() - self.tooltip.begin
|
local duration = system.get_time() - self.tooltip.begin
|
||||||
if self.hovered_item and self.tooltip.x and duration > tooltip_delay then
|
if self.hovered_item and self.tooltip.x and duration > tooltip_delay then
|
||||||
self:move_towards(self.tooltip, "alpha", tooltip_alpha, tooltip_alpha_rate)
|
self:move_towards(self.tooltip, "alpha", tooltip_alpha, tooltip_alpha_rate, "treeview")
|
||||||
else
|
else
|
||||||
self.tooltip.alpha = 0
|
self.tooltip.alpha = 0
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
---@meta
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.byte
|
||||||
|
---@param s string
|
||||||
|
---@param i? integer
|
||||||
|
---@param j? integer
|
||||||
|
---@return integer
|
||||||
|
---@return ...
|
||||||
|
function string.ubyte(s, i, j) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.char
|
||||||
|
---@param byte integer
|
||||||
|
---@param ... integer
|
||||||
|
---@return string
|
||||||
|
---@return ...
|
||||||
|
function string.uchar(byte, ...) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.find
|
||||||
|
---@param s string
|
||||||
|
---@param pattern string
|
||||||
|
---@param init? integer
|
||||||
|
---@param plain? boolean
|
||||||
|
---@return integer start
|
||||||
|
---@return integer end
|
||||||
|
---@return ... captured
|
||||||
|
function string.ufind(s, pattern, init, plain) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.gmatch
|
||||||
|
---@param s string
|
||||||
|
---@param pattern string
|
||||||
|
---@param init? integer
|
||||||
|
---@return fun():string, ...
|
||||||
|
function string.ugmatch(s, pattern, init) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.gsub
|
||||||
|
---@param s string
|
||||||
|
---@param pattern string
|
||||||
|
---@param repl string|table|function
|
||||||
|
---@param n integer
|
||||||
|
---@return string
|
||||||
|
---@return integer count
|
||||||
|
function string.ugsub(s, pattern, repl, n) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.len
|
||||||
|
---@param s string
|
||||||
|
---@return integer
|
||||||
|
function string.ulen(s) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.lower
|
||||||
|
---@param s string
|
||||||
|
---@return string
|
||||||
|
function string.ulower(s) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.match
|
||||||
|
---@param s string
|
||||||
|
---@param pattern string
|
||||||
|
---@param init? integer
|
||||||
|
---@return string | number captured
|
||||||
|
function string.umatch(s, pattern, init) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.reverse
|
||||||
|
---@param s string
|
||||||
|
---@return string
|
||||||
|
function string.ureverse(s) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.sub
|
||||||
|
---@param s string
|
||||||
|
---@param i integer
|
||||||
|
---@param j? integer
|
||||||
|
---@return string
|
||||||
|
function string.usub(s, i, j) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.upper
|
||||||
|
---@param s string
|
||||||
|
---@return string
|
||||||
|
function string.uupper(s) end
|
||||||
|
|
||||||
|
---Equivalent to utf8.escape()
|
||||||
|
---@param s string
|
||||||
|
---@return string utf8_string
|
||||||
|
function string.uescape(s) end
|
||||||
|
|
||||||
|
|
||||||
|
---Equivalent to utf8.charpos()
|
||||||
|
---@param s string
|
||||||
|
---@param charpos? integer
|
||||||
|
---@param index? integer
|
||||||
|
---@return integer charpos
|
||||||
|
---@return integer codepoint
|
||||||
|
function string.ucharpos(s, charpos, index) end
|
||||||
|
|
||||||
|
---Equivalent to utf8.next()
|
||||||
|
---@param s string
|
||||||
|
---@param charpos? integer
|
||||||
|
---@param index? integer
|
||||||
|
---@return integer charpos
|
||||||
|
---@return integer codepoint
|
||||||
|
function string.unext(s, charpos, index) end
|
||||||
|
|
||||||
|
---Equivalent to utf8.insert()
|
||||||
|
---@param s string
|
||||||
|
---@param idx? integer
|
||||||
|
---@param substring string
|
||||||
|
---return string new_string
|
||||||
|
function string.uinsert(s, idx, substring) end
|
||||||
|
|
||||||
|
---Equivalent to utf8.remove()
|
||||||
|
---@param s string
|
||||||
|
---@param start? integer
|
||||||
|
---@param stop? integer
|
||||||
|
---return string new_string
|
||||||
|
function string.uremove(s, start, stop) end
|
||||||
|
|
||||||
|
---Equivalent to utf8.width()
|
||||||
|
---@param s string
|
||||||
|
---@param ambi_is_double? boolean
|
||||||
|
---@param default_width? integer
|
||||||
|
---@return integer width
|
||||||
|
function string.uwidth(s, ambi_is_double, default_width) end
|
||||||
|
|
||||||
|
---Equivalent to utf8.widthindex()
|
||||||
|
---@param s string
|
||||||
|
---@param location integer
|
||||||
|
---@param ambi_is_double? boolean
|
||||||
|
---@param default_width? integer
|
||||||
|
---@return integer idx
|
||||||
|
---@return integer offset
|
||||||
|
---@return integer width
|
||||||
|
function string.uwidthindex(s, location, ambi_is_double, default_width) end
|
||||||
|
|
||||||
|
---Equivalent to utf8.title()
|
||||||
|
---@param s string
|
||||||
|
---return string new_string
|
||||||
|
function string.utitle(s) end
|
||||||
|
|
||||||
|
---Equivalent to utf8.fold()
|
||||||
|
---@param s string
|
||||||
|
---return string new_string
|
||||||
|
function string.ufold(s) end
|
||||||
|
|
||||||
|
---Equivalent to utf8.ncasecmp()
|
||||||
|
---@param a string
|
||||||
|
---@param b string
|
||||||
|
---@return integer result
|
||||||
|
function string.uncasecmp(a, b) end
|
||||||
|
|
||||||
|
---Equivalent to utf8.offset()
|
||||||
|
---@param s string
|
||||||
|
---@param n integer
|
||||||
|
---@param i? integer
|
||||||
|
---@return integer position_in_bytes
|
||||||
|
function string.uoffset(s, n, i) end
|
||||||
|
|
||||||
|
---Equivalent to utf8.codepoint()
|
||||||
|
---@param s string
|
||||||
|
---@param i? integer
|
||||||
|
---@param j? integer
|
||||||
|
---@return integer code
|
||||||
|
---@return ...
|
||||||
|
function string.ucodepoint(s, i, j) end
|
||||||
|
|
||||||
|
---Equivalent to utf8.codes()
|
||||||
|
---@param s string
|
||||||
|
---@return fun():integer, integer
|
||||||
|
function string.ucodes(s) end
|
|
@ -0,0 +1,187 @@
|
||||||
|
---@meta
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.byte
|
||||||
|
---@param s string
|
||||||
|
---@param i? integer
|
||||||
|
---@param j? integer
|
||||||
|
---@return integer
|
||||||
|
---@return ...
|
||||||
|
function utf8.byte(s, i, j) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.char
|
||||||
|
---@param byte integer
|
||||||
|
---@param ... integer
|
||||||
|
---@return string
|
||||||
|
---@return ...
|
||||||
|
function utf8.char(byte, ...) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.find
|
||||||
|
---@param s string
|
||||||
|
---@param pattern string
|
||||||
|
---@param init? integer
|
||||||
|
---@param plain? boolean
|
||||||
|
---@return integer start
|
||||||
|
---@return integer end
|
||||||
|
---@return ... captured
|
||||||
|
function utf8.find(s, pattern, init, plain) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.gmatch
|
||||||
|
---@param s string
|
||||||
|
---@param pattern string
|
||||||
|
---@param init? integer
|
||||||
|
---@return fun():string, ...
|
||||||
|
function utf8.gmatch(s, pattern, init) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.gsub
|
||||||
|
---@param s string
|
||||||
|
---@param pattern string
|
||||||
|
---@param repl string|table|function
|
||||||
|
---@param n integer
|
||||||
|
---@return string
|
||||||
|
---@return integer count
|
||||||
|
function utf8.gsub(s, pattern, repl, n) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.len
|
||||||
|
---@param s string
|
||||||
|
---@return integer
|
||||||
|
function utf8.len(s) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.lower
|
||||||
|
---@param s string
|
||||||
|
---@return string
|
||||||
|
function utf8.lower(s) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.match
|
||||||
|
---@param s string
|
||||||
|
---@param pattern string
|
||||||
|
---@param init? integer
|
||||||
|
---@return string | number captured
|
||||||
|
function utf8.match(s, pattern, init) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.reverse
|
||||||
|
---@param s string
|
||||||
|
---@return string
|
||||||
|
function utf8.reverse(s) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.sub
|
||||||
|
---@param s string
|
||||||
|
---@param i integer
|
||||||
|
---@param j? integer
|
||||||
|
---@return string
|
||||||
|
function utf8.sub(s, i, j) end
|
||||||
|
|
||||||
|
---UTF-8 equivalent of string.upper
|
||||||
|
---@param s string
|
||||||
|
---@return string
|
||||||
|
function utf8.upper(s) end
|
||||||
|
|
||||||
|
---Escape a str to UTF-8 format string. It support several escape format:
|
||||||
|
---* %ddd - which ddd is a decimal number at any length: change Unicode code point to UTF-8 format.
|
||||||
|
---* %{ddd} - same as %nnn but has bracket around.
|
||||||
|
---* %uddd - same as %ddd, u stands Unicode
|
||||||
|
---* %u{ddd} - same as %{ddd}
|
||||||
|
---* %xhhh - hexadigit version of %ddd
|
||||||
|
---* %x{hhh} same as %xhhh.
|
||||||
|
---* %? - '?' stands for any other character: escape this character.
|
||||||
|
---Example:
|
||||||
|
---```lua
|
||||||
|
---local u = utf8.escape
|
||||||
|
---print(u"%123%u123%{123}%u{123}%xABC%x{ABC}")
|
||||||
|
---print(u"%%123%?%d%%u")
|
||||||
|
---```
|
||||||
|
---@param s string
|
||||||
|
---@return string utf8_string
|
||||||
|
function utf8.escape(s) end
|
||||||
|
|
||||||
|
---Convert UTF-8 position to byte offset. if only index is given, return byte
|
||||||
|
---offset of this UTF-8 char index. if both charpos and index is given, a new
|
||||||
|
---charpos will be calculated, by add/subtract UTF-8 char index to current
|
||||||
|
---charpos. in all cases, it returns a new char position, and code point
|
||||||
|
---(a number) at this position.
|
||||||
|
---@param s string
|
||||||
|
---@param charpos? integer
|
||||||
|
---@param index? integer
|
||||||
|
---@return integer charpos
|
||||||
|
---@return integer codepoint
|
||||||
|
function utf8.charpos(s, charpos, index) end
|
||||||
|
|
||||||
|
---Iterate though the UTF-8 string s. If only s is given, it can used as a iterator:
|
||||||
|
---```lua
|
||||||
|
--- for pos, code in utf8.next, "utf8-string" do
|
||||||
|
--- -- ...
|
||||||
|
--- end
|
||||||
|
---````
|
||||||
|
---If only charpos is given, return the next byte offset of in string. if
|
||||||
|
---charpos and index is given, a new charpos will be calculated, by add/subtract
|
||||||
|
---UTF-8 char offset to current charpos. in all case, it return a new char
|
||||||
|
---position (in bytes), and code point (a number) at this position.
|
||||||
|
---@param s string
|
||||||
|
---@param charpos? integer
|
||||||
|
---@param index? integer
|
||||||
|
---@return integer charpos
|
||||||
|
---@return integer codepoint
|
||||||
|
function utf8.next(s, charpos, index) end
|
||||||
|
|
||||||
|
---Insert a substring to s. If idx is given, insert substring before char at
|
||||||
|
---this index, otherwise substring will concat to s. idx can be negative.
|
||||||
|
---@param s string
|
||||||
|
---@param idx? integer
|
||||||
|
---@param substring string
|
||||||
|
---return string new_string
|
||||||
|
function utf8.insert(s, idx, substring) end
|
||||||
|
|
||||||
|
---Delete a substring in s. If neither start nor stop is given, delete the last
|
||||||
|
---UTF-8 char in s, otherwise delete char from start to end of s. if stop is
|
||||||
|
---given, delete char from start to stop (include start and stop). start and
|
||||||
|
---stop can be negative.
|
||||||
|
---@param s string
|
||||||
|
---@param start? integer
|
||||||
|
---@param stop? integer
|
||||||
|
---return string new_string
|
||||||
|
function utf8.remove(s, start, stop) end
|
||||||
|
|
||||||
|
---Calculate the width of UTF-8 string s. if ambi_is_double is given, the
|
||||||
|
---ambiguous width character's width is 2, otherwise it's 1. fullwidth/doublewidth
|
||||||
|
---character's width is 2, and other character's width is 1. if default_width is
|
||||||
|
---given, it will be the width of unprintable character, used display a
|
||||||
|
---non-character mark for these characters. if s is a code point, return the
|
||||||
|
---width of this code point.
|
||||||
|
---@param s string
|
||||||
|
---@param ambi_is_double? boolean
|
||||||
|
---@param default_width? integer
|
||||||
|
---@return integer width
|
||||||
|
function utf8.width(s, ambi_is_double, default_width) end
|
||||||
|
|
||||||
|
---Return the character index at given location in string s. this is a reverse
|
||||||
|
---operation of utf8.width(). this function returns a index of location, and a
|
||||||
|
---offset in UTF-8 encoding. e.g. if cursor is at the second column (middle)
|
||||||
|
---of the wide char, offset will be 2. the width of character at idx is
|
||||||
|
---returned, also.
|
||||||
|
---@param s string
|
||||||
|
---@param location integer
|
||||||
|
---@param ambi_is_double? boolean
|
||||||
|
---@param default_width? integer
|
||||||
|
---@return integer idx
|
||||||
|
---@return integer offset
|
||||||
|
---@return integer width
|
||||||
|
function utf8.widthindex(s, location, ambi_is_double, default_width) end
|
||||||
|
|
||||||
|
---Convert UTF-8 string s to title-case, used to compare by ignore case. if s
|
||||||
|
---is a number, it's treat as a code point and return a convert code point
|
||||||
|
---(number). utf8.lower/utf8.pper has the same extension.
|
||||||
|
---@param s string
|
||||||
|
---return string new_string
|
||||||
|
function utf8.title(s) end
|
||||||
|
|
||||||
|
---Convert UTF-8 string s to folded case, used to compare by ignore case. if s
|
||||||
|
---is a number, it's treat as a code point and return a convert code point
|
||||||
|
---(number). utf8.lower/utf8.pper has the same extension.
|
||||||
|
---@param s string
|
||||||
|
---return string new_string
|
||||||
|
function utf8.fold(s) end
|
||||||
|
|
||||||
|
---Compare a and b without case, -1 means a < b, 0 means a == b and 1 means a > b.
|
||||||
|
---@param a string
|
||||||
|
---@param b string
|
||||||
|
---@return integer result
|
||||||
|
function utf8.ncasecmp(a, b) end
|
|
@ -5,6 +5,7 @@ int luaopen_renderer(lua_State *L);
|
||||||
int luaopen_regex(lua_State *L);
|
int luaopen_regex(lua_State *L);
|
||||||
int luaopen_process(lua_State *L);
|
int luaopen_process(lua_State *L);
|
||||||
int luaopen_dirmonitor(lua_State* L);
|
int luaopen_dirmonitor(lua_State* L);
|
||||||
|
int luaopen_utf8(lua_State* L);
|
||||||
|
|
||||||
static const luaL_Reg libs[] = {
|
static const luaL_Reg libs[] = {
|
||||||
{ "system", luaopen_system },
|
{ "system", luaopen_system },
|
||||||
|
@ -12,6 +13,7 @@ static const luaL_Reg libs[] = {
|
||||||
{ "regex", luaopen_regex },
|
{ "regex", luaopen_regex },
|
||||||
{ "process", luaopen_process },
|
{ "process", luaopen_process },
|
||||||
{ "dirmonitor", luaopen_dirmonitor },
|
{ "dirmonitor", luaopen_dirmonitor },
|
||||||
|
{ "utf8", luaopen_utf8 },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,4 +5,4 @@ void deinit_dirmonitor(struct dirmonitor_internal* monitor) { }
|
||||||
int get_changes_dirmonitor(struct dirmonitor_internal* monitor, char* buffer, size_t len) { return -1; }
|
int get_changes_dirmonitor(struct dirmonitor_internal* monitor, char* buffer, size_t len) { return -1; }
|
||||||
int translate_changes_dirmonitor(struct dirmonitor_internal* monitor, char* buffer, int size, int (*callback)(int, const char*, void*), void* data) { return -1; }
|
int translate_changes_dirmonitor(struct dirmonitor_internal* monitor, char* buffer, int size, int (*callback)(int, const char*, void*), void* data) { return -1; }
|
||||||
int add_dirmonitor(struct dirmonitor_internal* monitor, const char* path) { return -1; }
|
int add_dirmonitor(struct dirmonitor_internal* monitor, const char* path) { return -1; }
|
||||||
void remove_dirmonitor(struct dirmonitor_internal* monitor, int fd) { }
|
void remove_dirmonitor(struct dirmonitor_internal* monitor, int fd) { }
|
|
@ -161,6 +161,9 @@ top:
|
||||||
} else if (e.window.event == SDL_WINDOWEVENT_RESTORED) {
|
} else if (e.window.event == SDL_WINDOWEVENT_RESTORED) {
|
||||||
lua_pushstring(L, "restored");
|
lua_pushstring(L, "restored");
|
||||||
return 1;
|
return 1;
|
||||||
|
} else if (e.window.event == SDL_WINDOWEVENT_LEAVE) {
|
||||||
|
lua_pushstring(L, "mouseleft");
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
if (e.window.event == SDL_WINDOWEVENT_FOCUS_LOST) {
|
if (e.window.event == SDL_WINDOWEVENT_FOCUS_LOST) {
|
||||||
lua_pushstring(L, "focuslost");
|
lua_pushstring(L, "focuslost");
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4,6 +4,7 @@ lite_sources = [
|
||||||
'api/regex.c',
|
'api/regex.c',
|
||||||
'api/system.c',
|
'api/system.c',
|
||||||
'api/process.c',
|
'api/process.c',
|
||||||
|
'api/utf8.c',
|
||||||
'renderer.c',
|
'renderer.c',
|
||||||
'renwindow.c',
|
'renwindow.c',
|
||||||
'rencache.c',
|
'rencache.c',
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue