aboutsummaryrefslogtreecommitdiff
path: root/imports/codemirror/mode/javascript
diff options
context:
space:
mode:
Diffstat (limited to 'imports/codemirror/mode/javascript')
-rwxr-xr-ximports/codemirror/mode/javascript/index.html77
-rwxr-xr-ximports/codemirror/mode/javascript/javascript.js360
2 files changed, 437 insertions, 0 deletions
diff --git a/imports/codemirror/mode/javascript/index.html b/imports/codemirror/mode/javascript/index.html
new file mode 100755
index 00000000..c3ab91dc
--- /dev/null
+++ b/imports/codemirror/mode/javascript/index.html
@@ -0,0 +1,77 @@
1<!doctype html>
2<html>
3 <head>
4 <title>CodeMirror: JavaScript mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="javascript.js"></script>
8 <link rel="stylesheet" href="../../doc/docs.css">
9 <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
10 </head>
11 <body>
12 <h1>CodeMirror: JavaScript mode</h1>
13
14<div><textarea id="code" name="code">
15// Demo code (the actual new parser character stream implementation)
16
17function StringStream(string) {
18 this.pos = 0;
19 this.string = string;
20}
21
22StringStream.prototype = {
23 done: function() {return this.pos >= this.string.length;},
24 peek: function() {return this.string.charAt(this.pos);},
25 next: function() {
26 if (this.pos &lt; this.string.length)
27 return this.string.charAt(this.pos++);
28 },
29 eat: function(match) {
30 var ch = this.string.charAt(this.pos);
31 if (typeof match == "string") var ok = ch == match;
32 else var ok = ch &amp;&amp; match.test ? match.test(ch) : match(ch);
33 if (ok) {this.pos++; return ch;}
34 },
35 eatWhile: function(match) {
36 var start = this.pos;
37 while (this.eat(match));
38 if (this.pos > start) return this.string.slice(start, this.pos);
39 },
40 backUp: function(n) {this.pos -= n;},
41 column: function() {return this.pos;},
42 eatSpace: function() {
43 var start = this.pos;
44 while (/\s/.test(this.string.charAt(this.pos))) this.pos++;
45 return this.pos - start;
46 },
47 match: function(pattern, consume, caseInsensitive) {
48 if (typeof pattern == "string") {
49 function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
50 if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
51 if (consume !== false) this.pos += str.length;
52 return true;
53 }
54 }
55 else {
56 var match = this.string.slice(this.pos).match(pattern);
57 if (match &amp;&amp; consume !== false) this.pos += match[0].length;
58 return match;
59 }
60 }
61};
62</textarea></div>
63
64 <script>
65 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
66 lineNumbers: true,
67 matchBrackets: true
68 });
69 </script>
70
71 <p>JavaScript mode supports a single configuration
72 option, <code>json</code>, which will set the mode to expect JSON
73 data rather than a JavaScript program.</p>
74
75 <p><strong>MIME types defined:</strong> <code>text/javascript</code>, <code>application/json</code>.</p>
76 </body>
77</html>
diff --git a/imports/codemirror/mode/javascript/javascript.js b/imports/codemirror/mode/javascript/javascript.js
new file mode 100755
index 00000000..be2a0698
--- /dev/null
+++ b/imports/codemirror/mode/javascript/javascript.js
@@ -0,0 +1,360 @@
1CodeMirror.defineMode("javascript", function(config, parserConfig) {
2 var indentUnit = config.indentUnit;
3 var jsonMode = parserConfig.json;
4
5 // Tokenizer
6
7 var keywords = function(){
8 function kw(type) {return {type: type, style: "keyword"};}
9 var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
10 var operator = kw("operator"), atom = {type: "atom", style: "atom"};
11 return {
12 "if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
13 "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
14 "var": kw("var"), "const": kw("var"), "let": kw("var"),
15 "function": kw("function"), "catch": kw("catch"),
16 "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
17 "in": operator, "typeof": operator, "instanceof": operator,
18 "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom
19 };
20 }();
21
22 var isOperatorChar = /[+\-*&%=<>!?|]/;
23
24 function chain(stream, state, f) {
25 state.tokenize = f;
26 return f(stream, state);
27 }
28
29 function nextUntilUnescaped(stream, end) {
30 var escaped = false, next;
31 while ((next = stream.next()) != null) {
32 if (next == end && !escaped)
33 return false;
34 escaped = !escaped && next == "\\";
35 }
36 return escaped;
37 }
38
39 // Used as scratch variables to communicate multiple values without
40 // consing up tons of objects.
41 var type, content;
42 function ret(tp, style, cont) {
43 type = tp; content = cont;
44 return style;
45 }
46
47 function jsTokenBase(stream, state) {
48 var ch = stream.next();
49 if (ch == '"' || ch == "'")
50 return chain(stream, state, jsTokenString(ch));
51 else if (/[\[\]{}\(\),;\:\.]/.test(ch))
52 return ret(ch);
53 else if (ch == "0" && stream.eat(/x/i)) {
54 stream.eatWhile(/[\da-f]/i);
55 return ret("number", "number");
56 }
57 else if (/\d/.test(ch)) {
58 stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
59 return ret("number", "number");
60 }
61 else if (ch == "/") {
62 if (stream.eat("*")) {
63 return chain(stream, state, jsTokenComment);
64 }
65 else if (stream.eat("/")) {
66 stream.skipToEnd();
67 return ret("comment", "comment");
68 }
69 else if (state.reAllowed) {
70 nextUntilUnescaped(stream, "/");
71 stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
72 return ret("regexp", "string");
73 }
74 else {
75 stream.eatWhile(isOperatorChar);
76 return ret("operator", null, stream.current());
77 }
78 }
79 else if (ch == "#") {
80 stream.skipToEnd();
81 return ret("error", "error");
82 }
83 else if (isOperatorChar.test(ch)) {
84 stream.eatWhile(isOperatorChar);
85 return ret("operator", null, stream.current());
86 }
87 else {
88 stream.eatWhile(/[\w\$_]/);
89 var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
90 return (known && state.kwAllowed) ? ret(known.type, known.style, word) :
91 ret("variable", "variable", word);
92 }
93 }
94
95 function jsTokenString(quote) {
96 return function(stream, state) {
97 if (!nextUntilUnescaped(stream, quote))
98 state.tokenize = jsTokenBase;
99 return ret("string", "string");
100 };
101 }
102
103 function jsTokenComment(stream, state) {
104 var maybeEnd = false, ch;
105 while (ch = stream.next()) {
106 if (ch == "/" && maybeEnd) {
107 state.tokenize = jsTokenBase;
108 break;
109 }
110 maybeEnd = (ch == "*");
111 }
112 return ret("comment", "comment");
113 }
114
115 // Parser
116
117 var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
118
119 function JSLexical(indented, column, type, align, prev, info) {
120 this.indented = indented;
121 this.column = column;
122 this.type = type;
123 this.prev = prev;
124 this.info = info;
125 if (align != null) this.align = align;
126 }
127
128 function inScope(state, varname) {
129 for (var v = state.localVars; v; v = v.next)
130 if (v.name == varname) return true;
131 }
132
133 function parseJS(state, style, type, content, stream) {
134 var cc = state.cc;
135 // Communicate our context to the combinators.
136 // (Less wasteful than consing up a hundred closures on every call.)
137 cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
138
139 if (!state.lexical.hasOwnProperty("align"))
140 state.lexical.align = true;
141
142 while(true) {
143 var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
144 if (combinator(type, content)) {
145 while(cc.length && cc[cc.length - 1].lex)
146 cc.pop()();