How can I create a set of shared `set` and `show` rules which can be imported into a theme?

If I want consistent show and set rules across several templates, I have been trying to do so with a generic styling file, which is imported into each template. This guarantees the consistency, I would think, but in practice does not. E.g., in styling.typ:

#set text( size: 10pt,
          fill: blue,
          font: ("Lato", "Noto Sans", "Fira Sans", ),
          lang: "en",
          ligatures: true,
          discretionary-ligatures: true,
          historical-ligatures: true)

#show math.equation: set text(font: ("Lete Sans Math", "Noto Sans Math", "Fira Math", ),
          ligatures: true,
          discretionary-ligatures: true,
          historical-ligatures: true)
#show raw: set text(font: "Space Mono",
          ligatures: true,
          discretionary-ligatures: true,
          historical-ligatures: true)

while in template.typ:

#let exercise(title: "", date: none, body) = {
  // Set the document's basic properties.
  set document(author: "Me", title: title)
  set page(
    "a4",
    margin: (top: auto, bottom: auto, left: 1cm, right: 1cm),
    header: [
      #set text(0.8em)
      #parbreak()
      #line(stroke: blue+1pt, length: 100%)
   ]
  )

  // Title row.
  align(center)[
    #block(
      text(
        weight: 700,
        size: 1.75em,
        //font: "IBM Plex Serif",
        title
      )
    )
    #v(1em, weak: true)
  ]

  // Main body.
  set par(justify: false, leading: 1em, linebreaks: "optimized")
  include("styling.typ")
  body
}

so that in main.typ:

#import "template.typ": *

#show: exercise.with(
  title: "Hello, World!",
  authors: ((name: "Me", title: "", email: "", affiliation:""),),
  date: "Now",
)

This is body text!

My ultimate goal is to have a set of generic show and set rules that can be used consistently in several different templates (slides, documents, etc) but I can not get it to work correctly. Is this the wrong way to achieve that goal?

These two posts may help:

In case you still don’t understand: In your example, the set and show functions in styling.typ only work within their own scope, which is within styling.typ. Therefore, they cannot style other parts of the document.

To fix this, you need to write a function that takes content and returns styled content, like:

styling.typ

#let styling(it) = {
  set text(
    size: 10pt,
    fill: blue,
    font: ("Lato", "Noto Sans", "Fira Sans"),
    lang: "en",
    ligatures: true,
    discretionary-ligatures: true,
    historical-ligatures: true,
  )

  show math.equation: set text(
    font: ("Lete Sans Math", "Noto Sans Math", "Fira Math"),
    ligatures: true,
    discretionary-ligatures: true,
    historical-ligatures: true,
  )
  show raw: set text(
    font: "Space Mono",
    ligatures: true,
    discretionary-ligatures: true,
    historical-ligatures: true,
  )
  it
}

template.typ

#let exercise(title: "", date: none, body) = {
  ...

  import "styling.typ": styling
  show: styling

  body
}
3 Likes

Thanks very much; I hadn’t thought about using a function to create a new scope in which the styling is applied. For my own edification: what does the include(file) do, then, if not insert text from file into the current scope?

According to Typst Documents, include "bar.typ" will

Evaluates the file at the path bar.typ and returns the resulting content.

So I think included Typst files will be treated as individual documents, which won’t affect current context.

1 Like

If main.typ does #include "a.typ", then all content produced by a.typ will be inserted as if it had been produced by main.typ. So a.typ can affect the rest of the document in the usual ways for content: if a.typ defines a heading, it will be found by a query(heading) anywhere in main.typ. If a.typ increments a counter the effect will be visible in main.typ (because in typst a counter increment is done by inserting a piece of content with the increment instruction), etc.

1 Like

I think the important point here is that #include returns content from the other file, but does not affect the current context, like function parameters changed with #set or functions overwritten with #show.

In my understanding this is similar to Hygienic Macros provided by some programming languages (not C).

2 Likes