Is there a way to provide global settings for all included documents?

Hello! I’ve been looking to replace Latex and I came across Typst. Overall, I’m loving it, but I’ve encountered one area where Typst seems to be more cumbersome, and I’m wondering how to approach it.

I’ve gotten used to a workflow/document structure where I have (1) a package (a Latex .sty) with custom commands and layouts, (2) a “master document” where I import the package and set the package’s configuration, and (3) other documents that I include in the master document like so: \input{'name of subdocument'}. These subdocuments can use commands from the main package without having to import the package.

I’ve used this structure for submitting creative writing to journals – e.g., each subdocument could be a poem, and the master document would compile a PDF: the header would have my name, plus any other necessary info. Since journals have different requirements, I have a setting for the submission type, which governs things like the kind of info in the header (e.g., a regular submission might include my name, the name of the poem, etc., but a submission to a contest might only include the name of the poem).

With Typst, it seems that I need to include import statements in each document – or have a single file with all import statements, and import that file in each document.

If it’s just a single-line import statement, and if the package(s) only consist of set/show rules, it’s annoying but not a big deal.

The problem comes when I have to configure the package. I’d rather not have to duplicate the configuration across every document, because if I decided to change a setting, I’d have to do so across multiple documents.

Here’s a simplified example of how I have things now in Typst:

// ** manuscript-package.typ ** //

#let custom-linenum = state("custom-linenum", 0)

// layout rules
#let template(
    name: "",
    font-family: "",
    font-size: 12pt,
    submission-type: "",
    section-style: "",
    // etc. //
) = {
    set text(
        font: font-family,
        size: font-size
    )

    set page(
        header: {
            if submission-type === "type1" {
                // code for type1 header
            } else if submission-type === "type2" {
                // code for type2 header
            }
        }
    )

    show heading.where(level: 2): it => {
        if section-style === "style1" {
            // style1 heading
        } else if section-style === "style2" {
            // style2 heading
        }
    }
}

// functions, default settings, etc.
#let setup(
    name: "My Name",
    font-family: "Great Font",
    font-size: 12pt,
    submission-type: "type1",
    section-style: "style1",
    enable-linenum: true,
    linenum-interval: 5,
    // etc.//
) = {
    #let display-linenum(..options) = {
        //custom implementation of line numbering
    }
    
    #let line-end(..options) = {
        context if enable-linenum {
            // only display line number at specified interval
            if calc.rem(custom-linenum.get().first(), linenum-interval) == 0 {
                display-linenum()
            }

            // etc. //
            
           linebreak()
        }
    }

    // ...other functions... //

    let template = template.with(
        name: name,        
        font-family: font-family,
        // etc. //
    )

    (
        line-end: line-end,
        // ...other functions... //
        template: template
    )
}


// ** master document ** //
#import "master-package.typ": setup

#let (line-end, <<...other functions...>>, template) = setup(name: "My Name", font-family: "Wonderful Font", <<etc.>>)

#show: template

#include "subdocument1.typ"
#include "subdocument2.typ"
#include "subdocument2.typ"
 

I think Typst is overall more concise and easier to handle than Latex (I’ve essentially duplicated my Latex package with far less code in Typst), but I don’t care for the repetition/boilerplate needed to implement my preferred document structure.

I’d appreciate any insights or advice!

EDIT: Corrected some minor mistakes in the code block.

1 Like

Your post is a bit long, but your question looks like a language-independent question, perhaps it can be solved by a single shell script. For example:

# submit.sh
typst c main.typ --input doc=path/to/docA --input journal=ieee --input region=india
typst c main.typ --input doc=path/to/docA --input journal=ieee --input region=usa
typst c main.typ --input doc=path/to/docB --input journal=nature --input region=india

Does that work for you?

Thanks for the response.

I see how the script process would go. It’s an alternative I hadn’t considered. However, after exploring the forum more, I think I’ve found a solution that fits more readily into my current workflow. I’ll describe that in my next post.

If my original post wasn’t sufficiently informative, direct, etc., I’d appreciate constructive comments on how I can make my posts more useful to forum readers. Otherwise, I’m not sure how this is relevant.

AFAICT, the approach I outlined in my original post appears to be the standard (or at least typical) way to do it in Typst. However, using Elembic, I can pretty much duplicate my workflow from LaTeX.

I’ve rewritten my user-defined functions as Elembic elements and placed them in their own file. Then, I have a template file with a “settings” element, which only needs to be imported in the master document. I based this on the Simple Thesis Example from Elembic’s documentation.

Here’s an example:

// ** manuscript-elements.typ ** //
#import "@preview/elembic:1.1.1" as e

#let first-element = e.element.declare( /* etc. */ )
#let second-element = e.element.declare( /* etc. */ )
#let third-element = e.element.declare( /* etc. */ )


// ** manuscript-template.typ ** //
#import "@preview/elembic:1.1.1" as e

#let settings = e.element.declare( /* etc. */ )

#let template(doc) = e.get(get => {
  let opts = get(settings)
  
  // etc. //

})


// ** master document ** //
#import "@preview/elembic:1.1.1" as e
#import "manuscript-template.typ": settings, template

#show: e.set_(
  settings,
  field1: "Value",
  field2: "Other value"
)

#show: template

#include "subdocument1.typ"
#include "subdocument2.typ"
#include "subdocument2.typ"


// ** Subdocument 1 ** //
#import "@preview/elembic:1.1.1" as e
#import "manuscript-elements.typ": first-element

#show: e.set_(
  first-element,
  some-field: "Some value"
)

#first-element( /* etc. */ )