Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🔧 More typst export improvements #1665

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/beige-ways-learn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'myst-to-typst': patch
---

Allow overriding default breakable value for typst figures
5 changes: 5 additions & 0 deletions .changeset/clean-toys-work.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'myst-to-typst': patch
---

Add hook for customizing table columns in typst
5 changes: 5 additions & 0 deletions .changeset/heavy-melons-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'myst-to-typst': patch
---

Render table legends below tables in typst
5 changes: 5 additions & 0 deletions .changeset/soft-shrimps-brake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'myst-to-typst': patch
---

Support lists that do not start at 1 in typst
5 changes: 5 additions & 0 deletions .changeset/tidy-crabs-rhyme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'myst-to-typst': patch
---

Render cross-references with correct text in typst
5 changes: 5 additions & 0 deletions .changeset/unlucky-adults-fry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'myst-to-typst': patch
---

Support table cell background color in typst
33 changes: 24 additions & 9 deletions packages/myst-to-typst/src/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ export function determineCaptionKind(node: GenericNode): CaptionKind | null {

function renderFigureChild(node: GenericNode, state: ITypstSerializer) {
const useBrackets = node.type !== 'image' && node.type !== 'table';
if (node.type === 'legend') {
state.useMacro('#let legendStyle = (fill: black.lighten(20%), size: 8pt, style: "italic")');
state.write('text(..legendStyle)');
node.type = 'paragraph';
}
if (useBrackets) state.write('[\n');
else state.write('\n ');
state.renderChildren({ children: [node] });
Expand All @@ -60,12 +65,17 @@ export const containerHandler: Handler = (node, state) => {
state.data.isInFigure = true;
const { identifier, kind } = node;
let label: string | undefined = identifier;
const captions = node.children?.filter(
(child: GenericNode) => child.type === 'caption' || child.type === 'legend',
);
const nonCaptions = node.children?.filter(
(child: GenericNode) => child.type !== 'caption' && child.type !== 'legend',
);
const captionTypes = node.kind === 'table' ? ['caption'] : ['caption', 'legend'];
const captions: GenericNode[] = node.children?.filter((child: GenericNode) => {
return captionTypes.includes(child.type);
});
let nonCaptions: GenericNode[] = node.children?.filter((child: GenericNode) => {
return !captionTypes.includes(child.type);
});
nonCaptions = [
...nonCaptions.filter((child) => child.type !== 'legend'),
...nonCaptions.filter((child) => child.type === 'legend'),
];
if (!nonCaptions || nonCaptions.length === 0) {
fileError(state.file, `Figure with no non-caption content: ${label}`, {
node,
Expand Down Expand Up @@ -99,7 +109,10 @@ export const containerHandler: Handler = (node, state) => {
nonCaptions.filter((item: GenericNode) => item.type === 'container').length ===
nonCaptions.length;
state.useMacro('#import "@preview/subpar:0.1.1"');
state.write(`#show figure: set block(breakable: ${allSubFigs ? 'false' : 'true'})\n`);
state.useMacro('#let breakableDefault = true');
state.write(
`#show figure: set block(breakable: ${allSubFigs ? 'false' : 'breakableDefault'})\n`,
);
state.write('#subpar.grid(');
let columns = nonCaptions.length <= 3 ? nonCaptions.length : 2; // TODO: allow this to be customized
nonCaptions.forEach((item: GenericNode) => {
Expand All @@ -123,12 +136,14 @@ export const containerHandler: Handler = (node, state) => {
label = undefined;
}
} else if (nonCaptions && nonCaptions.length === 1) {
state.write('#show figure: set block(breakable: true)\n');
state.useMacro('#let breakableDefault = true');
state.write('#show figure: set block(breakable: breakableDefault)\n');
state.write('#figure(');
renderFigureChild(nonCaptions[0], state);
state.write(',');
} else {
state.write('#show figure: set block(breakable: true)\n');
state.useMacro('#let breakableDefault = true');
state.write('#show figure: set block(breakable: breakableDefault)\n');
state.write('#figure([\n ');
state.renderChildren(node, 1);
state.write('],');
Expand Down
20 changes: 12 additions & 8 deletions packages/myst-to-typst/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,17 @@ const handlers: Record<string, Handler> = {
state.addNewLine();
},
list(node, state) {
const setStart = node.ordered && node.start && node.start !== 1;
if (setStart) {
state.write(`#set enum(start: ${node.start})`);
}
state.data.list ??= { env: [] };
state.data.list.env.push(node.ordered ? '+' : '-');
state.renderChildren(node, 2);
state.renderChildren(node, setStart ? 1 : 2);
state.data.list.env.pop();
if (setStart) {
state.write('#set enum(start: 1)\n\n');
}
},
listItem(node, state) {
const listEnv = state.data.list?.env ?? [];
Expand Down Expand Up @@ -345,7 +352,7 @@ const handlers: Record<string, Handler> = {
caption: captionHandler,
legend: captionHandler,
captionNumber: () => undefined,
crossReference(node: CrossReference, state, parent) {
crossReference(node: CrossReference, state) {
if (node.remote) {
// We don't want to handle remote references, treat them as links
const url =
Expand All @@ -355,13 +362,10 @@ const handlers: Record<string, Handler> = {
linkHandler({ ...node, url: url }, state);
return;
}
// Look up reference and add the text
// const usedTemplate = node.template?.includes('%s') ? node.template : undefined;
// const text = (usedTemplate ?? toText(node))?.replace(/\s/g, '~') || '%s';
const id = node.identifier;
// state.write(text.replace(/%s/g, `@${id}`));
const next = nextCharacterIsText(parent, node);
state.write(next ? `#[@${id}]` : `@${id}`);
state.write(`#link(<${id}>)[`);
state.renderChildren(node);
state.write(']');
},
citeGroup(node, state) {
state.renderChildren(node, 0, { delim: ' ' });
Expand Down
10 changes: 8 additions & 2 deletions packages/myst-to-typst/src/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,12 @@ export const tableHandler: Handler = (node, state) => {
return;
}
state.useMacro('#import "@preview/tablex:0.0.9": tablex, cellx, hlinex, vlinex');
// These two separate style hooks are somewhat redundant, but they allow defining
// article-wide styles and single-table styles separately
state.useMacro('#let tableStyle = (:)');
state.useMacro('#let columnStyle = (:)');
state.write(
`${command}(columns: ${columns}, header-rows: ${countHeaderRows(node)}, repeat-header: true, ..tableStyle,\n`,
`${command}(columns: ${columns}, header-rows: ${countHeaderRows(node)}, repeat-header: true, ..tableStyle, ..columnStyle,\n`,
);
state.renderChildren(node, 1);
state.write(')\n');
Expand All @@ -48,7 +51,7 @@ export const tableRowHandler: Handler = (node, state) => {
};

export const tableCellHandler: Handler = (node, state) => {
if (node.rowspan || node.colspan || node.align) {
if (node.rowspan || node.colspan || node.align || node.style?.backgroundColor) {
state.write('cellx(');
if (node.rowspan) {
state.write(`rowspan: ${node.rowspan}, `);
Expand All @@ -59,6 +62,9 @@ export const tableCellHandler: Handler = (node, state) => {
if (node.align) {
state.write(`align: ${node.align}, `);
}
if (node.style?.backgroundColor) {
state.write(`fill: rgb("${node.style.backgroundColor}"), `);
}
state.write(')');
}
state.write('[\n');
Expand Down
Loading