CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/util/latex-envs.ts
Views: 687
1
/*
2
Limited support for some latex environments, only for rendering (not editing).
3
*/
4
5
export default function latexEnvs(value: string): string {
6
value = transformFigures(value);
7
value = transformItemEnvironments(value);
8
return value;
9
}
10
11
/*
12
transformFigures -- dumb parser to turn this:
13
14
---
15
16
...
17
18
\begin{figure}
19
\centering
20
\centerline{\includegraphics[width=WIDTH]{URL}}
21
\caption{\label{foo}CAPTION}
22
\end{figure}
23
24
...
25
26
---
27
28
into this:
29
30
---
31
32
...
33
34
<div style="text-align:center"><img src="URL" style="width:WIDTH"/><br/><br/>\figlabel{foo}CAPTION</div>
35
36
37
...
38
39
---
40
41
There can be lots of figures.
42
*/
43
44
function transformFigures(content: string): string {
45
while (true) {
46
const i = content.indexOf("\\begin{figure}");
47
if (i == -1) {
48
return content;
49
}
50
const j = content.indexOf("\\end{figure}");
51
if (j == -1) {
52
return content;
53
}
54
const k = content.indexOf("\\includegraphics");
55
if (k == -1) {
56
return content;
57
}
58
const c = content.indexOf("\\caption{");
59
if (c == -1) {
60
return content;
61
}
62
const c2 = content.lastIndexOf("}", j);
63
if (c2 == -1) {
64
return content;
65
}
66
67
const w = content.indexOf("width=");
68
const w2 = content.indexOf("{", k);
69
const w3 = content.indexOf("}", k);
70
if (w2 == -1 || w3 == -1) {
71
return content;
72
}
73
let style = "";
74
if (w != -1) {
75
style = `width:${content.slice(w + "width=".length, w2 - 1)}`;
76
}
77
const url = content.slice(w2 + 1, w3);
78
let caption = content.slice(c + "\\caption{".length, c2);
79
const x = caption.indexOf("\\label{");
80
let figlabel;
81
if (x != -1) {
82
const y = caption.indexOf("}", x);
83
figlabel = `\\figlabel{${caption.slice(x + "\\label{".length, y)}}`;
84
caption = caption.slice(0, x) + caption.slice(y + 1);
85
} else {
86
figlabel = "";
87
}
88
89
const md = `\n\n<div style="text-align:center;margin:20px auto;max-width:750px"><img src="${url}" style="${style}"/><br/><br/><b>Figure${figlabel}:</b> ${caption}</div>\n\n`;
90
content =
91
content.slice(0, i) + md + content.slice(j + "\\end{figure}".length);
92
}
93
}
94
95
/*
96
transformEnumerate -- dumb parser to turn this:
97
98
---
99
100
...
101
102
\begin{enumerate}
103
\item ITEM1
104
\item ITEM2
105
...
106
\end{enumerate}
107
108
...
109
110
---
111
112
into this:
113
114
---
115
116
...
117
118
1. ITEM1
119
120
1. ITEM2
121
122
...
123
124
---
125
126
and
127
128
---
129
130
\begin{itemize}
131
\item ITEM1
132
\item ITEM2
133
...
134
\end{itemize}
135
136
into
137
138
- ITEM1
139
140
- ITEM2
141
142
*/
143
144
function transformItemEnvironments(content: string) {
145
for (const type of ["itemize", "enumerate"]) {
146
content = transformItemsType(content, type as "itemize" | "enumerate");
147
}
148
return content;
149
}
150
151
function transformItemsType(
152
content: string,
153
type: "itemize" | "enumerate",
154
): string {
155
while (true) {
156
const BEGIN = `\\begin{${type}}`;
157
const i = content.indexOf(BEGIN);
158
if (i == -1) {
159
return content;
160
}
161
const END = `\\end{${type}}`;
162
const j = content.indexOf(END);
163
if (j == -1) {
164
return content;
165
}
166
167
const body = content.slice(i + BEGIN.length + 1, j);
168
const items = body
169
.split("\\item")
170
.filter((x) => x.trim())
171
.map((x) => (type == "itemize" ? "- " : "1. ") + x)
172
.join("\n\n");
173
content =
174
content.slice(0, i) +
175
"\n\n" +
176
items +
177
"\n\n" +
178
content.slice(j + END.length + 1);
179
}
180
return content;
181
}
182
183