Add support for variable loops in kara-templater, and add a few more utility functions.

- Variable loops are controlled using the tenv.maxloop(newmax) function to set the loop counter max. This is a wrapper around setting tenv.maxj.
- Add tenv.relayer(newlayer) function for changing the Layer of an output line.
- Add tenv.restyle(newstyle) function for changing the Style of an output line, despite this usually breaking positioning/sizing information.
- tenv.maxloops is an alias for tenv.maxloop.
- tenv.loopctl(newj, newmaxj) controls both loop variables if anyone wants to do that.
This closes #753 but documentation still needs to be written.

Originally committed to SVN as r2913.
This commit is contained in:
Niels Martin Hansen 2009-05-12 16:36:51 +00:00
parent 277adad41f
commit d71fa2d85c

View file

@ -265,6 +265,26 @@ function matching_templates(templates, line, tenv)
return test_next
end
-- Iterator function, run a loop using tenv.j and tenv.maxj as loop controllers
function template_loop(tenv, initmaxj)
local oldmaxj = initmaxj
tenv.maxj = initmaxj
tenv.j = 0
local function itor()
if tenv.j >= tenv.maxj or aegisub.progress.is_cancelled() then
return nil
else
tenv.j = tenv.j + 1
if oldmaxj ~= tenv.maxj then
aegisub.debug.out(5, "Number of loop iterations changed from %d to %d\n", oldmaxj, tenv.maxj)
oldmaxj = tenv.maxj
end
return tenv.j, tenv.maxj
end
end
return itor
end
-- Apply the templates
function apply_templates(meta, styles, subs, templates)
@ -278,6 +298,8 @@ function apply_templates(meta, styles, subs, templates)
}
tenv.tenv = tenv
-- Define helper functions in tenv
tenv.retime = function(mode, addstart, addend)
local line, syl = tenv.line, tenv.syl
local newstart, newend = line.start_time, line.end_time
@ -322,8 +344,31 @@ function apply_templates(meta, styles, subs, templates)
line.duration = newend - newstart
return ""
end
tenv.fxgroup = {}
tenv.relayer = function(layer)
line.layer = layer
return ""
end
tenv.restyle = function(style)
line.style = style
line.styleref = styles[style]
return ""
end
tenv.maxloop = function(newmaxj)
tenv.maxj = newmaxj
return ""
end
tenv.maxloops = tenv.maxloop
tenv.loopctl = function(newj, newmaxj)
tenv.j = newj
tenv.maxj = newmaxj
return ""
end
-- run all run-once code snippets
for k, t in pairs(templates.once) do
assert(t.code, "WTF, a 'once' template without code?")
@ -443,8 +488,7 @@ function apply_line(meta, styles, subs, line, templates, tenv)
-- Apply all line templates
aegisub.debug.out(5, "Running line templates\n")
for t in matching_templates(templates.line, line, tenv) do
tenv.j = 0
tenv.maxj = t.loops
if aegisub.progress.is_cancelled() then break end
-- Set varctx for per-line variables
varctx["start"] = varctx.lstart
@ -464,11 +508,15 @@ function apply_line(meta, styles, subs, line, templates, tenv)
varctx.x = varctx.lx
varctx.y = varctx.ly
while tenv.j < t.loops do
tenv.j = tenv.j + 1
for j, maxj in template_loop(tenv, t.loops) do
if t.code then
aegisub.debug.out(5, "Code template, %s\n", t.code)
tenv.line = line
-- Although run_code_template also performs template looping this works
-- by "luck", since by the time the first loop of this outer loop completes
-- the one run by run_code_template has already performed all iterations
-- and has tenv.j and tenv.maxj in a loop-ending state, causing the outer
-- loop to only ever run once.
run_code_template(t, tenv)
else
aegisub.debug.out(5, "Line template, pre = '%s', t = '%s'\n", t.pre, t.t)
@ -512,6 +560,7 @@ function apply_line(meta, styles, subs, line, templates, tenv)
-- Loop over syllables
for i = 0, line.kara.n do
if aegisub.progress.is_cancelled() then break end
local syl = line.kara[i]
aegisub.debug.out(5, "Applying templates to syllable: %s\n", syl.text)
@ -522,6 +571,7 @@ function apply_line(meta, styles, subs, line, templates, tenv)
-- Loop over furigana
for i = 1, line.furi.n do
if aegisub.progress.is_cancelled() then break end
local furi = line.furi[i]
aegisub.debug.out(5, "Applying templates to furigana: %s\n", furi.text)
@ -540,9 +590,7 @@ function run_code_template(template, tenv)
else
local pcall = pcall
setfenv(f, tenv)
tenv.maxj = template.loops
for j = 1, template.loops do
tenv.j = j
for j, maxj in template_loop(tenv, template.loops) do
local res, err = pcall(f)
if not res then
aegisub.debug.out(2, "Runtime error in template code: %s\nCode producing error: %s\n\n", err, template.code)
@ -604,6 +652,8 @@ function apply_syllable_templates(syl, line, templates, tenv, varctx, subs)
-- Loop over all templates matching the line style
for t in matching_templates(templates, line, tenv) do
if aegisub.progress.is_cancelled() then break end
tenv.syl = syl
tenv.basesyl = syl
set_ctx_syl(varctx, line, syl)
@ -631,6 +681,7 @@ end
function apply_one_syllable_template(syl, line, template, tenv, varctx, subs, skip_perchar, skip_multi)
local t = template
if aegisub.progress.is_cancelled() then return false end
aegisub.debug.out(5, "Applying template to one syllable with text: %s\n", syl.text)
@ -697,9 +748,7 @@ function apply_one_syllable_template(syl, line, template, tenv, varctx, subs, sk
run_code_template(t, tenv)
else
aegisub.debug.out(5, "Running %d effect loops\n", t.loops)
tenv.maxj = t.loops
for j = 1, t.loops do
tenv.j = j
for j, maxj in template_loop(tenv, t.loops) do
local newline = table.copy(line)
newline.styleref = syl.style
newline.style = syl.style.name