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/frontend/codemirror/extensions/insert-special-char.tsx
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import * as CodeMirror from "codemirror";
7
import { Button, Modal } from "antd";
8
9
import { alert_message } from "../../alerts";
10
import { show_react_modal } from "../../misc";
11
12
import emojis from "markdown-it-emoji/lib/data/full.json";
13
14
export interface Options {
15
char: string; // utf8 representation of the symbol
16
html?: string; // html code for the symbol (without "&...;" around it)
17
markdown?: string; // markdown for the symbol (without ":...:" around it)
18
}
19
20
export async function get_insert_special_char_from_user(): Promise<
21
undefined | Options
22
> {
23
return await show_react_modal((cb) => {
24
const style = {
25
width: "1.3em",
26
paddingLeft: ".3em",
27
display: "inline-block",
28
cursor: "pointer",
29
};
30
const symbols: JSX.Element[] = SYMBOLS.map((symbol, i) => (
31
<span
32
key={i}
33
style={style}
34
onClick={() => cb(undefined, symbol)}
35
>
36
{symbol.char}
37
</span>
38
));
39
return (
40
<Modal
41
title={<h3>&Omega; Insert Special Symbol or Emoji</h3>}
42
open
43
footer={<Button onClick={() => cb()}>Cancel</Button>}
44
onCancel={() => cb()}
45
centered
46
width={"70vw"}
47
>
48
<div
49
className="webapp-html-editor-symbols-dialog"
50
style={{ fontSize: "20pt" }}
51
>
52
{symbols}
53
</div>
54
</Modal>
55
);
56
});
57
}
58
59
function insert_special_char(mode: string, opts: Options): string {
60
if (mode == "html" && opts.html) {
61
return `&${opts.html};`;
62
}
63
if (mode == "md" && opts.markdown) {
64
return `:${opts.markdown}:`;
65
}
66
// This fallback should work wherever utf8 works,
67
// which is pretty general these days.
68
return opts.char;
69
}
70
71
CodeMirror.defineExtension(
72
"insert_special_char",
73
async function (): Promise<void> {
74
// @ts-ignore
75
const cm = this;
76
let opts: Options | undefined = undefined;
77
78
try {
79
opts = await get_insert_special_char_from_user();
80
} catch (err) {
81
alert_message({ type: "error", message: err.toString() });
82
return;
83
}
84
85
if (opts == null) {
86
return; // user canceled
87
}
88
89
const selections = cm.listSelections();
90
selections.reverse();
91
for (const sel of selections) {
92
const link = insert_special_char(cm.get_edit_mode(sel.head), opts);
93
if (sel.empty()) {
94
cm.replaceRange(link, sel.head);
95
} else {
96
cm.replaceRange(link, sel.from(), sel.to());
97
}
98
}
99
}
100
);
101
102
const SYMBOLS: Options[] = [
103
{ html: "Aacute", char: "Á" },
104
{ html: "aacute", char: "á" },
105
{ html: "Acirc", char: "Â" },
106
{ html: "acirc", char: "â" },
107
{ html: "acute", char: "´" },
108
{ html: "AElig", char: "Æ" },
109
{ html: "aelig", char: "æ" },
110
{ html: "Agrave", char: "À" },
111
{ html: "agrave", char: "à" },
112
{ html: "alefsym", char: "ℵ" },
113
{ html: "Alpha", char: "Α" },
114
{ html: "alpha", char: "α" },
115
{ html: "amp", char: "&" },
116
{ html: "and", char: "∧" },
117
{ html: "ang", char: "∠" },
118
{ html: "Aring", char: "Å" },
119
{ html: "aring", char: "å" },
120
{ html: "asymp", char: "≈" },
121
{ html: "Atilde", char: "Ã" },
122
{ html: "atilde", char: "ã" },
123
{ html: "Auml", char: "Ä" },
124
{ html: "auml", char: "ä" },
125
{ html: "bdquo", char: "„" },
126
{ html: "Beta", char: "Β" },
127
{ html: "beta", char: "β" },
128
{ html: "brvbar", char: "¦" },
129
{ html: "bull", char: "•" },
130
{ html: "cap", char: "∩" },
131
{ html: "Ccedil", char: "Ç" },
132
{ html: "ccedil", char: "ç" },
133
{ html: "cedil", char: "¸" },
134
{ html: "cent", char: "¢" },
135
{ html: "Chi", char: "Χ" },
136
{ html: "chi", char: "χ" },
137
{ html: "circ", char: "ˆ" },
138
{ html: "clubs", char: "♣" },
139
{ html: "cong", char: "≅" },
140
{ html: "copy", char: "©" },
141
{ html: "crarr", char: "↵" },
142
{ html: "cup", char: "∪" },
143
{ html: "curren", char: "¤" },
144
{ html: "dagger", char: "†" },
145
{ html: "Dagger", char: "‡" },
146
{ html: "darr", char: "↓" },
147
{ html: "dArr", char: "⇓" },
148
{ html: "deg", char: "°" },
149
{ html: "Delta", char: "Δ" },
150
{ html: "delta", char: "δ" },
151
{ html: "diams", char: "♦" },
152
{ html: "divide", char: "÷" },
153
{ html: "Eacute", char: "É" },
154
{ html: "eacute", char: "é" },
155
{ html: "Ecirc", char: "Ê" },
156
{ html: "ecirc", char: "ê" },
157
{ html: "Egrave", char: "È" },
158
{ html: "egrave", char: "è" },
159
{ html: "empty", char: "∅" },
160
{ html: "Epsilon", char: "Ε" },
161
{ html: "epsilon", char: "ε" },
162
{ html: "equiv", char: "≡" },
163
{ html: "Eta", char: "Η" },
164
{ html: "eta", char: "η" },
165
{ html: "ETH", char: "Ð" },
166
{ html: "eth", char: "ð" },
167
{ html: "Euml", char: "Ë" },
168
{ html: "euml", char: "ë" },
169
{ html: "euro", char: "€" },
170
{ html: "exist", char: "∃" },
171
{ html: "fnof", char: "ƒ" },
172
{ html: "forall", char: "∀" },
173
{ html: "frac12", char: "½" },
174
{ html: "frac14", char: "¼" },
175
{ html: "frac34", char: "¾" },
176
{ html: "frasl", char: "⁄" },
177
{ html: "Gamma", char: "Γ" },
178
{ html: "gamma", char: "γ" },
179
{ html: "ge", char: "≥" },
180
{ html: "gt", char: "<" },
181
{ html: "harr", char: "↔" },
182
{ html: "hArr", char: "⇔" },
183
{ html: "hearts", char: "♥" },
184
{ html: "hellip", char: "…" },
185
{ html: "Iacute", char: "Í" },
186
{ html: "iacute", char: "í" },
187
{ html: "Icirc", char: "Î" },
188
{ html: "icirc", char: "î" },
189
{ html: "iexcl", char: "¡" },
190
{ html: "Igrave", char: "Ì" },
191
{ html: "igrave", char: "ì" },
192
{ html: "image", char: "ℑ" },
193
{ html: "infin", char: "∞" },
194
{ html: "int", char: "∫" },
195
{ html: "Iota", char: "Ι" },
196
{ html: "iota", char: "ι" },
197
{ html: "iquest", char: "¿" },
198
{ html: "isin", char: "∈" },
199
{ html: "Iuml", char: "Ï" },
200
{ html: "iuml", char: "ï" },
201
{ html: "Kappa", char: "Κ" },
202
{ html: "kappa", char: "κ" },
203
{ html: "Lambda", char: "Λ" },
204
{ html: "lambda", char: "λ" },
205
{ html: "lang", char: "〈" },
206
{ html: "laquo", char: "«" },
207
{ html: "larr", char: "←" },
208
{ html: "lArr", char: "⇐" },
209
{ html: "lceil", char: "⌈" },
210
{ html: "ldquo", char: "“" },
211
{ html: "le", char: "≤" },
212
{ html: "lfloor", char: "⌊" },
213
{ html: "lowast", char: "∗" },
214
{ html: "loz", char: "◊" },
215
{ html: "lsaquo", char: "‹" },
216
{ html: "lsquo", char: "‘" },
217
{ html: "lt", char: "<" },
218
{ html: "macr", char: "¯" },
219
{ html: "mdash", char: "—" },
220
{ html: "micro", char: "µ" },
221
{ html: "middot", char: "·" },
222
{ html: "minus", char: "−" },
223
{ html: "Mu", char: "Μ" },
224
{ html: "mu", char: "μ" },
225
{ html: "nabla", char: "∇" },
226
{ html: "ndash", char: "–" },
227
{ html: "ne", char: "≠" },
228
{ html: "ni", char: "∋" },
229
{ html: "not", char: "¬" },
230
{ html: "notin", char: "∉" },
231
{ html: "nsub", char: "⊄" },
232
{ html: "Ntilde", char: "Ñ" },
233
{ html: "ntilde", char: "ñ" },
234
{ html: "Nu", char: "Ν" },
235
{ html: "nu", char: "ν" },
236
{ html: "Oacute", char: "Ó" },
237
{ html: "oacute", char: "ó" },
238
{ html: "Ocirc", char: "Ô" },
239
{ html: "ocirc", char: "ô" },
240
{ html: "OElig", char: "Œ" },
241
{ html: "oelig", char: "œ" },
242
{ html: "Ograve", char: "Ò" },
243
{ html: "ograve", char: "ò" },
244
{ html: "oline", char: "‾" },
245
{ html: "Omega", char: "Ω" },
246
{ html: "omega", char: "ω" },
247
{ html: "Omicron", char: "Ο" },
248
{ html: "omicron", char: "ο" },
249
{ html: "oplus", char: "⊕" },
250
{ html: "or", char: "∨" },
251
{ html: "ordf", char: "ª" },
252
{ html: "ordm", char: "º" },
253
{ html: "Oslash", char: "Ø" },
254
{ html: "oslash", char: "ø" },
255
{ html: "Otilde", char: "Õ" },
256
{ html: "otilde", char: "õ" },
257
{ html: "otimes", char: "⊗" },
258
{ html: "Ouml", char: "Ö" },
259
{ html: "ouml", char: "ö" },
260
{ html: "para", char: "¶" },
261
{ html: "part", char: "∂" },
262
{ html: "permil", char: "‰" },
263
{ html: "perp", char: "⊥" },
264
{ html: "Phi", char: "Φ" },
265
{ html: "phi", char: "φ" },
266
{ html: "Pi", char: "Π" },
267
{ html: "pi", char: "π" },
268
{ html: "piv", char: "ϖ" },
269
{ html: "plusmn", char: "±" },
270
{ html: "pound", char: "£" },
271
{ html: "prime", char: "′" },
272
{ html: "Prime", char: "″" },
273
{ html: "prod", char: "∏" },
274
{ html: "prop", char: "∝" },
275
{ html: "Psi", char: "Ψ" },
276
{ html: "psi", char: "ψ" },
277
{ html: "quot", char: '"' },
278
{ html: "radic", char: "√" },
279
{ html: "rang", char: "〉" },
280
{ html: "raquo", char: "»" },
281
{ html: "rarr", char: "→" },
282
{ html: "rArr", char: "⇒" },
283
{ html: "rceil", char: "⌉" },
284
{ html: "rdquo", char: "”" },
285
{ html: "real", char: "ℜ" },
286
{ html: "reg", char: "®" },
287
{ html: "rfloor", char: "⌋" },
288
{ html: "Rho", char: "Ρ" },
289
{ html: "rho", char: "ρ" },
290
{ html: "rsaquo", char: "›" },
291
{ html: "rsquo", char: "’" },
292
{ html: "sbquo", char: "‚" },
293
{ html: "Scaron", char: "Š" },
294
{ html: "scaron", char: "š" },
295
{ html: "sdot", char: "⋅" },
296
{ html: "sect", char: "§" },
297
{ html: "Sigma", char: "Σ" },
298
{ html: "sigma", char: "σ" },
299
{ html: "sigmaf", char: "ς" },
300
{ html: "sim", char: "∼" },
301
{ html: "spades", char: "♠" },
302
{ html: "sub", char: "⊂" },
303
{ html: "sube", char: "⊆" },
304
{ html: "sum", char: "∑" },
305
{ html: "sup", char: "⊃" },
306
{ html: "sup1", char: "¹" },
307
{ html: "sup2", char: "²" },
308
{ html: "sup3", char: "³" },
309
{ html: "supe", char: "⊇" },
310
{ html: "szlig", char: "ß" },
311
{ html: "Tau", char: "Τ" },
312
{ html: "tau", char: "τ" },
313
{ html: "there4", char: "∴" },
314
{ html: "Theta", char: "Θ" },
315
{ html: "theta", char: "θ" },
316
{ html: "thetasym", char: "ϑ" },
317
{ html: "THORN", char: "Þ" },
318
{ html: "thorn", char: "þ" },
319
{ html: "tilde", char: "˜" },
320
{ html: "times", char: "×" },
321
{ html: "trade", char: "™" },
322
{ html: "Uacute", char: "Ú" },
323
{ html: "uacute", char: "ú" },
324
{ html: "uarr", char: "↑" },
325
{ html: "uArr", char: "⇑" },
326
{ html: "Ucirc", char: "Û" },
327
{ html: "ucirc", char: "û" },
328
{ html: "Ugrave", char: "Ù" },
329
{ html: "ugrave", char: "ù" },
330
{ html: "uml", char: "¨" },
331
{ html: "upsih", char: "ϒ" },
332
{ html: "Upsilon", char: "Υ" },
333
{ html: "upsilon", char: "υ" },
334
{ html: "Uuml", char: "Ü" },
335
{ html: "uuml", char: "ü" },
336
{ html: "weierp", char: "℘" },
337
{ html: "Xi", char: "Ξ" },
338
{ html: "xi", char: "ξ" },
339
{ html: "Yacute", char: "Ý" },
340
{ html: "yacute", char: "ý" },
341
{ html: "yen", char: "¥" },
342
{ html: "yuml", char: "ÿ" },
343
{ html: "Yuml", char: "Ÿ" },
344
{ html: "Zeta", char: "Ζ" },
345
{ html: "zeta", char: "ζ" },
346
{ html: "zwj", char: "‍" },
347
{ html: "zwnj", char: "‌" },
348
] as Options[];
349
350
const seen = new Set<string>();
351
for (const markdown in emojis) {
352
const x = emojis[markdown];
353
if (seen.has(x)) continue;
354
seen.add(x);
355
SYMBOLS.push({ markdown, char: emojis[markdown] });
356
}
357
358