Skip to content

Commit

Permalink
📑 Add proof, solution, exercise defaults to typst export (#1757)
Browse files Browse the repository at this point in the history
  • Loading branch information
rowanc1 authored Jan 10, 2025
1 parent a6575fa commit cd69d47
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 39 deletions.
5 changes: 5 additions & 0 deletions .changeset/curvy-geese-retire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"myst-to-typst": patch
---

Add exercise and solution handlers
41 changes: 2 additions & 39 deletions packages/myst-to-typst/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import MATH_HANDLERS, { resolveRecursiveCommands } from './math.js';
import { select, selectAll } from 'unist-util-select';
import type { Admonition, Code, CrossReference, FootnoteDefinition, TabItem } from 'myst-spec-ext';
import { tableCellHandler, tableHandler, tableRowHandler } from './table.js';
import { proofHandlers } from './proofs.js';

export type { TypstResult } from './types.js';

Expand Down Expand Up @@ -73,26 +74,6 @@ const tabItem = `
])
}`;

const proof = `
#let proof(body, heading: [], kind: "proof", supplement: "Proof", labelName: none, color: blue, float: true) = {
let stroke = 1pt + color.lighten(90%)
let fill = color.lighten(90%)
let title
set figure.caption(position: top)
set figure(placement: none)
show figure.caption.where(body: heading): (it) => {
block(width: 100%, stroke: stroke, fill: fill, inset: 8pt, it)
}
place(auto, float: float, block(width: 100%, [
#figure(kind: kind, supplement: supplement, gap: 0pt, [
#set align(left);
#set figure.caption(position: bottom)
#block(width: 100%, fill: luma(253), stroke: stroke, inset: 8pt)[#body]
], caption: heading)
#if(labelName != none){label(labelName)}
]))
}`;

const INDENT = ' ';

const linkHandler = (node: any, state: ITypstSerializer) => {
Expand Down Expand Up @@ -456,25 +437,6 @@ const handlers: Record<string, Handler> = {
state.renderChildren(node);
state.write('\n]\n\n');
},
proof(node: GenericNode, state) {
state.useMacro(proof);
const title = select('admonitionTitle', node);
const kind = node.kind || 'proof';
const supplement = getDefaultCaptionSupplement(kind);
state.write(
`#proof(kind: "${kind}", supplement: "${supplement}", labelName: ${node.identifier ? `"${node.identifier}"` : 'none'}`,
);
if (title) {
state.write(', heading: [');
state.renderChildren(title);
state.write('])[');
} else {
state.write(')[');
}
state.renderChildren(node);
state.write(']');
state.ensureNewLine();
},
card(node, state) {
if (node.url) {
node.children?.push({ type: 'paragraph', children: [{ type: 'text', value: node.url }] });
Expand All @@ -496,6 +458,7 @@ const handlers: Record<string, Handler> = {
footer() {
return;
},
...proofHandlers,
};

class TypstSerializer implements ITypstSerializer {
Expand Down
55 changes: 55 additions & 0 deletions packages/myst-to-typst/src/proofs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { type GenericNode } from 'myst-common';
import type { Handler, ITypstSerializer } from './types.js';
import { getDefaultCaptionSupplement } from './container.js';
import { select } from 'unist-util-select';

const proof = `
#let proof(body, heading: [], kind: "proof", supplement: "Proof", labelName: none, color: blue, float: true) = {
let stroke = 1pt + color.lighten(90%)
let fill = color.lighten(90%)
let title
set figure.caption(position: top)
set figure(placement: none)
show figure.caption.where(body: heading): (it) => {
block(width: 100%, stroke: stroke, fill: fill, inset: 8pt, it)
}
place(auto, float: float, block(width: 100%, [
#figure(kind: kind, supplement: supplement, gap: 0pt, [
#set align(left);
#set figure.caption(position: bottom)
#block(width: 100%, fill: luma(253), stroke: stroke, inset: 8pt)[#body]
], caption: heading)
#if(labelName != none){label(labelName)}
]))
}`;

function writeProof(node: GenericNode, state: ITypstSerializer, kind: string) {
state.useMacro(proof);
const title = select('admonitionTitle', node);
const supplement = getDefaultCaptionSupplement(kind);
state.write(
`#proof(kind: "${kind}", supplement: "${supplement}", labelName: ${node.identifier ? `"${node.identifier}"` : 'none'}`,
);
if (title) {
state.write(', heading: [');
state.renderChildren(title);
state.write('])[\n');
} else {
state.write(')[\n');
}
state.renderChildren(node);
state.write(']');
state.ensureNewLine();
}

export const proofHandlers: Record<string, Handler> = {
proof(node: GenericNode, state) {
writeProof(node, state, node.kind || 'proof');
},
exercise(node: GenericNode, state) {
writeProof(node, state, 'exercise');
},
solution(node: GenericNode, state) {
writeProof(node, state, 'solution');
},
};
16 changes: 16 additions & 0 deletions packages/myst-to-typst/tests/proofs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
title: myst-to-typst code
cases:
- title: proof
mdast:
type: root
children:
- type: exercise
identifier: my-exercise
children:
- type: paragraph
children:
- type: text
value: Recall...
typst: |-
#proof(kind: "exercise", supplement: "Exercise", labelName: "my-exercise")[
Recall...]

0 comments on commit cd69d47

Please sign in to comment.