Skip to content

Commit

Permalink
🧱 Update proof and blockquote for typst
Browse files Browse the repository at this point in the history
  • Loading branch information
rowanc1 committed Oct 30, 2024
1 parent eb411d0 commit 49d5c8b
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 20 deletions.
5 changes: 5 additions & 0 deletions .changeset/silent-badgers-begin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"myst-to-typst": patch
---

add proof and change blockquote
32 changes: 24 additions & 8 deletions packages/myst-to-typst/src/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ function renderFigureChild(node: GenericNode, state: ITypstSerializer) {
if (useBrackets) state.write('\n]');
}

function getDefaultCaptionSupplement(kind: CaptionKind | string) {
export function getDefaultCaptionSupplement(kind: CaptionKind | string) {
if (kind === 'code') kind = 'program';
const domain = kind.includes(':') ? kind.split(':')[1] : kind;
return `${domain.slice(0, 1).toUpperCase()}${domain.slice(1)}`;
Expand All @@ -55,7 +55,6 @@ export const containerHandler: Handler = (node, state) => {
});
return;
}

state.ensureNewLine();
const prevState = state.data.isInFigure;
state.data.isInFigure = true;
Expand All @@ -73,6 +72,28 @@ export const containerHandler: Handler = (node, state) => {
source: 'myst-to-typst',
});
}
const flatCaptions = captions
.map((cap: GenericNode) => cap.children)
.filter(Boolean)
.flat();

if (node.kind === 'quote') {
const prevIsInBlockquote = state.data.isInBlockquote;
state.data.isInBlockquote = true;
state.write('#quote(block: true');
if (flatCaptions.length > 0) {
state.write(', attribution: [');
state.renderChildren(flatCaptions);
state.write('])[');
} else {
state.write(')[');
}
state.renderChildren(nonCaptions);
state.write(']');
state.data.isInBlockquote = prevIsInBlockquote;
return;
}

if (nonCaptions && nonCaptions.length > 1) {
const allSubFigs =
nonCaptions.filter((item: GenericNode) => item.type === 'container').length ===
Expand Down Expand Up @@ -114,12 +135,7 @@ export const containerHandler: Handler = (node, state) => {
}
if (captions?.length) {
state.write('\n caption: [\n');
state.renderChildren({
children: captions
.map((cap: GenericNode) => cap.children)
.filter(Boolean)
.flat(),
});
state.renderChildren(flatCaptions);
state.write('\n],');
}
if (kind) {
Expand Down
67 changes: 55 additions & 12 deletions packages/myst-to-typst/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Plugin } from 'unified';
import type { VFile } from 'vfile';
import type { GenericNode } from 'myst-common';
import { fileError, fileWarn, toText, getMetadataTags } from 'myst-common';
import { captionHandler, containerHandler } from './container.js';
import { captionHandler, containerHandler, getDefaultCaptionSupplement } from './container.js';
import type {
Handler,
ITypstSerializer,
Expand Down Expand Up @@ -57,12 +57,6 @@ const admonitionMacros = {
'#let warningBlock(body, heading: [Warning]) = admonition(body, heading: heading, color: yellow)',
};

const blockquote = `#let blockquote(node, color: gray) = {
let stroke = (left: 2pt + color.darken(20%))
set text(fill: black.lighten(40%), style: "oblique")
block(width: 100%, inset: 8pt, stroke: stroke)[#node]
}`;

const tabSet = `
#let tabSet(body) = {
block(width: 100%, stroke: luma(240), [#body])
Expand All @@ -79,6 +73,26 @@ const tabItem = `
])
}`;

const proof = `
#let proof(body, heading: none, 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 @@ -128,8 +142,13 @@ const handlers: Record<string, Handler> = {
state.renderChildren(node, 2);
},
blockquote(node, state) {
state.useMacro(blockquote);
state.renderEnvironment(node, 'blockquote');
if (state.data.isInBlockquote) {
state.renderChildren(node);
return;
}
state.write('#quote(block: true)[');
state.renderChildren(node);
state.write(']');
},
definitionList(node, state) {
let dedent = false;
Expand Down Expand Up @@ -282,7 +301,7 @@ const handlers: Record<string, Handler> = {
}
state.useMacro(admonitionMacros[node.kind]);
state.write(`#${node.kind}Block`);
if (title && toText(title).toLowerCase().replace(' ', '') !== node.kind) {
if (title && toText(title).toLowerCase().replaceAll(' ', '') !== node.kind) {
state.write('(heading: [');
state.renderChildren(title);
state.write('])');
Expand Down Expand Up @@ -416,6 +435,25 @@ 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();
},
};

class TypstSerializer implements ITypstSerializer {
Expand Down Expand Up @@ -474,10 +512,15 @@ class TypstSerializer implements ITypstSerializer {
}

renderChildren(
node: Partial<Parent>,
node: Partial<Parent> | Parent[],
trailingNewLines = 0,
{ delim = '', trimEnd = true }: RenderChildrenOptions = {},
opts: RenderChildrenOptions = {},
) {
if (Array.isArray(node)) {
this.renderChildren({ children: node }, trailingNewLines, opts);
return;
}
const { delim = '', trimEnd = true } = opts;
const numChildren = node.children?.length ?? 0;
node.children?.forEach((child, index) => {
if (!child) return;
Expand Down
1 change: 1 addition & 0 deletions packages/myst-to-typst/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type Options = {
export type StateData = {
tableColumns?: number;
isInFigure?: boolean;
isInBlockquote?: boolean;
isInTable?: boolean;
longFigure?: boolean;
definitionIndent?: number;
Expand Down

0 comments on commit 49d5c8b

Please sign in to comment.