Hi first of all thanks for the really interesting question.
Touying rn builds the set of slides you could recall as it traverses the tree thus we cannot recall something before it has been inserted into the tree. And we have no easy way to achieve an invisible slide that can be recalled. perhaps that would be a nice feature.
Furthermore we cannot defer the execution of a subslide really, you can only set a limit on the maximum subslide count by passing in repeat to the slide function. And the subslides always start at 1.
I think the easiest solution rn would be to write a function that parses slide content similar to how touying does and just emits what you want.
I wrote up a very simplified version here:
#import "@preview/touying:0.7.4": *
#import themes.simple: *
#show: simple-theme.with(
config-info(
title: "Split Your Slides"
)
)
/// Allows you to relatively simply split your slides. See the example below.
/// Works by parsing the metadata of the animation method and changing the subslides based on your range and emitting it into a repeat fixed slide.
///
/// - s (int): the start of the range you want to show
/// - e (int): the last index of the range you want to show
/// - head (content): a heading to be used for the slide
/// - bodies (content): multiple bodies containing pure `only` or `uncover` functions.
/// -> content
#let split-slide(s,e,head:[== My Heading],..bodies) = {
assert(s<=e, message:"s (="+str(s)+") must be less equal than e (="+str(e)+").")
let parse-body(body) = {
let animation-fns = ("uncover": uncover, "only": only)
let d = (:)
let m = utils.trim(body.children).at(0)
d.insert("fn", animation-fns.at(repr(m.value.fn)))
d.insert("args-cover-fn", m.value.args.at("cover-fn"))
d.insert("args-subslide", m.value.args.at(0))
d.insert("args-body", m.value.args.at(1))
return d
}
let body-dicts = ()
for body in bodies.pos() {
body-dicts.push(parse-body(body))
}
let transform-subslides(body-dict, s, e) = {
let transform-int-subslide(s,r) = {
calc.max(1, r - s + 1)
}
let new-subslide = none
if type(body-dict.args-subslide) == array {
new-subslide = body-dict.args-subslide.map(transform-int-subslide.with(s))
} else if type(body-dict.args-subslide) == int {
new-subslide = transform-int-subslide(s,body-dict.args-subslide)
} else if type(body-dict.args-subslide) == str {
//split into numbers and "-" array
let compute-new-range(subslide) = {
//a-b -> (a, "-", b)
let splitted = subslide.matches(regex("(\\d*)(-)?(\\d*)")).at(0).captures
let this-s = if splitted.at(0)=="" {1} else {int(splitted.at(0))}
let this-e = if splitted.at(2)=="" {1000} else {int(splitted.at(2))}
//compute intersection of both intervals s..e, this-s..this-e.
let union-s = calc.max(s, this-s)
let union-e = calc.min(e, this-e)
let union = union-e - union-s
//compute if visible
let first = if union >= 0 {transform-int-subslide(s, union-s)} else {1000}
(first, splitted.at(1), first+union).map(str).join("")
}
new-subslide = compute-new-range(body-dict.args-subslide)
}
(body-dict.fn)(cover-fn: body-dict.args-cover-fn, new-subslide, body-dict.args-body)
}
let combined-body = ()
for body-dict in body-dicts {
combined-body.push(transform-subslides(body-dict, s,e))
}
slide(repeat:e - s + 1)[
#place(hide(head))
#combined-body.sum()
]
}
#let slide-a(s,e) = split-slide(
s, e,
head:[== Slide A]
)[
#uncover("1-2")[First Content, ]
][
#uncover("2-")[Second Content, ]
][
#uncover("3-")[Third Content]
]
#slide-a(1,2)
== Slide B
#slide[
Number 1,
#pause
Number 2
]
#slide-a(3,3)
You can ofc make this much better but at some point you are just repeating what touying internally does.
Perhaps create an issue and we can think about this. The easiest solution would likely be that we allow passing in some argument into a slide function that tells touying to not emit any of the content but save it in the recaller map still.