pi-studio 0.5.24 → 0.5.25
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 +17 -5
- 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.25] — 2026-03-21
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- Studio PDF exports now add more space below ruled section headings to keep bibliography entries clear of the `References` underline, and figure captions now use left-aligned ragged-right formatting for long multi-line captions, including reinjected PDF subfigure groups, without disturbing normal figure centering.
|
|
11
|
+
|
|
7
12
|
## [0.5.24] — 2026-03-20
|
|
8
13
|
|
|
9
14
|
### Fixed
|
package/index.ts
CHANGED
|
@@ -175,11 +175,13 @@ const CMUX_STUDIO_STATUS_COLOR_DARK = "#5ea1ff";
|
|
|
175
175
|
const CMUX_STUDIO_STATUS_COLOR_LIGHT = "#0047ab";
|
|
176
176
|
|
|
177
177
|
const PDF_PREAMBLE = `\\usepackage{titlesec}
|
|
178
|
-
\\titleformat{\\section}{\\Large\\bfseries\\sffamily}{}{0pt}{}[\\vspace{
|
|
178
|
+
\\titleformat{\\section}{\\Large\\bfseries\\sffamily}{}{0pt}{}[\\vspace{3pt}\\titlerule\\vspace{12pt}]
|
|
179
179
|
\\titleformat{\\subsection}{\\large\\bfseries\\sffamily}{}{0pt}{}
|
|
180
180
|
\\titleformat{\\subsubsection}{\\normalsize\\bfseries\\sffamily}{}{0pt}{}
|
|
181
181
|
\\titlespacing*{\\section}{0pt}{1.5ex plus 0.5ex minus 0.2ex}{1ex plus 0.2ex}
|
|
182
182
|
\\titlespacing*{\\subsection}{0pt}{1.2ex plus 0.4ex minus 0.2ex}{0.6ex plus 0.1ex}
|
|
183
|
+
\\usepackage{caption}
|
|
184
|
+
\\captionsetup[figure]{justification=raggedright,singlelinecheck=false}
|
|
183
185
|
\\usepackage{enumitem}
|
|
184
186
|
\\setlist[itemize]{nosep, leftmargin=1.5em}
|
|
185
187
|
\\setlist[enumerate]{nosep, leftmargin=1.5em}
|
|
@@ -1827,7 +1829,7 @@ function buildStudioLatexInjectedPdfSubfigureBlock(
|
|
|
1827
1829
|
? (group.caption ? `\\textbf{${figureLabel}} ${group.caption}` : `\\textbf{${figureLabel}}`)
|
|
1828
1830
|
: (group.caption ? group.caption : "");
|
|
1829
1831
|
|
|
1830
|
-
|
|
1832
|
+
const minipageBlocks = group.items.map((item) => {
|
|
1831
1833
|
const widthSpec = item.widthSpec || "0.48\\textwidth";
|
|
1832
1834
|
const imageCommand = `\\includegraphics${item.imageOptions ? `[${item.imageOptions}]` : "[width=\\linewidth]"}{${item.imagePath}}`;
|
|
1833
1835
|
const subfigureLabel = formatStudioLatexSubfigureCaptionLabel(item.label, labels);
|
|
@@ -1838,7 +1840,7 @@ function buildStudioLatexInjectedPdfSubfigureBlock(
|
|
|
1838
1840
|
`\\begin{minipage}[t]{${widthSpec}}`,
|
|
1839
1841
|
"\\centering",
|
|
1840
1842
|
imageCommand,
|
|
1841
|
-
captionLine ? `\\par\\smallskip ${captionLine}` : "",
|
|
1843
|
+
captionLine ? `\\par\\smallskip{\\raggedright ${captionLine}\\par}` : "",
|
|
1842
1844
|
"\\end{minipage}",
|
|
1843
1845
|
].filter(Boolean);
|
|
1844
1846
|
return {
|
|
@@ -1866,7 +1868,7 @@ function buildStudioLatexInjectedPdfSubfigureBlock(
|
|
|
1866
1868
|
"\\begin{figure}[p]",
|
|
1867
1869
|
"\\centering",
|
|
1868
1870
|
rows.join("\n\\par\\medskip\n"),
|
|
1869
|
-
figureCaption ? `\\par\\bigskip ${figureCaption}` : "",
|
|
1871
|
+
figureCaption ? `\\par\\bigskip{\\raggedright ${figureCaption}\\par}` : "",
|
|
1870
1872
|
"\\end{figure}",
|
|
1871
1873
|
"\\clearpage",
|
|
1872
1874
|
].filter(Boolean);
|
|
@@ -1909,6 +1911,15 @@ function injectStudioLatexPdfSubfigureBlocks(
|
|
|
1909
1911
|
return transformed;
|
|
1910
1912
|
}
|
|
1911
1913
|
|
|
1914
|
+
function normalizeStudioGeneratedFigureCaptions(latex: string): string {
|
|
1915
|
+
return String(latex ?? "").replace(/\\begin\{figure\*?\}(?:\[[^\]]*\])?[\s\S]*?\\end\{figure\*?\}/g, (figureEnv) => {
|
|
1916
|
+
return String(figureEnv).replace(/\\caption(\[[^\]]*\])?\{/g, (_match, optionalArg) => {
|
|
1917
|
+
const suffix = typeof optionalArg === "string" ? optionalArg : "";
|
|
1918
|
+
return `\\captionsetup{justification=raggedright,singlelinecheck=false}\\caption${suffix}{\\raggedright `;
|
|
1919
|
+
});
|
|
1920
|
+
});
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1912
1923
|
function formatStudioLatexMainAlgorithmCaptionLabel(label: string | null, labels: Map<string, { number: string; kind: string }>): string | null {
|
|
1913
1924
|
const normalizedLabel = String(label ?? "").trim();
|
|
1914
1925
|
if (!normalizedLabel) return null;
|
|
@@ -3004,7 +3015,8 @@ async function renderStudioPdfFromGeneratedLatex(
|
|
|
3004
3015
|
|
|
3005
3016
|
const generatedLatex = await readFile(latexPath, "utf-8");
|
|
3006
3017
|
const injectedLatex = injectStudioLatexPdfSubfigureBlocks(generatedLatex, subfigureGroups, sourcePath, resourcePath);
|
|
3007
|
-
|
|
3018
|
+
const normalizedLatex = normalizeStudioGeneratedFigureCaptions(injectedLatex);
|
|
3019
|
+
await writeFile(latexPath, normalizedLatex, "utf-8");
|
|
3008
3020
|
|
|
3009
3021
|
await new Promise<void>((resolve, reject) => {
|
|
3010
3022
|
const child = spawn(pdfEngine, [
|