Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80635 views
1
/**
2
* Prism: Lightweight, robust, elegant syntax highlighting
3
* MIT license http://www.opensource.org/licenses/mit-license.php/
4
* @author Lea Verou http://lea.verou.me
5
*
6
* @providesModule Prism
7
* @jsx React.DOM
8
*/
9
10
var React = require('React');
11
var unindent = require('unindent');
12
13
// Private helper vars
14
var lang = /\blang(?:uage)?-(?!\*)(\w+)\b/i;
15
16
var _ = {
17
util: {
18
type: function (o) {
19
return Object.prototype.toString.call(o).match(/\[object (\w+)\]/)[1];
20
},
21
22
// Deep clone a language definition (e.g. to extend it)
23
clone: function (o) {
24
var type = _.util.type(o);
25
26
switch (type) {
27
case 'Object':
28
var clone = {};
29
30
for (var key in o) {
31
if (o.hasOwnProperty(key)) {
32
clone[key] = _.util.clone(o[key]);
33
}
34
}
35
36
return clone;
37
38
case 'Array':
39
return o.slice();
40
}
41
42
return o;
43
}
44
},
45
46
languages: {
47
extend: function (id, redef) {
48
var lang = _.util.clone(_.languages[id]);
49
50
for (var key in redef) {
51
lang[key] = redef[key];
52
}
53
54
return lang;
55
},
56
57
// Insert a token before another token in a language literal
58
insertBefore: function (inside, before, insert, root) {
59
root = root || _.languages;
60
var grammar = root[inside];
61
var ret = {};
62
63
for (var token in grammar) {
64
65
if (grammar.hasOwnProperty(token)) {
66
67
if (token == before) {
68
69
for (var newToken in insert) {
70
71
if (insert.hasOwnProperty(newToken)) {
72
ret[newToken] = insert[newToken];
73
}
74
}
75
}
76
77
ret[token] = grammar[token];
78
}
79
}
80
81
return root[inside] = ret;
82
},
83
84
// Traverse a language definition with Depth First Search
85
DFS: function(o, callback) {
86
for (var i in o) {
87
callback.call(o, i, o[i]);
88
89
if (_.util.type(o) === 'Object') {
90
_.languages.DFS(o[i], callback);
91
}
92
}
93
}
94
},
95
96
tokenize: function(text, grammar, language) {
97
var Token = _.Token;
98
99
var strarr = [text];
100
101
var rest = grammar.rest;
102
103
if (rest) {
104
for (var token in rest) {
105
grammar[token] = rest[token];
106
}
107
108
delete grammar.rest;
109
}
110
111
tokenloop: for (var token in grammar) {
112
if(!grammar.hasOwnProperty(token) || !grammar[token]) {
113
continue;
114
}
115
116
var pattern = grammar[token],
117
inside = pattern.inside,
118
lookbehind = !!pattern.lookbehind,
119
lookbehindLength = 0;
120
121
pattern = pattern.pattern || pattern;
122
123
for (var i=0; i<strarr.length; i++) { // Don’t cache length as it changes during the loop
124
125
var str = strarr[i];
126
127
if (strarr.length > text.length) {
128
// Something went terribly wrong, ABORT, ABORT!
129
break tokenloop;
130
}
131
132
if (str instanceof Token) {
133
continue;
134
}
135
136
pattern.lastIndex = 0;
137
138
var match = pattern.exec(str);
139
140
if (match) {
141
if(lookbehind) {
142
lookbehindLength = match[1].length;
143
}
144
145
var from = match.index - 1 + lookbehindLength,
146
match = match[0].slice(lookbehindLength),
147
len = match.length,
148
to = from + len,
149
before = str.slice(0, from + 1),
150
after = str.slice(to + 1);
151
152
var args = [i, 1];
153
154
if (before) {
155
args.push(before);
156
}
157
158
var wrapped = new Token(token, inside? _.tokenize(match, inside) : match);
159
160
args.push(wrapped);
161
162
if (after) {
163
args.push(after);
164
}
165
166
Array.prototype.splice.apply(strarr, args);
167
}
168
}
169
}
170
171
return strarr;
172
},
173
174
hooks: {
175
all: {},
176
177
add: function (name, callback) {
178
var hooks = _.hooks.all;
179
180
hooks[name] = hooks[name] || [];
181
182
hooks[name].push(callback);
183
},
184
185
run: function (name, env) {
186
var callbacks = _.hooks.all[name];
187
188
if (!callbacks || !callbacks.length) {
189
return;
190
}
191
192
for (var i=0, callback; callback = callbacks[i++];) {
193
callback(env);
194
}
195
}
196
}
197
};
198
199
var Token = _.Token = function(type, content) {
200
this.type = type;
201
this.content = content;
202
};
203
204
Token.reactify = function(o, key) {
205
if (typeof o == 'string') {
206
return o;
207
}
208
209
if (Array.isArray(o)) {
210
return o.map(function(element, i) {
211
return Token.reactify(element, i);
212
});
213
}
214
215
var attributes = {
216
className: 'token ' + o.type,
217
key: key
218
}
219
if (o.type == 'comment') {
220
attributes.spellCheck = true;
221
}
222
223
return React.DOM.span(attributes, Token.reactify(o.content));
224
};
225
226
_.languages.markup = {
227
'comment': /&lt;!--[\w\W]*?-->/g,
228
'prolog': /&lt;\?.+?\?>/,
229
'doctype': /&lt;!DOCTYPE.+?>/,
230
'cdata': /&lt;!\[CDATA\[[\w\W]*?]]>/i,
231
'tag': {
232
pattern: /&lt;\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+))?\s*)*\/?>/gi,
233
inside: {
234
'tag': {
235
pattern: /^&lt;\/?[\w:-]+/i,
236
inside: {
237
'punctuation': /^&lt;\/?/,
238
'namespace': /^[\w-]+?:/
239
}
240
},
241
'attr-value': {
242
pattern: /=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi,
243
inside: {
244
'punctuation': /=|>|"/g
245
}
246
},
247
'punctuation': /\/?>/g,
248
'attr-name': {
249
pattern: /[\w:-]+/g,
250
inside: {
251
'namespace': /^[\w-]+?:/
252
}
253
}
254
255
}
256
},
257
'entity': /&amp;#?[\da-z]{1,8};/gi
258
};
259
260
_.languages.css = {
261
'comment': /\/\*[\w\W]*?\*\//g,
262
'atrule': {
263
pattern: /@[\w-]+?.*?(;|(?=\s*{))/gi,
264
inside: {
265
'punctuation': /[;:]/g
266
}
267
},
268
'url': /url\((["']?).*?\1\)/gi,
269
'selector': /[^\{\}\s][^\{\};]*(?=\s*\{)/g,
270
'property': /(\b|\B)[\w-]+(?=\s*:)/ig,
271
'string': /("|')(\\?.)*?\1/g,
272
'important': /\B!important\b/gi,
273
'ignore': /&(lt|gt|amp);/gi,
274
'punctuation': /[\{\};:]/g
275
};
276
277
_.languages.insertBefore('markup', 'tag', {
278
'style': {
279
pattern: /(&lt;|<)style[\w\W]*?(>|&gt;)[\w\W]*?(&lt;|<)\/style(>|&gt;)/ig,
280
inside: {
281
'tag': {
282
pattern: /(&lt;|<)style[\w\W]*?(>|&gt;)|(&lt;|<)\/style(>|&gt;)/ig,
283
inside: _.languages.markup.tag.inside
284
},
285
rest: _.languages.css
286
}
287
}
288
});
289
290
_.languages.clike = {
291
'comment': {
292
pattern: /(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g,
293
lookbehind: true
294
},
295
'string': /("|')(\\?.)*?\1/g,
296
'class-name': {
297
pattern: /((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/ig,
298
lookbehind: true,
299
inside: {
300
punctuation: /(\.|\\)/
301
}
302
},
303
'keyword': /\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/g,
304
'boolean': /\b(true|false)\b/g,
305
'function': {
306
pattern: /[a-z0-9_]+\(/ig,
307
inside: {
308
punctuation: /\(/
309
}
310
},
311
'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,
312
'operator': /[-+]{1,2}|!|&lt;=?|>=?|={1,3}|(&amp;){1,2}|\|?\||\?|\*|\/|\~|\^|\%/g,
313
'ignore': /&(lt|gt|amp);/gi,
314
'punctuation': /[{}[\];(),.:]/g
315
};
316
317
_.languages.javascript = _.languages.extend('clike', {
318
'keyword': /\b(var|let|if|else|while|do|for|return|in|instanceof|function|get|set|new|with|typeof|try|throw|catch|finally|null|break|continue|this)\b/g,
319
'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g
320
});
321
322
_.languages.insertBefore('javascript', 'keyword', {
323
'regex': {
324
pattern: /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,
325
lookbehind: true
326
}
327
});
328
329
_.languages.insertBefore('markup', 'tag', {
330
'script': {
331
pattern: /(&lt;|<)script[\w\W]*?(>|&gt;)[\w\W]*?(&lt;|<)\/script(>|&gt;)/ig,
332
inside: {
333
'tag': {
334
pattern: /(&lt;|<)script[\w\W]*?(>|&gt;)|(&lt;|<)\/script(>|&gt;)/ig,
335
inside: _.languages.markup.tag.inside
336
},
337
rest: _.languages.javascript
338
}
339
}
340
});
341
342
var Prism = React.createClass({
343
statics: {
344
_: _
345
},
346
getDefaultProps: function() {
347
return {
348
language: 'javascript'
349
};
350
},
351
render: function() {
352
var grammar = _.languages[this.props.language];
353
return (
354
<div className={'prism language-' + this.props.language}>
355
{Token.reactify(_.tokenize(this.props.children, grammar))}
356
</div>
357
);
358
}
359
})
360
361
module.exports = Prism;
362
363