How can I get a regex to match #emph[text]?

in my template, I use

  show regex("^—.*") : it => {
    set text(style: "normal")
    align(right, it)
  }

To catch text that apear at the end of my quotes like:

#quote(block: true, quotes: auto,)[#par()[Subhuti, what is called Buddhism, is not Buddhism.]
#par()[— The Buddha, #emph[Diamond Pranjaparamita Sutta]]
]

But it only catches — The Buddha, and stop after that.

I have tried different regex including escaping # with \ or \\ but nothing works.
Thanks

Is there a reason why you’re not just using the attribution field?

#quote(
  block: true,
  quotes: auto,
  attribution: [The Buddha, _Diamond Pranjaparamita Sutta_]
)[
  Subhuti, what is called Buddhism, is not Buddhism.
]

Thank you for your reply @ssotoen

I actually should have specified the context of my quesiton as I knew about the atribution (which is a nice thing in Typst)

The context of my question is from mdbook-typst and particularly my branch of it. I have been using mdbook-typst to transform my mdbook to a final PDF A5 with custom typst template and it works really well. I can type my book in Obsidian with a mdbook structure and after compiling, I get a nice PDF with footnote, images, quotes etc. transformed from markdown to typst. This is a little dream for me, as I work on a boox tablet and I can generate my book from my obsidian vault via Termux.

Anyway, the thing is that there is no attribution in markdown by default, so I ended up doing:

> Text  
> Text  
>  
> -- Atribution

in my markdown. Then via the typst template I was hoping to left align all my attributions in my quotes in markdown, hence my question.


When I do

  show quote: it => {
    panic(it.body)
  }

in my template, I get this in my terminal:

error: panicked with: sequence(
  sequence(
    parbreak(),
    [Subhuti, what is called Buddhism, is not Buddhism.],
    parbreak(),
  ),
  [ ],
  sequence(
    parbreak(),
    sequence(
      [— The Buddha,],
      [ ],
      emph(body: [Diamond Pranjaparamita Sutta]),
    ),
    parbreak(),
  ),
  [ ],
)

I thought I could access the different fields in the it.body in the show rule to apply different style via if function. But the outcome is that sequence(...), is there a way to access the elements of that sequence? (there is an interesting example here that is even able to give an attribution)

You can get the sequence’s items with .children. To build back a sequence there’s no exposed API but as a hack you can get the constructor with [].func(). Example:

#show quote.where(block: true, attribution: none): it => {
  let elems = it.body.children
  let attr-start = elems.position(x => x == [--])
  if attr-start == none {
    return it
  }
  let body = elems.slice(0, attr-start)
  let attr = elems.slice(attr-start + 1)
  let sequence = [].func()
  quote(block: true, attribution: sequence(attr), sequence(body))
}

#quote(block: true)[
  X

  -- Y
]

though in your case it seems you’ll need more elaborate code to parse the sequence.

Ok thank you, this seems to do the trick

#show quote.where(block: true, attribution: none): it => {
    let elems = it.body.children
    let last-line = elems.at(elems.len()-2).children.at(1)
    let last-line-array = elems.at(elems.len()-2).children
    let first-char 

    if last-line.has("children") {
      first-char = last-line.children.at(0).text.codepoints().at(0)
    } else {
      first-char = last-line.text.codepoints().at(0)
    }

    if first-char != "—" {
    return it
    }

    let body = elems.slice(0, elems.len()-2)
    let sequence = [].func()
    
    last-line-array = last-line-array.slice(1)
    last-line-array = last-line-array.join().children.map(e => {
      if e.has("text") {e.text.replace("— ", "")}
      else {e}
    })
    quote(block: true, attribution: sequence(last-line-array), sequence(body))
  }

the problem was that if you have some italic or something else in your attribution, then instead of having a simple text as content, you have an array. Maybe there is a easier way to treat both case, but I did it separatly.

Thanks for your help

Here is a update version that takes in account en dash as well (which are dash-dash in obsidian)

#show quote.where(block: true, attribution: none): it => {

    let elems = it.body.children
    let last-line = elems.at(elems.len()-2).children.at(1)
    let last-line-array = elems.at(elems.len()-2).children
    let first-char 

    if last-line.has("children") {
      first-char = last-line.children.at(0).text.codepoints().at(0)
    } else {
      first-char = last-line.text.codepoints().at(0)
    }

    if first-char != "—" and first-char != "–" { // second case is for -- used in markdown
    return it
    }

    let body = elems.slice(0, elems.len()-2)
    let sequence = [].func()

      last-line-array = last-line-array.slice(1).join().children
      last-line-array = last-line-array.enumerate().map(((i, e)) => {
      if i == 0 and e == [–] {""} // this is for -- used in markdown
      else if i == 1 and e == [ ] and last-line-array.at(0) == [–] {""}
      else if e.has("text") {e.text.replace("— ", "")} // this is for — used in markdown
      else {e}
    })

    quote(block: true, attribution: sequence(last-line-array), sequence(body))
  }
1 Like