How to use context instead of a callback function in locate function calls?

I am trying to test the new 0.12.0-rc1 and I keep getting this:

warning: `locate` with callback function is deprecated
    ┌─ template/template.typ:305:12
    │  
305 │       header: locate(
    │ ╭─────────────^
306 │ │       loc => {
307 │ │         // Retrieve the current page number
308 │ │         let pageNumber = counter(page).at(loc).first()
    · │
329 │ │       },
330 │ │     ),
    │ ╰─────^
    │  
    = hint: use a `context` expression instead

And the code I have essentially adds footer and header page numbers:

set page(
    header: locate(
      loc => {
        // Retrieve the current page number
        let pageNumber = counter(page).at(loc).first()

        // Check if the current page starts with a non-chapter heading
        let headings = query(heading.where(level: 1))
        let isSectionPage = headings.any(it => it.location().page() == pageNumber)
        if (not isSectionPage) {
          let before = query(selector(heading.where(level: 1)).before(loc))

          // Create the heading numbering.
          let number = if before.last().numbering != none {
            counter(heading.where(level: 1)).display(before.last().numbering)
            // h(7pt, weak: true)
          }

          return [
            #set text(8pt)
            #smallcaps[Chapter #number. #before.last().body]
            #h(1fr) #pageNumber
            #line(length: 100%)
          ]
        }
      },
    ),
    footer: locate(
      loc => {
        // Retrieve the current page number
        let pageNumber = counter(page).at(loc).first()

        // Check if the current page starts with a non-chapter heading
        let headings = query(heading.where(level: 1))
        let isSectionPage = headings.any(it => it.location().page() == pageNumber)
        if (isSectionPage) {
          return align(center, text(0.95em, str(pageNumber)));
        }

        // If the page is not a section page, don't display anything
        return;
      },
    ),
  )

I couldn’t find an example on how to replace loc => {} with context. How should I do that?

1 Like

Hello!
Don’t hesitate to provide a minimal working example in your post in the future, it helps to reproduce your exact issue and solve the underlying problem.
In this case, the migration from locate(loc => {...}) to a context expression is relatively straightforward:

  • Replace locate(...) with context { ... }
  • Replace loc with here(), although, technically speaking you may even use counter(page).get().first(). See get.
#set page(
    header: context {
        // Retrieve the current page number
        let pageNumber = counter(page).at(here()).first()

        // Check if the current page starts with a non-chapter heading
        let headings = query(heading.where(level: 1))
        let isSectionPage = headings.any(it => it.location().page() == pageNumber)
        if (not isSectionPage) {
          let before = query(selector(heading.where(level: 1)).before(loc))

          // Create the heading numbering.
          let number = if before.last().numbering != none {
            counter(heading.where(level: 1)).display(before.last().numbering)
            // h(7pt, weak: true)
          }

          return [
            #set text(8pt)
            #smallcaps[Chapter #number. #before.last().body]
            #h(1fr) #pageNumber
            #line(length: 100%)
          ]
        }
    },
    footer: context {
        // Retrieve the current page number
        let pageNumber = counter(page).at(here()).first()

        // Check if the current page starts with a non-chapter heading
        let headings = query(heading.where(level: 1))
        let isSectionPage = headings.any(it => it.location().page() == pageNumber)
        if (isSectionPage) {
          return align(center, text(0.95em, str(pageNumber)));
        }

        // If the page is not a section page, don't display anything
        return;
   },
)

I don’t think I’ve seen an explicit guide in the official documentation, but in small text you can read

In Typst 0.10 and lower, the locate function took a closure that made the current location in the document available (like here does now).

For a more detailed explanation and comparison, you can take a look at @laurmaedje’s blog post on the topic.

For page numbers, you can take a look at this post, which gives a good example of a context expression How can I use different page number locations on alternating pages? - #2 by Andrew.

2 Likes