Builds as one slide per step when the template has Build 1, 2, ... (v1.3.2)

- Template.step_builds: build slides without ProPresenter's build feature;
  each build in the notes becomes one slide per step from the template's
  k-th build slide (last one reused): heading + first item, then one more
  line per slide; font runs cut to each step's text
- Build headings (":"/"?"/italic, or above a numbered / same-word list) kept
  as Line.lead; TextEdit format marks them with ">"
- Prefer a one-slide-per-step template over a newer old-style one
- Clear message when a notes file in Google Drive can't be read
- README: builds, underline, fonts are never changed

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-22 11:40:04 -04:00
co-authored by Claude Opus 5.5
parent f2306f781e
commit 042fe30396
7 changed files with 145 additions and 22 deletions
Binary file not shown.
+37 -1
View File
@@ -144,7 +144,43 @@ def main():
check("fill-in blanks are not underline marks", plantext.parse_bold("Faith is ______.") ==
[("Faith is ______.", False, False, False)])
# 8. other campuses: their template names, and who preaches there according to the email
# 8. a template with one slide per build step (Build 1, Build 2, ...) instead of the build feature
STEP = os.path.join(PRO, "_TEMPLATE_GENERIC - DO NOT DELETE 2609-1.pro")
stpl = deck.Template(open(STEP, "rb").read())
check("step template detected", stpl.step_builds and len(stpl.builds) == 4 and not tpl.step_builds)
p8 = notes.parse(open(os.path.join(NOTES, "Slides - Where is Your Faith - Part 8.rtf"), "rb").read())
out = slides_of(deck.build(stpl, p8, "TEST", stpl.speaker()))
check("step deck slide count", len(out) == deck.slide_count(stpl, p8), "%d vs %d" % (len(out), deck.slide_count(stpl, p8)))
steps = [(lab, texts[0][1]) for lab, texts in out if lab.startswith("Build")]
flaw = ["What is your FLAW?", "1. FEARFUL INSECURITY - Gideon and Barak", "2. FLESHLY IMPULSES - David and Samson",
"3. FAMILY DYSFUNCTION - David and Jephthah"]
want = [("Build %d" % k, " / ".join(flaw[:k + 1])) for k in (1, 2, 3)]
check("build steps: heading + one more line per slide", steps[:3] == want, "%s" % steps[:3])
check("second build: 3 steps from Build 1-3", [s[0] for s in steps[3:]] == ["Build 1", "Build 2", "Build 3"]
and steps[5][1].count(" / ") == 3, "%s" % steps[3:])
check("no STREAM DECK slide with step builds", not any("STREAM DECK" in lab for lab, _ in out))
nums = deck.slide_numbers(stpl, p8)
firsts = [nums[i] for i, s in enumerate(p8.slides) if s.kind == "build"]
check("slide numbers point at each build's first step", [out[n - 1][0] for n in firsts] == ["Build 1", "Build 1"],
"%s" % firsts)
five = notes.Plan()
five.slides = [p8.slides[0], notes.Slide("build", [notes.Line([("Heading:", False, False)], lead=True)] +
[notes.Line([("Item %d" % k, False, False)]) for k in range(1, 6)])]
out5 = [(lab, texts[0][1]) for lab, texts in slides_of(deck.build(stpl, five, "TEST", stpl.speaker()))
if lab.startswith("Build")]
check("a 5-item build: 5 slides, the last template slide reused",
[l for l, _ in out5] == ["Build 1", "Build 2", "Build 3", "Build 4", "Build 4"]
and out5[-1][1] == "Heading: / Item 1 / Item 2 / Item 3 / Item 4 / Item 5", "%s" % out5)
runs = [{"loc": 0, "len": 10}, {"loc": 10, "len": 30}, {"loc": 40, "len": 5}]
data = deck.make_rtf(stpl.style("build", "build"), [(0, [("What is your FLAW?", False, False, False)]),
(0, [("1. FEARFUL", False, False, False)])])
check("font runs cut to a step's text", deck.clip_runs(runs, data) == [{"loc": 0, "len": 10}, {"loc": 10, "len": 19}])
rt = plantext.load(plantext.dump(p8, "x"))
check("build heading survives the TextEdit round trip",
[l.lead for s in p8.slides if s.kind == "build" for l in s.lines] ==
[l.lead for s in rt.slides if s.kind == "build" for l in s.lines])
# 9. other campuses: their template names, and who preaches there according to the email
import app
import settings
for n, want in (("_TEMPLATE - DO NOT DELETE 2608 Lower Thirds.pro", True),