How to split (heading) content into seperate strings/contents for styling

Hello

I am trying to find a way to style different parts of a heading body separately.

To do this I need to read the heading body content as a string → Locate the “:” character → Split the string → Render it with different styling:

#show heading.where(level: 5): it => {
  // str(it.body) // ERROR: content can not be converted to str
  // it.body.position(":") // ERROR: Element sequence has no method `position`

  // I need a way to split it.body into "SOLUTION:" and 
  // " Two and three is five" so I can style them separately.

  text(weight: 600, [SOLUTION: ])
  text(weight: 300, [ Two and three is five])
}

===== SOLUTION: Two and three is five

Needed output (first word is bold, the rest is regular text):

SOLUTION: Two and three is five

Further, if anyone knows how to output the different methods on an object I would be greatfull. E.g. what are the methods on the heading? (it.body, it.numbering… what else?)

Short description of my actual use-case:
I am typesetting a book written in markdown, using cmarker to read the markdown and convert to Typst. To style unique part of the markdown, I give it a heading as a handle to grab via Typst show rules, in this case heading with depth 5 is used for math solutions and math notes.

There’s no need to do any string manipulation, you can use regex to match the part of the body that comes after “:” and style that differently:

#show heading.where(level: 5): it => {
  set text(weight: 600)
  show ":": set text(weight: 600)  // undo matching of ":" in show rule
  show regex(":.*"): set text(weight: 300)
  
  it
}

(possibly the show rule matching only “:” could be combined into the regex one, but I am bad with regex…)

You can hover over variables to show what their methods are, this is useful for debugging (see: Tips on debugging Typst code, including the dark magic). Alternatively you can use the repr function.
For headings in particular, all of their methods are also outlined in the docs: Heading - Typst Documentation

heading(
  level: auto|int,
  depth: int,
  offset: int,
  numbering: none|str|function,
  supplement: none|auto|content|function,
  outlined: bool,
  bookmarked: auto|bool,
  hanging-indent: auto|length,
  content       // body
) → content

I don’t know exactly how cmarker works, but if it’s possible i’d pass this data to a custom solution function, instead of doing semi-hacky things with headings :smile: It works here, but for more complex tasks doing it this way is easier, and doesn’t lead to weird artefacts (e.g. you might not want that solutions are headings)

Thanks @aarnent for taking your time to post this detailed answer! It is highly appreciated.

regex is of cause the answer, I did not realize Typst had a regular expression function but if cause it is there.

I agree that using headings as text styling handles is a bit hacky, but it is the only option I found so far. For most local show rules I’m injecting Typst code into the markdown string before rendering, but for specific case I was at a loss.

And thanks for providing details on the repr function, that will come in handy for me.