Possible to import file body without style?

I’m stuck in a situation where I want to be able to access the body of a file in other files without certain styling /show rules, but I can only see two options.

#let note = (
  meta: (
    name: "note1",
    uuid: "rupiv",
  ),
  body: [
    Note contents
  ],
)
#apply-style-and-display(note)

then, in the file where I want to use the body for other things,

#import "note.typ": note
// do stuff

.
The other option would be:

#let meta = (
    name: "note1",
    uuid: "rupiv",
)

Note contents

then to render the single-note file,

#import "note.typ": meta
#let body = include("note.typ")
#apply-style-and-display((meta: meta, body: body))

and to use the note for other things,

#import "note.typ": meta
#let body = include("note.typ")
// do stuff

.
The ergonomics of both suck. The pattern I’m looking to create would be something like:

#let meta = (
    name: "note1",
    uuid: "rupiv",
)
#show: apply-style.with(meta)

Note contents

then to use the note for other things,

#import "note.typ": meta, body-without-style

Unfortunately, I can’t find a way to only apply the style when the single note is being rendered rather than being imported/included without adding a bunch of boilerplate to the note itself.

If there were some way for show rules to return “it”, then this pattern would be easy. Just,

#let meta = (
    name: "note1",
    uuid: "rupiv",
)
#let body = show: it => apply-style(meta, it) // returning "it" somehow

Note contents

If I understand your requirements correctly, the following solves the problem:

#let meta = (
    name: "note1",
    uuid: "rupiv",
)
// this has to be a function. If it wasn't,
// there'd be a cyclic import preventing this from working
#let body() = {
  let body = include "note.typ"

  // the whole file is a sequence, and the last item is what
  // the `show: ...` rule makes out of the actual content
  let body = body.children.last()
  // we can assure that the first item in that sequence
  // will be a metadata element containing the raw body
  let body = body.children.first().value

  body
}

#show: body => {
  // this has to be the first thing
  // be sure to use `{...}` instead of `[...]` to avoid spaces
  metadata(body)
  [= Note]
  set text(red)
  body
}

Note contents

 

#import "note.typ": meta, body

#include "note.typ"

#body()

I tried to use an example show rule that is sufficiently complex (it styles and also adds content to the raw body). That means that the actual raw body could be nested deep inside what the show rule produces, but by placing some metadata in the beginning we can circumvent any complications and (hopefully) reliably find the raw content.

2 Likes

Ooh, that’s exactly it. I hadn’t explored methods on content and assumed that it was just a black box. But being able to explore everything within a content opens up so many things. Thanks for the pointer.

You’re welcome! definitely look at the repr() function, or simply call func() and fields() methods to find what’s inside a piece of content, it can help with exploring your options.

1 Like