Files
l3-ocr-exercises/td-corrige.typ
2026-10-16 17:00:37 +02:00

102 lines
3.3 KiB
Typst

#import "@preview/minicise:0.1.0": sheet
#import "@preview/mitex:0.2.7": mitex
#import "@preview/cmarker:0.1.10"
// --------------------------------------------------------- configuration ----
#show: sheet.with(
title: [Exercices de cours -- Corrigés],
course: [Objets connectés et robotique],
semester: [L3 IFA, S5],
date: [2026],
author: [Vincent Lannurien],
)
// the markdown source rendered as the body of this sheet
#let md-source = "td-corrige.md"
// set to `false` to drop the first page with the table of contents
#let show-toc = false
// ---------------------------------------------------------------- styles ----
#show figure.caption: set text(size: 0.9em, fill: luma(70))
// the outline picks up the headings cmarker emits further down
#show outline.entry.where(level: 2): set text(weight: "semibold")
// each `##` heading starts on a fresh page, except the first one, which stays
// on the title page — `weak` avoids a blank page when we are already at the top
#let md-section = counter("md-section")
#show heading.where(level: 2, outlined: true): it => {
context if md-section.get().first() > 0 {
pagebreak(weak: true)
}
md-section.step()
it
}
// ------------------------------------------------------------------ math ----
// hugo goldmark delimits math with `\(...\)` and `\[...\]`, while cmarker
// expects the typst/markdown `$...$` and `$$...$$` forms
#let goldmark-math(markdown) = {
markdown
.replace("\\[", "$$")
.replace("\\]", "$$")
.replace("\\(", "$")
.replace("\\)", "$")
}
// ---------------------------------------------------------------- images ----
// maximum footprint of an image coming from the markdown source
#let img-max-height = 7cm
// set to `none` to drop the frame around screenshots
#let img-stroke = 0.5pt + luma(180)
// scale an image down so it fits both the available width and `img-max-height`,
// without ever blowing it up past its natural size
#let fitted-image(source, ..args) = layout(available => {
let natural = measure(image(source, ..args))
let factor = calc.min(
1.0,
available.width / natural.width,
img-max-height / natural.height,
)
image(source, width: natural.width * factor, ..args)
})
// handle `![alt](src)` and `<img src=... width=... height=...>`
#let md-image(source, alt: none, width: auto, height: auto, ..args) = {
// an explicit width/height in the markdown wins over the automatic fitting
let body = if width == auto and height == auto {
fitted-image(source, alt: alt, ..args)
} else {
image(source, alt: alt, width: width, height: height, ..args)
}
let framed = block(stroke: img-stroke, radius: 3pt, clip: true, body)
// alt text, when there is one, becomes a numbered caption
if alt == none or alt == "" {
align(center, framed)
} else {
figure(framed, caption: alt)
}
}
// ------------------------------------------------------------------- toc ----
// outline's own title is a level-1 heading, which would outrank every heading in
// the source (they start at `##`), so we emit it ourselves at the right level
#if show-toc {
heading(level: 2, outlined: false)[Sommaire]
outline(title: none, depth: 3, indent: 1em)
pagebreak()
}
// ------------------------------------------------------------- exercices ----
#cmarker.render(goldmark-math(read(md-source)), math: mitex, scope: (image: md-image))