From d71fa2d85c9b8a6d2608fa83997908e38203b1dc Mon Sep 17 00:00:00 2001 From: Niels Martin Hansen Date: Tue, 12 May 2009 16:36:51 +0000 Subject: [PATCH] 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. --- .../automation/autoload/kara-templater.lua | 69 ++++++++++++++++--- 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/aegisub/automation/autoload/kara-templater.lua b/aegisub/automation/autoload/kara-templater.lua index 254b8db72..283c843b1 100644 --- a/aegisub/automation/autoload/kara-templater.lua +++ b/aegisub/automation/autoload/kara-templater.lua @@ -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