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/custom-modes.ts
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
// Multiplex'd worksheet mode
7
8
import { MARKERS } from "@cocalc/util/sagews";
9
import { clone, object } from "underscore";
10
import CodeMirror from "./codemirror";
11
import "codemirror/addon/mode/multiplex";
12
import "./multiplex";
13
14
export const sagews_decorator_modes: [string, string][] = [
15
["cjsx", "text/cjsx"],
16
["coffeescript", "coffeescript"],
17
["cython", "cython"],
18
["file", "text"],
19
["fortran", "text/x-fortran"],
20
["html", "htmlmixed"],
21
["javascript", "javascript"],
22
["java", "text/x-java"], // !! more specific name must be first!!!! (java vs javascript!)
23
["latex", "stex"],
24
["lisp", "ecl"],
25
["md", "gfm2"],
26
["gp", "text/pari"],
27
["go", "text/x-go"],
28
["perl", "text/x-perl"],
29
["python3", "python"],
30
["python", "python"],
31
["ruby", "text/x-ruby"], // !! more specific name must be first or get mismatch!
32
["r", "r"],
33
["sage", "python"],
34
["script", "shell"],
35
["sh", "shell"],
36
["julia", "text/x-julia"],
37
["wiki", "mediawiki"],
38
["mediawiki", "mediawiki"],
39
];
40
41
// Many of the modes below are multiplexed
42
43
interface MultiplexOption {
44
open: string | RegExp;
45
close: string | RegExp;
46
mode: unknown;
47
start?: boolean;
48
delimStyle?: string;
49
}
50
51
// not using these two gfm2 and htmlmixed2 modes, with their sub-latex mode, since
52
// detection of math isn't good enough. e.g., \$ causes math mode and $ doesn't seem to... \$500 and $\sin(x)$.
53
54
CodeMirror.defineMode("gfm2", function (config) {
55
const options: MultiplexOption[] = [];
56
for (let x of [
57
["$$", "$$"],
58
["$", "$"],
59
["\\[", "\\]"],
60
["\\(", "\\)"],
61
]) {
62
options.push({
63
open: x[0],
64
close: x[1],
65
mode: CodeMirror.getMode(config, "stex"),
66
});
67
}
68
return (CodeMirror as any).multiplexingMode(
69
CodeMirror.getMode(config, "gfm"),
70
...options
71
);
72
});
73
74
CodeMirror.defineMode("htmlmixed2", function (config) {
75
const options: MultiplexOption[] = [];
76
for (let x of [
77
["$$", "$$"],
78
["$", "$"],
79
["\\[", "\\]"],
80
["\\(", "\\)"],
81
]) {
82
options.push({
83
open: x[0],
84
close: x[1],
85
mode: CodeMirror.getMode(config, "stex"),
86
});
87
}
88
return (CodeMirror as any).multiplexingMode(
89
CodeMirror.getMode(config, "htmlmixed"),
90
...options
91
);
92
});
93
94
CodeMirror.defineMode("stex2", function (config) {
95
const options: MultiplexOption[] = [];
96
for (let x of ["sagesilent", "sageblock"]) {
97
options.push({
98
open: `\\begin{${x}}`,
99
close: `\\end{${x}}`,
100
mode: CodeMirror.getMode(config, "sagews"),
101
});
102
}
103
options.push({
104
open: "\\sage{",
105
close: "}",
106
mode: CodeMirror.getMode(config, "sagews"),
107
});
108
return (CodeMirror as any).multiplexingMode(
109
CodeMirror.getMode(config, "stex"),
110
...options
111
);
112
});
113
114
CodeMirror.defineMode("rnw", function (config) {
115
const block = {
116
open: /^<<.+?>>=/,
117
close: /^@/,
118
mode: CodeMirror.getMode(config, "r"),
119
};
120
const inline = {
121
open: "\\Sexpr{",
122
close: "}",
123
mode: CodeMirror.getMode(config, "r"),
124
};
125
return (CodeMirror as any).multiplexingMode(
126
CodeMirror.getMode(config, "stex2"),
127
block,
128
inline
129
);
130
});
131
132
CodeMirror.defineMode("rtex", function (config) {
133
const block = {
134
open: /^%%\s+begin\.rcode/,
135
close: /^%%\s+end\.rcode/,
136
indent: "% ",
137
mode: CodeMirror.getMode(config, "r"),
138
};
139
const inline = {
140
open: "\\rinline{",
141
close: "}",
142
mode: CodeMirror.getMode(config, "r"),
143
};
144
return (CodeMirror as any).multiplexingMode(
145
CodeMirror.getMode(config, "stex2"),
146
block,
147
inline
148
);
149
});
150
151
CodeMirror.defineMode("cython", (config) => {
152
// FUTURE: need to figure out how to do this so that the name
153
// of the mode is cython
154
return (CodeMirror as any).multiplexingMode(
155
CodeMirror.getMode(config, "python")
156
);
157
});
158
159
CodeMirror.defineMode("mojo", (config) => {
160
// FUTURE: need to figure out how to do this so that the name
161
// of the mode is mojo or modular
162
return (CodeMirror as any).multiplexingMode(
163
CodeMirror.getMode(config, "python")
164
);
165
});
166
167
CodeMirror.defineMode("sagews", function (config) {
168
const options: MultiplexOption[] = [];
169
const close = new RegExp(`[${MARKERS.output}${MARKERS.cell}]`);
170
for (const x of sagews_decorator_modes) {
171
// NOTE: very important to close on both MARKERS.output *and* MARKERS.cell,
172
// rather than just MARKERS.cell, or it will try to
173
// highlight the *hidden* output message line, which can
174
// be *enormous*, and could take a very very long time, but is
175
// a complete waste, since we never see that markup.
176
options.push({
177
open: "%" + x[0],
178
start: true, // must be at beginning of line
179
close,
180
mode: CodeMirror.getMode(config, x[1]),
181
});
182
}
183
184
return (CodeMirror as any).cocalcMultiplexingMode(
185
CodeMirror.getMode(config, "python"),
186
...options
187
);
188
});
189
190
CodeMirror.defineMode("rmd", function (config) {
191
// derived from the sagews modes with some additions
192
let mode, open;
193
const modes = clone(object(sagews_decorator_modes));
194
modes["fortran95"] = modes["fortran"];
195
modes["octave"] = "octave";
196
modes["bash"] = modes["sh"];
197
198
const options: MultiplexOption[] = [];
199
200
// blocks (ATTN ruby before r!)
201
// all engine modes: names(knitr::knit_engines$get())
202
for (let name of [
203
"ruby",
204
"r",
205
"python",
206
"octave",
207
"fortran95",
208
"fortran",
209
"octave",
210
"bash",
211
"go",
212
"julia",
213
"perl",
214
]) {
215
mode = modes[name];
216
open = new RegExp(`\`\`\`\\s*{${name}[^}]*?}`);
217
options.push({
218
open,
219
close: "```",
220
delimStyle: "gfm",
221
mode: CodeMirror.getMode(config, mode),
222
});
223
}
224
225
// ATTN: this case must come later, it is less specific
226
// inline, just `r ...` exists, not for other languages.
227
options.push({
228
open: "`r",
229
close: "`",
230
mode: CodeMirror.getMode(config, "r"),
231
});
232
233
return (CodeMirror as any).multiplexingMode(
234
CodeMirror.getMode(config, "yaml-frontmatter"),
235
...options
236
);
237
});
238
239