pi-studio 0.5.52 → 0.5.53

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.
@@ -0,0 +1,203 @@
1
+ const STUDIO_LITERAL_MARKDOWN_LATEX_COMMANDS = new Set([
2
+ "documentclass",
3
+ "usepackage",
4
+ "newtheorem",
5
+ "begin",
6
+ "end",
7
+ "section",
8
+ "subsection",
9
+ "subsubsection",
10
+ "chapter",
11
+ "part",
12
+ "paragraph",
13
+ "subparagraph",
14
+ "title",
15
+ "author",
16
+ "date",
17
+ "maketitle",
18
+ "tableofcontents",
19
+ "includegraphics",
20
+ "caption",
21
+ "label",
22
+ "ref",
23
+ "eqref",
24
+ "autoref",
25
+ "pageref",
26
+ "cite",
27
+ "citet",
28
+ "citep",
29
+ "citealt",
30
+ "citeauthor",
31
+ "nocite",
32
+ "textbf",
33
+ "textit",
34
+ "texttt",
35
+ "emph",
36
+ "underline",
37
+ "footnote",
38
+ "centering",
39
+ "newcommand",
40
+ "renewcommand",
41
+ "providecommand",
42
+ "bibliography",
43
+ "bibliographystyle",
44
+ "printbibliography",
45
+ "addbibresource",
46
+ "bibitem",
47
+ "item",
48
+ "input",
49
+ "include",
50
+ "latex",
51
+ "tex",
52
+ ]);
53
+
54
+ function isEscapedAt(text, index) {
55
+ let slashCount = 0;
56
+ for (let i = index - 1; i >= 0 && text[i] === "\\"; i -= 1) {
57
+ slashCount += 1;
58
+ }
59
+ return slashCount % 2 === 1;
60
+ }
61
+
62
+ function findClosingUnescapedDelimiter(text, startIndex, delimiter) {
63
+ let searchIndex = Math.max(0, startIndex);
64
+ while (searchIndex <= text.length) {
65
+ const matchIndex = text.indexOf(delimiter, searchIndex);
66
+ if (matchIndex < 0) return -1;
67
+ if (!isEscapedAt(text, matchIndex)) return matchIndex;
68
+ searchIndex = matchIndex + delimiter.length;
69
+ }
70
+ return -1;
71
+ }
72
+
73
+ function preserveLiteralLatexCommandsInMarkdownSegment(markdown) {
74
+ const source = String(markdown || "");
75
+ let out = "";
76
+ let index = 0;
77
+
78
+ while (index < source.length) {
79
+ if (source[index] === "`") {
80
+ let tickCount = 1;
81
+ while (source[index + tickCount] === "`") tickCount += 1;
82
+ const fence = "`".repeat(tickCount);
83
+ const closeIndex = source.indexOf(fence, index + tickCount);
84
+ if (closeIndex >= 0) {
85
+ out += source.slice(index, closeIndex + tickCount);
86
+ index = closeIndex + tickCount;
87
+ continue;
88
+ }
89
+ }
90
+
91
+ if (source.startsWith("$$", index) && !isEscapedAt(source, index)) {
92
+ const closeIndex = findClosingUnescapedDelimiter(source, index + 2, "$$");
93
+ if (closeIndex >= 0) {
94
+ out += source.slice(index, closeIndex + 2);
95
+ index = closeIndex + 2;
96
+ continue;
97
+ }
98
+ }
99
+
100
+ if (source[index] === "$" && !isEscapedAt(source, index)) {
101
+ const closeIndex = findClosingUnescapedDelimiter(source, index + 1, "$");
102
+ if (closeIndex >= 0) {
103
+ out += source.slice(index, closeIndex + 1);
104
+ index = closeIndex + 1;
105
+ continue;
106
+ }
107
+ }
108
+
109
+ if (source.startsWith("\\(", index)) {
110
+ const closeIndex = source.indexOf("\\)", index + 2);
111
+ if (closeIndex >= 0) {
112
+ out += source.slice(index, closeIndex + 2);
113
+ index = closeIndex + 2;
114
+ continue;
115
+ }
116
+ }
117
+
118
+ if (source.startsWith("\\[", index)) {
119
+ const closeIndex = source.indexOf("\\]", index + 2);
120
+ if (closeIndex >= 0) {
121
+ out += source.slice(index, closeIndex + 2);
122
+ index = closeIndex + 2;
123
+ continue;
124
+ }
125
+ }
126
+
127
+ if (source[index] === "\\" && source[index + 1] === "\\") {
128
+ out += "\\\\";
129
+ index += 2;
130
+ continue;
131
+ }
132
+
133
+ if (source[index] === "\\" && /[A-Za-z@]/.test(source[index + 1] || "")) {
134
+ let endIndex = index + 1;
135
+ while (/[A-Za-z@]/.test(source[endIndex] || "")) endIndex += 1;
136
+ if (source[endIndex] === "*") endIndex += 1;
137
+ const commandName = source.slice(index + 1, endIndex).replace(/\*$/, "").toLowerCase();
138
+ if (STUDIO_LITERAL_MARKDOWN_LATEX_COMMANDS.has(commandName)) {
139
+ out += "\\" + source.slice(index, endIndex);
140
+ index = endIndex;
141
+ continue;
142
+ }
143
+ }
144
+
145
+ out += source[index];
146
+ index += 1;
147
+ }
148
+
149
+ return out;
150
+ }
151
+
152
+ export function preserveLiteralLatexCommandsInMarkdown(markdown) {
153
+ const lines = String(markdown || "").split("\n");
154
+ const out = [];
155
+ let plainBuffer = [];
156
+ let inFence = false;
157
+ let fenceChar;
158
+ let fenceLength = 0;
159
+
160
+ const flushPlain = () => {
161
+ if (plainBuffer.length === 0) return;
162
+ out.push(preserveLiteralLatexCommandsInMarkdownSegment(plainBuffer.join("\n")));
163
+ plainBuffer = [];
164
+ };
165
+
166
+ for (const line of lines) {
167
+ const trimmed = line.trimStart();
168
+ const fenceMatch = trimmed.match(/^(`{3,}|~{3,})/);
169
+
170
+ if (fenceMatch) {
171
+ const marker = fenceMatch[1];
172
+ const markerChar = marker[0];
173
+ const markerLength = marker.length;
174
+
175
+ if (!inFence) {
176
+ flushPlain();
177
+ inFence = true;
178
+ fenceChar = markerChar;
179
+ fenceLength = markerLength;
180
+ out.push(line);
181
+ continue;
182
+ }
183
+
184
+ if (fenceChar === markerChar && markerLength >= fenceLength) {
185
+ inFence = false;
186
+ fenceChar = undefined;
187
+ fenceLength = 0;
188
+ }
189
+
190
+ out.push(line);
191
+ continue;
192
+ }
193
+
194
+ if (inFence) {
195
+ out.push(line);
196
+ } else {
197
+ plainBuffer.push(line);
198
+ }
199
+ }
200
+
201
+ flushPlain();
202
+ return out.join("\n");
203
+ }