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/multiplex.js
Views: 687
1
// CodeMirror, copyright (c) by Marijn Haverbeke and others
2
// Distributed under an MIT license: https://codemirror.net/LICENSE
3
4
/*
5
Multiplexing mode -- exactly like the original CodeMirror multiplexingMode,
6
https://codemirror.net/demo/multiplex.html,
7
except use the option start:true to make it so the mode switch pattern
8
must be at the beginning of the line.
9
10
Original copyright on https://codemirror.net/addon/mode/multiplex.js:
11
CodeMirror, copyright (c) by Marijn Haverbeke and others
12
Distributed under an MIT license: http://codemirror.net/LICENSE
13
*/
14
15
import CodeMirror from "./codemirror";
16
17
CodeMirror.cocalcMultiplexingMode = function (outer /*, others */) {
18
// Others should be {open, close, mode [, delimStyle] [, innerStyle]} objects
19
var others = Array.prototype.slice.call(arguments, 1);
20
21
function indexOf(string, pattern, from, returnEnd) {
22
if (typeof pattern == "string") {
23
var found = string.indexOf(pattern, from);
24
return returnEnd && found > -1 ? found + pattern.length : found;
25
}
26
var m = pattern.exec(from ? string.slice(from) : string);
27
return m ? m.index + from + (returnEnd ? m[0].length : 0) : -1;
28
}
29
30
return {
31
startState: function () {
32
return {
33
outer: CodeMirror.startState(outer),
34
innerActive: null,
35
inner: null,
36
};
37
},
38
39
copyState: function (state) {
40
return {
41
outer: CodeMirror.copyState(outer, state.outer),
42
innerActive: state.innerActive,
43
inner:
44
state.innerActive &&
45
CodeMirror.copyState(state.innerActive.mode, state.inner),
46
};
47
},
48
49
token: function (stream, state) {
50
if (!state.innerActive) {
51
var cutOff = Infinity,
52
oldContent = stream.string;
53
for (var i = 0; i < others.length; ++i) {
54
var other = others[i];
55
if (
56
// This is our modification of usptream.
57
other.start &&
58
oldContent.slice(0, other.open.length) != other.open
59
) {
60
continue;
61
}
62
var found = indexOf(oldContent, other.open, stream.pos);
63
if (found == stream.pos) {
64
if (!other.parseDelimiters) stream.match(other.open);
65
state.innerActive = other;
66
67
// Get the outer indent, making sure to handle CodeMirror.Pass
68
var outerIndent = 0;
69
if (outer.indent) {
70
var possibleOuterIndent = outer.indent(state.outer, "", "");
71
if (possibleOuterIndent !== CodeMirror.Pass)
72
outerIndent = possibleOuterIndent;
73
}
74
75
state.inner = CodeMirror.startState(other.mode, outerIndent);
76
return (
77
other.delimStyle &&
78
other.delimStyle + " " + other.delimStyle + "-open"
79
);
80
} else if (found != -1 && found < cutOff) {
81
cutOff = found;
82
}
83
}
84
if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff);
85
var outerToken = outer.token(stream, state.outer);
86
if (cutOff != Infinity) stream.string = oldContent;
87
return outerToken;
88
} else {
89
var curInner = state.innerActive,
90
oldContent = stream.string;
91
if (!curInner.close && stream.sol()) {
92
state.innerActive = state.inner = null;
93
return this.token(stream, state);
94
}
95
var found = curInner.close
96
? indexOf(
97
oldContent,
98
curInner.close,
99
stream.pos,
100
curInner.parseDelimiters
101
)
102
: -1;
103
if (found == stream.pos && !curInner.parseDelimiters) {
104
stream.match(curInner.close);
105
state.innerActive = state.inner = null;
106
return (
107
curInner.delimStyle &&
108
curInner.delimStyle + " " + curInner.delimStyle + "-close"
109
);
110
}
111
if (found > -1) stream.string = oldContent.slice(0, found);
112
var innerToken = curInner.mode.token(stream, state.inner);
113
if (found > -1) stream.string = oldContent;
114
115
if (found == stream.pos && curInner.parseDelimiters)
116
state.innerActive = state.inner = null;
117
118
if (curInner.innerStyle) {
119
if (innerToken) innerToken = innerToken + " " + curInner.innerStyle;
120
else innerToken = curInner.innerStyle;
121
}
122
123
return innerToken;
124
}
125
},
126
127
indent: function (state, textAfter, line) {
128
var mode = state.innerActive ? state.innerActive.mode : outer;
129
if (!mode.indent) return CodeMirror.Pass;
130
return mode.indent(
131
state.innerActive ? state.inner : state.outer,
132
textAfter,
133
line
134
);
135
},
136
137
blankLine: function (state) {
138
var mode = state.innerActive ? state.innerActive.mode : outer;
139
if (mode.blankLine) {
140
mode.blankLine(state.innerActive ? state.inner : state.outer);
141
}
142
if (!state.innerActive) {
143
for (var i = 0; i < others.length; ++i) {
144
var other = others[i];
145
if (other.open === "\n") {
146
state.innerActive = other;
147
state.inner = CodeMirror.startState(
148
other.mode,
149
mode.indent ? mode.indent(state.outer, "", "") : 0
150
);
151
}
152
}
153
} else if (state.innerActive.close === "\n") {
154
state.innerActive = state.inner = null;
155
}
156
},
157
158
electricChars: outer.electricChars,
159
160
innerMode: function (state) {
161
return state.inner
162
? { state: state.inner, mode: state.innerActive.mode }
163
: { state: state.outer, mode: outer };
164
},
165
};
166
};
167
168