mirror of https://github.com/odrling/Aegisub
Add native support for MoonScript
This commit is contained in:
parent
99d74e18b3
commit
19854e207a
|
@ -1,31 +0,0 @@
|
|||
local tr = aegisub.gettext
|
||||
script_name = tr("Select overlaps")
|
||||
script_description = tr("Select lines which begin while another non-comment line is active")
|
||||
script_author = "Thomas Goyne"
|
||||
script_version = "2"
|
||||
local select_overlaps
|
||||
select_overlaps = function(subs)
|
||||
local dialogue = { }
|
||||
for i, line in ipairs(subs) do
|
||||
if line.class == "dialogue" then
|
||||
line.i = i
|
||||
table.insert(dialogue, line)
|
||||
end
|
||||
end
|
||||
table.sort(dialogue, function(a, b)
|
||||
return a.start_time < b.start_time or (a.start_time == b.start_time and a.i < b.i)
|
||||
end)
|
||||
local end_time = 0
|
||||
local overlaps = { }
|
||||
local _list_0 = dialogue
|
||||
for _index_0 = 1, #_list_0 do
|
||||
local line = _list_0[_index_0]
|
||||
if line.start_time >= end_time then
|
||||
end_time = line.end_time
|
||||
else
|
||||
table.insert(overlaps, line.i)
|
||||
end
|
||||
end
|
||||
return overlaps
|
||||
end
|
||||
return aegisub.register_macro(script_name, script_description, select_overlaps)
|
|
@ -1,314 +0,0 @@
|
|||
local regex = aegisub.__init_regex()
|
||||
local select_first
|
||||
select_first = function(n, a, ...)
|
||||
if n == 0 then
|
||||
return
|
||||
end
|
||||
return a, select_first(n - 1, ...)
|
||||
end
|
||||
local unpack_args
|
||||
unpack_args = function(...)
|
||||
local userdata_start = nil
|
||||
for i = 1, select('#', ...) do
|
||||
local v = select(i, ...)
|
||||
if type(v) == 'userdata' then
|
||||
userdata_start = i
|
||||
break
|
||||
end
|
||||
end
|
||||
if not (userdata_start) then
|
||||
return 0, ...
|
||||
end
|
||||
local flags = regex.process_flags(select(userdata_start, ...))
|
||||
if type(flags) == 'string' then
|
||||
error(flags, 3)
|
||||
end
|
||||
return flags, select_first(userdata_start - 1, ...)
|
||||
end
|
||||
local check_arg
|
||||
check_arg = function(arg, expected_type, argn, func_name, level)
|
||||
if type(arg) ~= expected_type then
|
||||
return error("Argument " .. tostring(argn) .. " to " .. tostring(func_name) .. " should be a '" .. tostring(expected_type) .. "', is '" .. tostring(type(arg)) .. "' (" .. tostring(arg) .. ")", level + 1)
|
||||
end
|
||||
end
|
||||
local replace_match
|
||||
replace_match = function(match, func, str, last, acc)
|
||||
if last < match.last then
|
||||
acc[#acc + 1] = str:sub(last, match.first - 1)
|
||||
end
|
||||
local repl = func(match.str, match.first, match.last)
|
||||
if type(repl) == 'string' then
|
||||
acc[#acc + 1] = repl
|
||||
else
|
||||
acc[#acc + 1] = match.str
|
||||
end
|
||||
return match.first, match.last + 1
|
||||
end
|
||||
local do_single_replace_fun
|
||||
do_single_replace_fun = function(re, func, str, acc, pos)
|
||||
local matches = re:match(str, pos)
|
||||
if not (matches) then
|
||||
return pos
|
||||
end
|
||||
local start
|
||||
if #matches == 1 then
|
||||
start = 1
|
||||
else
|
||||
start = 2
|
||||
end
|
||||
local last = pos
|
||||
local first
|
||||
for i = start, #matches do
|
||||
first, last = replace_match(matches[i], func, str, last, acc)
|
||||
end
|
||||
if first == last then
|
||||
acc[#acc + 1] = str:sub(last, last)
|
||||
last = last + 1
|
||||
end
|
||||
return last, matches[1].first <= str:len()
|
||||
end
|
||||
local do_replace_fun
|
||||
do_replace_fun = function(re, func, str, max)
|
||||
local acc = { }
|
||||
local pos = 1
|
||||
local i
|
||||
for i = 1, max do
|
||||
local more
|
||||
pos, more = do_single_replace_fun(re, func, str, acc, pos)
|
||||
if not (more) then
|
||||
max = i
|
||||
break
|
||||
end
|
||||
end
|
||||
return table.concat(acc, '') .. str:sub(pos)
|
||||
end
|
||||
local RegEx
|
||||
do
|
||||
local start
|
||||
local _parent_0 = nil
|
||||
local _base_0 = {
|
||||
_check_self = function(self)
|
||||
if not (self.__class == RegEx) then
|
||||
return error('re method called with invalid self. You probably used . when : is needed.', 3)
|
||||
end
|
||||
end,
|
||||
gsplit = function(self, str, skip_empty, max_split)
|
||||
self:_check_self()
|
||||
check_arg(str, 'string', 2, 'gsplit', self._level)
|
||||
if not max_split or max_split <= 0 then
|
||||
max_split = str:len()
|
||||
end
|
||||
start = 1
|
||||
local prev = 1
|
||||
local do_split
|
||||
do_split = function()
|
||||
if not str or str:len() == 0 then
|
||||
return
|
||||
end
|
||||
local first, last
|
||||
if max_split > 0 then
|
||||
first, last = regex.search(self._regex, str, start)
|
||||
end
|
||||
if not first or first > str:len() then
|
||||
local ret = str:sub(prev, str:len())
|
||||
str = nil
|
||||
return ret
|
||||
end
|
||||
local ret = str:sub(prev, first - 1)
|
||||
prev = last + 1
|
||||
start = 1 + (function()
|
||||
if start >= last then
|
||||
return start
|
||||
else
|
||||
return last
|
||||
end
|
||||
end)()
|
||||
if skip_empty and ret:len() == 0 then
|
||||
return do_split()
|
||||
else
|
||||
max_split = max_split - 1
|
||||
return ret
|
||||
end
|
||||
end
|
||||
return do_split
|
||||
end,
|
||||
split = function(self, str, skip_empty, max_split)
|
||||
self:_check_self()
|
||||
check_arg(str, 'string', 2, 'split', self._level)
|
||||
return (function()
|
||||
local _accum_0 = { }
|
||||
local _len_0 = 1
|
||||
for v in self:gsplit(str, skip_empty, max_split) do
|
||||
_accum_0[_len_0] = v
|
||||
_len_0 = _len_0 + 1
|
||||
end
|
||||
return _accum_0
|
||||
end)()
|
||||
end,
|
||||
gfind = function(self, str)
|
||||
self:_check_self()
|
||||
check_arg(str, 'string', 2, 'gfind', self._level)
|
||||
start = 1
|
||||
return function()
|
||||
local first, last = regex.search(self._regex, str, start)
|
||||
if not (first) then
|
||||
return
|
||||
end
|
||||
if last >= start then
|
||||
start = last + 1
|
||||
else
|
||||
start = start + 1
|
||||
end
|
||||
return str:sub(first, last), first, last
|
||||
end
|
||||
end,
|
||||
find = function(self, str)
|
||||
self:_check_self()
|
||||
check_arg(str, 'string', 2, 'find', self._level)
|
||||
local ret = (function()
|
||||
local _accum_0 = { }
|
||||
local _len_0 = 1
|
||||
for s, f, l in self:gfind(str) do
|
||||
_accum_0[_len_0] = {
|
||||
str = s,
|
||||
first = f,
|
||||
last = l
|
||||
}
|
||||
_len_0 = _len_0 + 1
|
||||
end
|
||||
return _accum_0
|
||||
end)()
|
||||
return next(ret) and ret
|
||||
end,
|
||||
sub = function(self, str, repl, max_count)
|
||||
self:_check_self()
|
||||
check_arg(str, 'string', 2, 'sub', self._level)
|
||||
if max_count ~= nil then
|
||||
check_arg(max_count, 'number', 4, 'sub', self._level)
|
||||
end
|
||||
if not max_count or max_count == 0 then
|
||||
max_count = str:len() + 1
|
||||
end
|
||||
if type(repl) == 'function' then
|
||||
return do_replace_fun(self, repl, str, max_count)
|
||||
elseif type(repl) == 'string' then
|
||||
return regex.replace(self._regex, repl, str, max_count)
|
||||
else
|
||||
return error("Argument 2 to sub should be a string or function, is '" .. tostring(type(repl)) .. "' (" .. tostring(repl) .. ")", self._level)
|
||||
end
|
||||
end,
|
||||
gmatch = function(self, str, start)
|
||||
self:_check_self()
|
||||
check_arg(str, 'string', 2, 'gmatch', self._level)
|
||||
if start then
|
||||
start = start - 1
|
||||
else
|
||||
start = 0
|
||||
end
|
||||
local match = regex.match(self._regex, str, start)
|
||||
local i = 1
|
||||
return function()
|
||||
if not (match) then
|
||||
return
|
||||
end
|
||||
local first, last = regex.get_match(match, i)
|
||||
if not (first) then
|
||||
return
|
||||
end
|
||||
i = i + 1
|
||||
return {
|
||||
str = str:sub(first + start, last + start),
|
||||
first = first + start,
|
||||
last = last + start
|
||||
}
|
||||
end
|
||||
end,
|
||||
match = function(self, str, start)
|
||||
self:_check_self()
|
||||
check_arg(str, 'string', 2, 'match', self._level)
|
||||
local ret = (function()
|
||||
local _accum_0 = { }
|
||||
local _len_0 = 1
|
||||
for v in self:gmatch(str, start) do
|
||||
_accum_0[_len_0] = v
|
||||
_len_0 = _len_0 + 1
|
||||
end
|
||||
return _accum_0
|
||||
end)()
|
||||
if next(ret) == nil then
|
||||
return nil
|
||||
end
|
||||
return ret
|
||||
end
|
||||
}
|
||||
_base_0.__index = _base_0
|
||||
if _parent_0 then
|
||||
setmetatable(_base_0, _parent_0.__base)
|
||||
end
|
||||
local _class_0 = setmetatable({
|
||||
__init = function(self, _regex, _level)
|
||||
self._regex, self._level = _regex, _level
|
||||
end,
|
||||
__base = _base_0,
|
||||
__name = "RegEx",
|
||||
__parent = _parent_0
|
||||
}, {
|
||||
__index = function(cls, name)
|
||||
local val = rawget(_base_0, name)
|
||||
if val == nil and _parent_0 then
|
||||
return _parent_0[name]
|
||||
else
|
||||
return val
|
||||
end
|
||||
end,
|
||||
__call = function(cls, ...)
|
||||
local _self_0 = setmetatable({}, _base_0)
|
||||
cls.__init(_self_0, ...)
|
||||
return _self_0
|
||||
end
|
||||
})
|
||||
_base_0.__class = _class_0
|
||||
local self = _class_0
|
||||
start = 1
|
||||
if _parent_0 and _parent_0.__inherited then
|
||||
_parent_0.__inherited(_parent_0, _class_0)
|
||||
end
|
||||
RegEx = _class_0
|
||||
end
|
||||
local real_compile
|
||||
real_compile = function(pattern, level, flags, stored_level)
|
||||
if pattern == '' then
|
||||
error('Regular expression must not be empty', level + 1)
|
||||
end
|
||||
local re = regex.compile(pattern, flags)
|
||||
if type(re) == 'string' then
|
||||
error(regex, level + 1)
|
||||
end
|
||||
return RegEx(re, stored_level or level + 1)
|
||||
end
|
||||
local invoke
|
||||
invoke = function(str, pattern, fn, flags, ...)
|
||||
local compiled_regex = real_compile(pattern, 3, flags)
|
||||
return compiled_regex[fn](compiled_regex, str, ...)
|
||||
end
|
||||
local gen_wrapper
|
||||
gen_wrapper = function(impl_name)
|
||||
return function(str, pattern, ...)
|
||||
check_arg(str, 'string', 1, impl_name, 2)
|
||||
check_arg(pattern, 'string', 2, impl_name, 2)
|
||||
return invoke(str, pattern, impl_name, unpack_args(...))
|
||||
end
|
||||
end
|
||||
local re = regex.init_flags(re)
|
||||
re.compile = function(pattern, ...)
|
||||
check_arg(pattern, 'string', 1, 'compile', 2)
|
||||
return real_compile(pattern, 2, regex.process_flags(...), 2)
|
||||
end
|
||||
re.split = gen_wrapper('split')
|
||||
re.gsplit = gen_wrapper('gsplit')
|
||||
re.find = gen_wrapper('find')
|
||||
re.gfind = gen_wrapper('gfind')
|
||||
re.match = gen_wrapper('match')
|
||||
re.gmatch = gen_wrapper('gmatch')
|
||||
re.sub = gen_wrapper('sub')
|
||||
return re
|
|
@ -1,58 +0,0 @@
|
|||
local unicode
|
||||
unicode = {
|
||||
charwidth = function(s, i)
|
||||
local b = s:byte(i or 1)
|
||||
if not b then
|
||||
return 1
|
||||
elseif b < 128 then
|
||||
return 1
|
||||
elseif b < 224 then
|
||||
return 2
|
||||
elseif b < 240 then
|
||||
return 3
|
||||
else
|
||||
return 4
|
||||
end
|
||||
end,
|
||||
chars = function(s)
|
||||
local curchar, i = 0, 1
|
||||
return function()
|
||||
if i > s:len() then
|
||||
return
|
||||
end
|
||||
local j = i
|
||||
curchar = curchar + 1
|
||||
i = i + unicode.charwidth(s, i)
|
||||
return s:sub(j, i - 1), curchar
|
||||
end
|
||||
end,
|
||||
len = function(s)
|
||||
local n = 0
|
||||
for c in unicode.chars(s) do
|
||||
n = n + 1
|
||||
end
|
||||
return n
|
||||
end,
|
||||
codepoint = function(s)
|
||||
local b = s:byte(1)
|
||||
if b < 128 then
|
||||
return b
|
||||
end
|
||||
local res, w
|
||||
if b < 224 then
|
||||
res = b - 192
|
||||
w = 2
|
||||
elseif b < 240 then
|
||||
res = b - 224
|
||||
w = 3
|
||||
else
|
||||
res = b - 240
|
||||
w = 4
|
||||
end
|
||||
for i = 2, w do
|
||||
res = res * 64 + s:byte(i) - 128
|
||||
end
|
||||
return res
|
||||
end
|
||||
}
|
||||
return unicode
|
|
@ -1,242 +0,0 @@
|
|||
local sformat = string.format
|
||||
local copy
|
||||
copy = function(tbl)
|
||||
return (function()
|
||||
local _tbl_0 = { }
|
||||
for k, v in pairs(tbl) do
|
||||
_tbl_0[k] = v
|
||||
end
|
||||
return _tbl_0
|
||||
end)()
|
||||
end
|
||||
local deep_copy
|
||||
deep_copy = function(tbl)
|
||||
local seen = { }
|
||||
copy = function(val)
|
||||
if type(tbl) ~= 'table' then
|
||||
return val
|
||||
end
|
||||
if seen[tbl] then
|
||||
return seen[val]
|
||||
end
|
||||
seen[val] = tbl
|
||||
return (function()
|
||||
local _tbl_0 = { }
|
||||
for k, v in pairs(val) do
|
||||
_tbl_0[k] = copy(v)
|
||||
end
|
||||
return _tbl_0
|
||||
end)()
|
||||
end
|
||||
return copy(tbl)
|
||||
end
|
||||
local ass_color
|
||||
ass_color = function(r, g, b)
|
||||
return sformat("&H%02X%02X%02X&", b, g, r)
|
||||
end
|
||||
local ass_alpha
|
||||
ass_alpha = function(a)
|
||||
return sformat("&H%02X&", a)
|
||||
end
|
||||
local ass_style_color
|
||||
ass_style_color = function(r, g, b, a)
|
||||
return sformat("&H%02X%02X%02X%02X", a, b, g, r)
|
||||
end
|
||||
local extract_color
|
||||
extract_color = function(s)
|
||||
local a, b, g, r
|
||||
a, b, g, r = s:match('&H(%x%x)(%x%x)(%x%x)(%x%x)')
|
||||
if a then
|
||||
return tonumber(r, 16), tonumber(g, 16), tonumber(b, 16), tonumber(a, 16)
|
||||
end
|
||||
b, g, r = s:match('&H(%x%x)(%x%x)(%x%x)&')
|
||||
if b then
|
||||
return tonumber(r, 16), tonumber(g, 16), tonumber(b, 16), 0
|
||||
end
|
||||
a = s:match('&H(%x%x)&')
|
||||
if a then
|
||||
return 0, 0, 0, tonumber(a, 16)
|
||||
end
|
||||
r, g, b, a = s:match('#(%x%x)(%x?%x?)(%x?%x?)(%x?%x?)')
|
||||
if r then
|
||||
return tonumber(r, 16), tonumber(g, 16) or 0, tonumber(b, 16) or 0, tonumber(a, 16) or 0
|
||||
end
|
||||
end
|
||||
local alpha_from_style
|
||||
alpha_from_style = function(scolor)
|
||||
return ass_alpha(select(4, extract_color(scolor)))
|
||||
end
|
||||
local color_from_style
|
||||
color_from_style = function(scolor)
|
||||
local r, g, b = extract_color(scolor)
|
||||
return ass_color(r or 0, g or 0, b or 0)
|
||||
end
|
||||
local HSV_to_RGB
|
||||
HSV_to_RGB = function(H, S, V)
|
||||
local r, g, b = 0, 0, 0
|
||||
if S == 0 then
|
||||
r = self:clamp(V * 255, 0, 255)
|
||||
g = r
|
||||
b = r
|
||||
else
|
||||
H = math.abs(H) % 360
|
||||
local Hi = math.floor(H / 60)
|
||||
local f = H / 60.0 - Hi
|
||||
local p = V * (1 - S)
|
||||
local q = V * (1 - f * S)
|
||||
local t = V * (1 - (1 - f) * S)
|
||||
if Hi == 0 then
|
||||
r = V * 255.0
|
||||
g = t * 255.0
|
||||
b = p * 255.0
|
||||
elseif Hi == 1 then
|
||||
r = q * 255.0
|
||||
g = V * 255.0
|
||||
b = p * 255.0
|
||||
elseif Hi == 2 then
|
||||
r = p * 255.0
|
||||
g = V * 255.0
|
||||
b = t * 255.0
|
||||
elseif Hi == 3 then
|
||||
r = p * 255.0
|
||||
g = q * 255.0
|
||||
b = V * 255.0
|
||||
elseif Hi == 4 then
|
||||
r = t * 255.0
|
||||
g = p * 255.0
|
||||
b = V * 255.0
|
||||
elseif Hi == 5 then
|
||||
r = V * 255.0
|
||||
g = p * 255.0
|
||||
b = q * 255.0
|
||||
else
|
||||
error("math.floor(H % 360 / 60) should be [0, 6), is " .. tostring(Hi) .. "?")
|
||||
end
|
||||
end
|
||||
return r, g, b
|
||||
end
|
||||
local HSL_to_RGB
|
||||
HSL_to_RGB = function(H, S, L)
|
||||
local r, g, b
|
||||
H = math.abs(H) % 360
|
||||
S = clamp(S, 0, 1)
|
||||
L = clamp(L, 0, 1)
|
||||
if S == 0 then
|
||||
r = L
|
||||
g = L
|
||||
b = L
|
||||
else
|
||||
local Q
|
||||
if L < 0.5 then
|
||||
Q = L * (1.0 + S)
|
||||
else
|
||||
Q = L + S - (L * S)
|
||||
end
|
||||
local P = 2.0 * L - Q
|
||||
local Hk = H / 360
|
||||
local Tr, Tg, Tb
|
||||
if Hk < 1 / 3 then
|
||||
Tr = Hk + 1 / 3
|
||||
Tg = Hk
|
||||
Tb = Hk + 2 / 3
|
||||
elseif Hk > 2 / 3 then
|
||||
Tr = Hk - 2 / 3
|
||||
Tg = Hk
|
||||
Tb = Hk - 1 / 3
|
||||
else
|
||||
Tr = Hk + 1 / 3
|
||||
Tg = Hk
|
||||
Tb = Hk - 1 / 3
|
||||
end
|
||||
local get_component
|
||||
get_component = function(T)
|
||||
if T < 1 / 6 then
|
||||
return P + ((Q - P) * 6.0 * T)
|
||||
elseif 1 / 6 <= T and T < 1 / 2 then
|
||||
return Q
|
||||
elseif 1 / 2 <= T and T < 2 / 3 then
|
||||
return P + ((Q - P) * (2 / 3 - T) * 6.0)
|
||||
else
|
||||
return P
|
||||
end
|
||||
end
|
||||
r = get_component(Tr)
|
||||
g = get_component(Tg)
|
||||
b = get_component(Tb)
|
||||
end
|
||||
return math.floor(r * 255 + 0.5), math.floor(g * 255 + 0.5), math.floor(b * 255 + 0.5)
|
||||
end
|
||||
local trim
|
||||
trim = function(s)
|
||||
return s:gsub('^%s*(.-)%s*$', '%1')
|
||||
end
|
||||
local headtail
|
||||
headtail = function(s)
|
||||
local a, b, head, tail = s:find('(.-)%s+(.*)')
|
||||
if a then
|
||||
return head, tail
|
||||
else
|
||||
return s, ''
|
||||
end
|
||||
end
|
||||
local words
|
||||
words = function(s)
|
||||
return function()
|
||||
if s == '' then
|
||||
return
|
||||
end
|
||||
local head, tail = headtail(s)
|
||||
s = tail
|
||||
return head
|
||||
end
|
||||
end
|
||||
local clamp
|
||||
clamp = function(val, min, max)
|
||||
if val < min then
|
||||
return min
|
||||
elseif val > max then
|
||||
return max
|
||||
else
|
||||
return val
|
||||
end
|
||||
end
|
||||
local interpolate
|
||||
interpolate = function(pct, min, max)
|
||||
if pct <= 0 then
|
||||
return min
|
||||
elseif pct >= 1 then
|
||||
return max
|
||||
else
|
||||
return pct * (max - min) + min
|
||||
end
|
||||
end
|
||||
local interpolate_color
|
||||
interpolate_color = function(pct, first, last)
|
||||
local r1, g1, b1 = extract_color(first)
|
||||
local r2, g2, b2 = extract_color(last)
|
||||
local r, g, b = interpolate(pct, r1, r2), interpolate(pct, g1, g2), interpolate(pct, b1, b2)
|
||||
return ass_color(r, g, b)
|
||||
end
|
||||
local interpolate_alpha
|
||||
interpolate_alpha = function(pct, first, last)
|
||||
return ass_alpha(interpolate(pct, select(4, extract_color(first)), select(4, extract_color(last))))
|
||||
end
|
||||
return {
|
||||
copy = copy,
|
||||
deep_copy = deep_copy,
|
||||
ass_color = ass_color,
|
||||
ass_alpha = ass_alpha,
|
||||
ass_style_color = ass_style_color,
|
||||
extract_color = extract_color,
|
||||
alpha_from_style = alpha_from_style,
|
||||
color_from_style = color_from_style,
|
||||
HSV_to_RGB = HSV_to_RGB,
|
||||
HSL_to_RGB = HSL_to_RGB,
|
||||
trim = trim,
|
||||
headtail = headtail,
|
||||
words = words,
|
||||
clamp = clamp,
|
||||
interpolate = interpolate,
|
||||
interpolate_color = interpolate_color,
|
||||
interpolate_alpha = interpolate_alpha
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -51,6 +51,7 @@
|
|||
#include <libaegisub/fs.h>
|
||||
#include <libaegisub/path.h>
|
||||
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
@ -517,8 +518,10 @@ namespace Automation4 {
|
|||
if (fact->GetEngineName().empty() || fact->GetFilenamePattern().empty())
|
||||
continue;
|
||||
|
||||
fnfilter += str(boost::format("%s scripts (%s)|%s|") % fact->GetEngineName() % fact->GetFilenamePattern() % fact->GetFilenamePattern());
|
||||
catchall += fact->GetFilenamePattern() + ";";
|
||||
std::string filter(fact->GetFilenamePattern());
|
||||
boost::replace_all(filter, ",", ";");
|
||||
fnfilter += str(boost::format("%s scripts (%s)|%s|") % fact->GetEngineName() % fact->GetFilenamePattern() % filter);
|
||||
catchall += filter + ";";
|
||||
}
|
||||
fnfilter += from_wx(_("All Files")) + " (*.*)|*.*";
|
||||
|
||||
|
|
|
@ -191,6 +191,103 @@ namespace {
|
|||
TableIter::init(L);
|
||||
return 3;
|
||||
}
|
||||
|
||||
int frame_from_ms(lua_State *L)
|
||||
{
|
||||
const agi::Context *c = get_context(L);
|
||||
int ms = lua_tointeger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
if (c && c->videoController->TimecodesLoaded())
|
||||
push_value(L, c->videoController->FrameAtTime(ms, agi::vfr::START));
|
||||
else
|
||||
lua_pushnil(L);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ms_from_frame(lua_State *L)
|
||||
{
|
||||
const agi::Context *c = get_context(L);
|
||||
int frame = lua_tointeger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
if (c && c->videoController->TimecodesLoaded())
|
||||
push_value(L, c->videoController->TimeAtFrame(frame, agi::vfr::START));
|
||||
else
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int video_size(lua_State *L)
|
||||
{
|
||||
const agi::Context *c = get_context(L);
|
||||
if (c && c->videoController->IsLoaded()) {
|
||||
push_value(L, c->videoController->GetWidth());
|
||||
push_value(L, c->videoController->GetHeight());
|
||||
push_value(L, c->videoController->GetAspectRatioValue());
|
||||
push_value(L, (int)c->videoController->GetAspectRatioType());
|
||||
return 4;
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int get_keyframes(lua_State *L)
|
||||
{
|
||||
const agi::Context *c = get_context(L);
|
||||
if (!c) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<int> const& kf = c->videoController->GetKeyFrames();
|
||||
|
||||
lua_newtable(L);
|
||||
for (size_t i = 0; i < kf.size(); ++i) {
|
||||
push_value(L, kf[i]);
|
||||
lua_rawseti(L, -2, i);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int decode_path(lua_State *L)
|
||||
{
|
||||
std::string path = luaL_checkstring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
push_value(L, config::path->Decode(path));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cancel_script(lua_State *L)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
int lua_text_textents(lua_State *L)
|
||||
{
|
||||
luaL_argcheck(L, lua_istable(L, 1), 1, "");
|
||||
luaL_argcheck(L, lua_isstring(L, 2), 2, "");
|
||||
|
||||
lua_pushvalue(L, 1);
|
||||
agi::scoped_ptr<AssEntry> et(Automation4::LuaAssFile::LuaToAssEntry(L));
|
||||
AssStyle *st = dynamic_cast<AssStyle*>(et.get());
|
||||
lua_pop(L, 1);
|
||||
if (!st)
|
||||
return luaL_error(L, "Not a style entry");
|
||||
|
||||
double width, height, descent, extlead;
|
||||
if (!Automation4::CalculateTextExtents(st, luaL_checkstring(L, 2), width, height, descent, extlead))
|
||||
return luaL_error(L, "Some internal error occurred calculating text_extents");
|
||||
|
||||
push_value(L, width);
|
||||
push_value(L, height);
|
||||
push_value(L, descent);
|
||||
push_value(L, extlead);
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" int luaopen_lpeg (lua_State *L);
|
||||
|
@ -198,19 +295,56 @@ extern "C" int luaopen_lpeg (lua_State *L);
|
|||
namespace Automation4 {
|
||||
int regex_init(lua_State *L);
|
||||
|
||||
// LuaScript
|
||||
class LuaScript : public Script {
|
||||
lua_State *L;
|
||||
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string author;
|
||||
std::string version;
|
||||
|
||||
std::vector<cmd::Command*> macros;
|
||||
std::vector<ExportFilter*> filters;
|
||||
|
||||
/// load script and create internal structures etc.
|
||||
void Create();
|
||||
/// destroy internal structures, unreg features and delete environment
|
||||
void Destroy();
|
||||
|
||||
static int LuaInclude(lua_State *L);
|
||||
static int LuaModuleLoader(lua_State *L);
|
||||
|
||||
public:
|
||||
LuaScript(agi::fs::path const& filename);
|
||||
~LuaScript() { Destroy(); }
|
||||
|
||||
void RegisterCommand(LuaCommand *command);
|
||||
void UnregisterCommand(LuaCommand *command);
|
||||
void RegisterFilter(LuaExportFilter *filter);
|
||||
|
||||
static LuaScript* GetScriptObject(lua_State *L);
|
||||
|
||||
// Script implementation
|
||||
void Reload() { Create(); }
|
||||
|
||||
std::string GetName() const { return name; }
|
||||
std::string GetDescription() const { return description; }
|
||||
std::string GetAuthor() const { return author; }
|
||||
std::string GetVersion() const { return version; }
|
||||
bool GetLoadedState() const { return L != 0; }
|
||||
|
||||
std::vector<cmd::Command*> GetMacros() const { return macros; }
|
||||
std::vector<ExportFilter*> GetFilters() const { return filters; }
|
||||
std::vector<SubtitleFormat*> GetFormats() const { return std::vector<SubtitleFormat*>(); }
|
||||
};
|
||||
|
||||
LuaScript::LuaScript(agi::fs::path const& filename)
|
||||
: Script(filename)
|
||||
, L(0)
|
||||
, L(nullptr)
|
||||
{
|
||||
Create();
|
||||
}
|
||||
|
||||
LuaScript::~LuaScript()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void LuaScript::Create()
|
||||
{
|
||||
Destroy();
|
||||
|
@ -283,13 +417,13 @@ namespace Automation4 {
|
|||
|
||||
set_field(L, "register_macro", LuaCommand::LuaRegister);
|
||||
set_field(L, "register_filter", LuaExportFilter::LuaRegister);
|
||||
set_field(L, "text_extents", LuaTextExtents);
|
||||
set_field(L, "frame_from_ms", LuaFrameFromMs);
|
||||
set_field(L, "ms_from_frame", LuaMsFromFrame);
|
||||
set_field(L, "video_size", LuaVideoSize);
|
||||
set_field(L, "keyframes", LuaGetKeyframes);
|
||||
set_field(L, "decode_path", LuaDecodePath);
|
||||
set_field(L, "cancel", LuaCancel);
|
||||
set_field(L, "text_extents", lua_text_textents);
|
||||
set_field(L, "frame_from_ms", frame_from_ms);
|
||||
set_field(L, "ms_from_frame", ms_from_frame);
|
||||
set_field(L, "video_size", video_size);
|
||||
set_field(L, "keyframes", get_keyframes);
|
||||
set_field(L, "decode_path", decode_path);
|
||||
set_field(L, "cancel", cancel_script);
|
||||
set_field(L, "lua_automation_version", 4);
|
||||
set_field(L, "__init_regex", regex_init);
|
||||
set_field(L, "__init_clipboard", clipboard_init);
|
||||
|
@ -301,8 +435,7 @@ namespace Automation4 {
|
|||
_stackcheck.check_stack(0);
|
||||
|
||||
// load user script
|
||||
LuaScriptReader script_reader(GetFilename());
|
||||
if (lua_load(L, script_reader.reader_func, &script_reader, GetPrettyFilename().string().c_str())) {
|
||||
if (!LoadFile(L, GetFilename())) {
|
||||
std::string err = str(boost::format("Error loading Lua script \"%s\":\n\n%s") % GetPrettyFilename().string() % get_string_or_default(L, -1));
|
||||
lua_pop(L, 1);
|
||||
throw ScriptLoadError(err);
|
||||
|
@ -359,12 +492,7 @@ namespace Automation4 {
|
|||
delete_clear(filters);
|
||||
|
||||
lua_close(L);
|
||||
L = 0;
|
||||
}
|
||||
|
||||
void LuaScript::Reload()
|
||||
{
|
||||
Create();
|
||||
L = nullptr;
|
||||
}
|
||||
|
||||
void LuaScript::RegisterCommand(LuaCommand *command)
|
||||
|
@ -397,29 +525,6 @@ namespace Automation4 {
|
|||
return (LuaScript*)ptr;
|
||||
}
|
||||
|
||||
int LuaScript::LuaTextExtents(lua_State *L)
|
||||
{
|
||||
luaL_argcheck(L, lua_istable(L, 1), 1, "");
|
||||
luaL_argcheck(L, lua_isstring(L, 2), 2, "");
|
||||
|
||||
lua_pushvalue(L, 1);
|
||||
agi::scoped_ptr<AssEntry> et(LuaAssFile::LuaToAssEntry(L));
|
||||
AssStyle *st = dynamic_cast<AssStyle*>(et.get());
|
||||
lua_pop(L, 1);
|
||||
if (!st)
|
||||
return luaL_error(L, "Not a style entry");
|
||||
|
||||
double width, height, descent, extlead;
|
||||
if (!CalculateTextExtents(st, luaL_checkstring(L, 2), width, height, descent, extlead))
|
||||
return luaL_error(L, "Some internal error occurred calculating text_extents");
|
||||
|
||||
push_value(L, width);
|
||||
push_value(L, height);
|
||||
push_value(L, descent);
|
||||
push_value(L, extlead);
|
||||
return 4;
|
||||
}
|
||||
|
||||
/// @brief Module loader which uses our include rather than Lua's, for unicode file support
|
||||
/// @param L The Lua state
|
||||
/// @return Always 1 per loader_Lua?
|
||||
|
@ -431,18 +536,27 @@ namespace Automation4 {
|
|||
|
||||
// Get the lua package include path (which the user may have modified)
|
||||
lua_getglobal(L, "package");
|
||||
push_value(L, "path");
|
||||
lua_gettable(L, -2);
|
||||
lua_getfield(L, -1, "path");
|
||||
std::string package_paths(luaL_checkstring(L, -1));
|
||||
lua_pop(L, 2);
|
||||
|
||||
boost::char_separator<char> sep(";");
|
||||
for (auto filename : boost::tokenizer<boost::char_separator<char>>(package_paths, sep)) {
|
||||
boost::replace_all(filename, "?", module);
|
||||
|
||||
// If there's a .moon file at that path, load it instead of the
|
||||
// .lua file
|
||||
agi::fs::path path = filename;
|
||||
if (agi::fs::HasExtension(path, "lua")) {
|
||||
agi::fs::path moonpath = path;
|
||||
moonpath.replace_extension("moon");
|
||||
if (agi::fs::FileExists(moonpath))
|
||||
path = moonpath;
|
||||
}
|
||||
|
||||
try {
|
||||
LuaScriptReader script_reader(filename);
|
||||
if (lua_load(L, script_reader.reader_func, &script_reader, filename.c_str()))
|
||||
return luaL_error(L, "Error loading Lua module \"%s\":\n\n%s", filename.c_str(), luaL_checkstring(L, -1));
|
||||
if (!LoadFile(L, path))
|
||||
return luaL_error(L, "Error loading Lua module \"%s\":\n\n%s", path.string().c_str(), luaL_checkstring(L, -1));
|
||||
break;
|
||||
}
|
||||
catch (agi::fs::FileNotFound const&) {
|
||||
|
@ -452,7 +566,7 @@ namespace Automation4 {
|
|||
// Not an error so swallow and continue on
|
||||
}
|
||||
catch (agi::Exception const& e) {
|
||||
return luaL_error(L, "Error loading Lua module \"%s\":\n\n%s", filename.c_str(), e.GetChainedMessage().c_str());
|
||||
return luaL_error(L, "Error loading Lua module \"%s\":\n\n%s", path.string().c_str(), e.GetChainedMessage().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -480,8 +594,7 @@ namespace Automation4 {
|
|||
if (!agi::fs::FileExists(filepath))
|
||||
return luaL_error(L, "Lua include not found: %s", filename.c_str());
|
||||
|
||||
LuaScriptReader script_reader(filepath);
|
||||
if (lua_load(L, script_reader.reader_func, &script_reader, filename.c_str()))
|
||||
if (!LoadFile(L, filepath))
|
||||
return luaL_error(L, "Error loading Lua include \"%s\":\n\n%s", filename.c_str(), luaL_checkstring(L, -1));
|
||||
|
||||
int pretop = lua_gettop(L) - 1; // don't count the function value itself
|
||||
|
@ -489,80 +602,6 @@ namespace Automation4 {
|
|||
return lua_gettop(L) - pretop;
|
||||
}
|
||||
|
||||
int LuaScript::LuaFrameFromMs(lua_State *L)
|
||||
{
|
||||
const agi::Context *c = get_context(L);
|
||||
int ms = lua_tointeger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
if (c && c->videoController->TimecodesLoaded())
|
||||
push_value(L, c->videoController->FrameAtTime(ms, agi::vfr::START));
|
||||
else
|
||||
lua_pushnil(L);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScript::LuaMsFromFrame(lua_State *L)
|
||||
{
|
||||
const agi::Context *c = get_context(L);
|
||||
int frame = lua_tointeger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
if (c && c->videoController->TimecodesLoaded())
|
||||
push_value(L, c->videoController->TimeAtFrame(frame, agi::vfr::START));
|
||||
else
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScript::LuaVideoSize(lua_State *L)
|
||||
{
|
||||
const agi::Context *c = get_context(L);
|
||||
if (c && c->videoController->IsLoaded()) {
|
||||
push_value(L, c->videoController->GetWidth());
|
||||
push_value(L, c->videoController->GetHeight());
|
||||
push_value(L, c->videoController->GetAspectRatioValue());
|
||||
push_value(L, (int)c->videoController->GetAspectRatioType());
|
||||
return 4;
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int LuaScript::LuaGetKeyframes(lua_State *L)
|
||||
{
|
||||
const agi::Context *c = get_context(L);
|
||||
if (!c) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<int> const& kf = c->videoController->GetKeyFrames();
|
||||
|
||||
lua_newtable(L);
|
||||
for (size_t i = 0; i < kf.size(); ++i) {
|
||||
push_value(L, kf[i]);
|
||||
lua_rawseti(L, -2, i);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScript::LuaDecodePath(lua_State *L)
|
||||
{
|
||||
std::string path = luaL_checkstring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
push_value(L, config::path->Decode(path));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScript::LuaCancel(lua_State *L)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
void LuaThreadedCall(lua_State *L, int nargs, int nresults, std::string const& title, wxWindow *parent, bool can_open_config)
|
||||
{
|
||||
bool failed = false;
|
||||
|
@ -934,18 +973,15 @@ namespace Automation4 {
|
|||
}
|
||||
|
||||
LuaScriptFactory::LuaScriptFactory()
|
||||
: ScriptFactory("Lua", "*.lua")
|
||||
: ScriptFactory("Lua", "*.lua,*.moon")
|
||||
{
|
||||
Register(this);
|
||||
}
|
||||
|
||||
Script* LuaScriptFactory::Produce(agi::fs::path const& filename) const
|
||||
{
|
||||
// Just check if file extension is .lua
|
||||
// Reject anything else
|
||||
if (agi::fs::HasExtension(filename, "lua"))
|
||||
if (agi::fs::HasExtension(filename, "lua") || agi::fs::HasExtension(filename, "moon"))
|
||||
return new LuaScript(filename);
|
||||
else
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -276,54 +276,4 @@ namespace Automation4 {
|
|||
|
||||
void ProcessSubs(AssFile *subs, wxWindow *export_dialog);
|
||||
};
|
||||
|
||||
class LuaScript : public Script {
|
||||
lua_State *L;
|
||||
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string author;
|
||||
std::string version;
|
||||
|
||||
std::vector<cmd::Command*> macros;
|
||||
std::vector<ExportFilter*> filters;
|
||||
|
||||
/// load script and create internal structures etc.
|
||||
void Create();
|
||||
/// destroy internal structures, unreg features and delete environment
|
||||
void Destroy();
|
||||
|
||||
static int LuaTextExtents(lua_State *L);
|
||||
static int LuaInclude(lua_State *L);
|
||||
static int LuaModuleLoader(lua_State *L);
|
||||
static int LuaFrameFromMs(lua_State *L);
|
||||
static int LuaMsFromFrame(lua_State *L);
|
||||
static int LuaVideoSize(lua_State *L);
|
||||
static int LuaGetKeyframes(lua_State *L);
|
||||
static int LuaDecodePath(lua_State *L);
|
||||
static int LuaCancel(lua_State *L);
|
||||
|
||||
public:
|
||||
LuaScript(agi::fs::path const& filename);
|
||||
~LuaScript();
|
||||
|
||||
void RegisterCommand(LuaCommand *command);
|
||||
void UnregisterCommand(LuaCommand *command);
|
||||
void RegisterFilter(LuaExportFilter *filter);
|
||||
|
||||
static LuaScript* GetScriptObject(lua_State *L);
|
||||
|
||||
// Script implementation
|
||||
void Reload();
|
||||
|
||||
std::string GetName() const { return name; }
|
||||
std::string GetDescription() const { return description; }
|
||||
std::string GetAuthor() const { return author; }
|
||||
std::string GetVersion() const { return version; }
|
||||
bool GetLoadedState() const { return L != 0; }
|
||||
|
||||
std::vector<cmd::Command*> GetMacros() const { return macros; }
|
||||
std::vector<ExportFilter*> GetFilters() const { return filters; }
|
||||
std::vector<SubtitleFormat*> GetFormats() const { return std::vector<SubtitleFormat*>(); }
|
||||
};
|
||||
}
|
||||
|
|
|
@ -22,33 +22,41 @@
|
|||
#include "auto4_lua_scriptreader.h"
|
||||
|
||||
#include <libaegisub/io.h>
|
||||
#include <libaegisub/fs.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <lua.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace Automation4 {
|
||||
LuaScriptReader::LuaScriptReader(agi::fs::path const& filename)
|
||||
: file(agi::io::Open(filename))
|
||||
, first(true)
|
||||
{
|
||||
}
|
||||
bool LoadFile(lua_State *L, agi::fs::path const& filename) {
|
||||
std::unique_ptr<std::istream> file(agi::io::Open(filename, true));
|
||||
file->seekg(0, std::ios::end);
|
||||
size_t size = file->tellg();
|
||||
file->seekg(0, std::ios::beg);
|
||||
|
||||
LuaScriptReader::~LuaScriptReader() { }
|
||||
std::string buff;
|
||||
buff.resize(size);
|
||||
|
||||
const char *LuaScriptReader::Read(size_t *bytes_read) {
|
||||
file->read(buf, sizeof(buf));
|
||||
*bytes_read = file->gcount();
|
||||
if (first) {
|
||||
first = false;
|
||||
// Skip the bom
|
||||
if (*bytes_read >= 3 && buf[0] == -17 && buf[1] == -69 && buf[2] == -65) {
|
||||
*bytes_read -= 3;
|
||||
return buf + 3;
|
||||
}
|
||||
// Discard the BOM if present
|
||||
file->read(&buff[0], 3);
|
||||
size_t start = file->gcount();
|
||||
if (start == 3 && buff[0] == -17 && buff[1] == -69 && buff[2] == -65) {
|
||||
buff.resize(size - 3);
|
||||
start = 0;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char* LuaScriptReader::reader_func(lua_State *, void *data, size_t *size) {
|
||||
return static_cast<LuaScriptReader*>(data)->Read(size);
|
||||
file->read(&buff[start], size - start);
|
||||
|
||||
if (!agi::fs::HasExtension(filename, "moon"))
|
||||
return luaL_loadbuffer(L, &buff[0], buff.size(), filename.string().c_str()) == 0;
|
||||
|
||||
// We have a MoonScript file, so we need to load it with that
|
||||
// It might be nice to have a dedicated lua state for compiling
|
||||
// MoonScript to Lua
|
||||
if (luaL_dostring(L, "return require('moonscript').loadstring"))
|
||||
return false; // Leaves error message on stack
|
||||
lua_pushlstring(L, &buff[0], buff.size());
|
||||
return lua_pcall(L, 1, 1, 0) == 0; // Leaves script or error message on stack
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,23 +19,8 @@
|
|||
|
||||
#include <libaegisub/fs_fwd.h>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
struct lua_State;
|
||||
|
||||
namespace Automation4 {
|
||||
class LuaScriptReader {
|
||||
std::unique_ptr<std::istream> file;
|
||||
bool first;
|
||||
char buf[512];
|
||||
|
||||
const char *Read(size_t *bytes_read);
|
||||
public:
|
||||
LuaScriptReader(agi::fs::path const& filename);
|
||||
~LuaScriptReader();
|
||||
|
||||
static const char* reader_func(lua_State *, void *data, size_t *size);
|
||||
};
|
||||
bool LoadFile(lua_State *L, agi::fs::path const& filename);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue