pi-studio 0.5.22 → 0.5.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/index.ts +77 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,11 @@ All notable changes to `pi-studio` are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.5.23] — 2026-03-20
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- LaTeX PDF export now preprocesses common `algorithm` / `algorithmic` / `algpseudocode` blocks into pandoc-friendly quoted step layouts, improving exported algorithm readability while keeping the existing Studio PDF pipeline.
|
|
11
|
+
|
|
7
12
|
## [0.5.22] — 2026-03-20
|
|
8
13
|
|
|
9
14
|
### Fixed
|
package/index.ts
CHANGED
|
@@ -1560,6 +1560,78 @@ function preprocessStudioLatexAlgorithmsForPreview(markdown: string): StudioLate
|
|
|
1560
1560
|
};
|
|
1561
1561
|
}
|
|
1562
1562
|
|
|
1563
|
+
function renderStudioLatexAlgorithmPdfLines(
|
|
1564
|
+
lines: StudioLatexAlgorithmPreviewLine[],
|
|
1565
|
+
startIndex: number,
|
|
1566
|
+
indent: number,
|
|
1567
|
+
): { latex: string; nextIndex: number } {
|
|
1568
|
+
const parts: string[] = [];
|
|
1569
|
+
let index = startIndex;
|
|
1570
|
+
|
|
1571
|
+
while (index < lines.length) {
|
|
1572
|
+
const line = lines[index]!;
|
|
1573
|
+
if (line.indent < indent) break;
|
|
1574
|
+
if (line.indent > indent) {
|
|
1575
|
+
const nested = renderStudioLatexAlgorithmPdfLines(lines, index, line.indent);
|
|
1576
|
+
if (nested.latex.trim()) {
|
|
1577
|
+
parts.push(`\\begin{quote}\n${nested.latex}\n\\end{quote}`);
|
|
1578
|
+
}
|
|
1579
|
+
index = nested.nextIndex;
|
|
1580
|
+
continue;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
const prefix = line.lineNumber == null ? "" : `${line.lineNumber}. `;
|
|
1584
|
+
parts.push(`${prefix}${line.content}`.trim());
|
|
1585
|
+
index++;
|
|
1586
|
+
|
|
1587
|
+
while (index < lines.length && lines[index]!.indent > indent) {
|
|
1588
|
+
const nested = renderStudioLatexAlgorithmPdfLines(lines, index, lines[index]!.indent);
|
|
1589
|
+
if (nested.latex.trim()) {
|
|
1590
|
+
parts.push(`\\begin{quote}\n${nested.latex}\n\\end{quote}`);
|
|
1591
|
+
}
|
|
1592
|
+
index = nested.nextIndex;
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
return {
|
|
1597
|
+
latex: parts.filter(Boolean).join("\n\n"),
|
|
1598
|
+
nextIndex: index,
|
|
1599
|
+
};
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
function buildStudioLatexAlgorithmPdfBlock(
|
|
1603
|
+
block: StudioLatexAlgorithmPreviewBlock,
|
|
1604
|
+
labels: Map<string, { number: string; kind: string }>,
|
|
1605
|
+
): string {
|
|
1606
|
+
const body = renderStudioLatexAlgorithmPdfLines(block.lines, 0, 0).latex.trim();
|
|
1607
|
+
const captionLabel = formatStudioLatexMainAlgorithmCaptionLabel(block.label, labels);
|
|
1608
|
+
const heading = captionLabel
|
|
1609
|
+
? (block.caption ? `\\textbf{${captionLabel}} ${block.caption}` : `\\textbf{${captionLabel}}`)
|
|
1610
|
+
: (block.caption ? `\\textbf{${block.caption}}` : "");
|
|
1611
|
+
const parts = [heading, body].filter(Boolean);
|
|
1612
|
+
return `\n\n\\begin{quote}\n${parts.join("\n\n")}\n\\end{quote}\n\n`;
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
function preprocessStudioLatexAlgorithmsForPdf(markdown: string, sourcePath: string | undefined, baseDir: string | undefined): string {
|
|
1616
|
+
const previewTransform = preprocessStudioLatexAlgorithmsForPreview(markdown);
|
|
1617
|
+
if (previewTransform.algorithmBlocks.length === 0) return markdown;
|
|
1618
|
+
const labels = readStudioLatexAuxLabels(sourcePath, baseDir);
|
|
1619
|
+
let transformed = previewTransform.markdown;
|
|
1620
|
+
|
|
1621
|
+
for (const block of previewTransform.algorithmBlocks) {
|
|
1622
|
+
const startMarker = `PISTUDIOALGORITHMSTART${block.markerId}`;
|
|
1623
|
+
const endMarker = `PISTUDIOALGORITHMEND${block.markerId}`;
|
|
1624
|
+
const startIndex = transformed.indexOf(startMarker);
|
|
1625
|
+
if (startIndex < 0) continue;
|
|
1626
|
+
const endIndex = transformed.indexOf(endMarker, startIndex + startMarker.length);
|
|
1627
|
+
if (endIndex < 0) continue;
|
|
1628
|
+
const endSliceIndex = endIndex + endMarker.length;
|
|
1629
|
+
transformed = transformed.slice(0, startIndex) + buildStudioLatexAlgorithmPdfBlock(block, labels) + transformed.slice(endSliceIndex);
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
return transformed;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1563
1635
|
function appendStudioHtmlClassAttribute(attrs: string, className: string): string {
|
|
1564
1636
|
if (/\bclass="([^"]*)"/.test(attrs)) {
|
|
1565
1637
|
return attrs.replace(/\bclass="([^"]*)"/, (_match, existing) => {
|
|
@@ -2646,12 +2718,15 @@ async function renderStudioPdfWithPandoc(
|
|
|
2646
2718
|
): Promise<{ pdf: Buffer; warning?: string }> {
|
|
2647
2719
|
const pandocCommand = process.env.PANDOC_PATH?.trim() || "pandoc";
|
|
2648
2720
|
const pdfEngine = process.env.PANDOC_PDF_ENGINE?.trim() || "xelatex";
|
|
2721
|
+
const latexPdfSource = isLatex
|
|
2722
|
+
? preprocessStudioLatexAlgorithmsForPdf(markdown, sourcePath, resourcePath)
|
|
2723
|
+
: markdown;
|
|
2649
2724
|
const sourceWithResolvedRefs = isLatex
|
|
2650
|
-
? injectStudioLatexEquationTags(preprocessStudioLatexReferences(
|
|
2725
|
+
? injectStudioLatexEquationTags(preprocessStudioLatexReferences(latexPdfSource, sourcePath, resourcePath), sourcePath, resourcePath)
|
|
2651
2726
|
: markdown;
|
|
2652
2727
|
const effectiveEditorLanguage = inferStudioPdfLanguage(sourceWithResolvedRefs, editorPdfLanguage);
|
|
2653
2728
|
const pandocWorkingDir = resolveStudioPandocWorkingDir(resourcePath);
|
|
2654
|
-
const bibliographyArgs = buildStudioPandocBibliographyArgs(
|
|
2729
|
+
const bibliographyArgs = buildStudioPandocBibliographyArgs(markdown, isLatex, resourcePath);
|
|
2655
2730
|
|
|
2656
2731
|
const runPandocPdfExport = async (
|
|
2657
2732
|
inputFormat: string,
|