The title seems convoluted, but this is easier to digest description of what I need to do:
I have a file with some bulleted data (data.typ) but some of these data is conditional.
Now I have two other files that include this one, variant1.typ and variant2.typ. If the former includes data.typ it has to show all bullets, only limited ones if included in variant2.typ.
My thinking was a variable data-type that variant files can set, but while I understand limited scopes of these in Typst, I have no idea how to make this work.
Maybe I’m not answering the question; perhaps I’m just clarifying it.
I would have tried a function that shows the list items for which the selector variable is true, as in the following example:
// data.typ
#let bList = [
- b1
- b2
- b3
- b4
]
#let bShow = (true, false, true, false)
// variants.typ
#let bullets(bList, bShow, showAll) = {
let j = 0
for bStr in bList.children {
if bStr != [ ] {
if showAll or bShow.at(j) { bStr }
j += 1
}
}
}
Selected: // only shows items for which selector is true
#bullets(bList, bShow, false)
All:
#bullets(bList, bShow, true)
But perhaps I’m not understanding exactly how the contents of the data.typ is structured? Or is there an issue because the contents is included?
As @Lutz_Hendricks says the preferred method depends on the structure of data.typ, but here are some solutions I can think of:
Define a function in data.typ that returns the desired data:
data.typ:
#let get-data(type) = [
Content for all variants
#if type == 1 [
Content for variant 1
]
#if type == 2 [
Content for variant 2
]
]
variant1.typ:
#import "data.typ": get-data
#get-data(1)
Advantage: clear and robust. No significant disadvantage in my opinion.
Define structured data in data.typ and import it as a variable:
data.typ:
#let data = (
(type: "all", value: [Content for all variants]),
(type: 1, value: [Content for variant 1]),
(type: 2, value: [Content for variant 2]),
)
variant1.typ:
#import "data.typ": data
#{
data.filter(x => x.type in (1, "all"))
.map(x => x.value).join(parbreak())
}
Advantage: data is declarative, you can have different/complicated selection logic in different variant files.
Disadvantage: heavy syntax in data.typ, more complicated to use in variant files.
Set a state in variant files, and use it in data.typ:
variant1.typ:
#state("data-type").update(1)
#include "data.typ"
data.typ:
#context [
#let data-type = state("data-type").get()
Content for all variants
#if data-type == 1 [
Content for variant 1
]
#if data-type == 2 [
Content for variant 2
]
]
Advantage: might feel familiar if you’re used to global variables, and the state can be accessed from any content in any file without having to import a function or variable definition.
Disadvantage: makes the content opaque (you cannot see what’s in a context value), and using a global state without explicit import/include can make the code harder to understand. Also, states are a bit tricky and can be surprising sometimes, see for example here: Why doesn't state behave like the documentation says?
Use labels and show rules:
data.typ:
Content for all variants
#[Content for variant 1]<only1>
#[Content for variant 2]<only2>
variant1.typ:
#show <only2>: none
#include "data.typ"
Advantage: lightweight, declarative syntax so the selection logic can be separated from the data.
Disadvantage: can interfere with other functionality:
A piece of content can only have a single label and you might want to use it for something else.
Content “discarded” with #show ...: none is only hidden from the output, it’s still there in the document and can show up in query results.
While I believe the option 4 is the right way in the end (not like much the only at the end of the label), the options 3 works for me. Both documents contain what they should.
I wasn’t precise that actually data.typ contains fully formatted document with bullets I need to show in one variant and omit in another or replace some bits of the content. #if condition [] works well for me.