aboutsummaryrefslogtreecommitdiff
path: root/imports/codemirror/mode/ruby/ruby.js
diff options
context:
space:
mode:
Diffstat (limited to 'imports/codemirror/mode/ruby/ruby.js')
-rwxr-xr-ximports/codemirror/mode/ruby/ruby.js195
1 files changed, 195 insertions, 0 deletions
diff --git a/imports/codemirror/mode/ruby/ruby.js b/imports/codemirror/mode/ruby/ruby.js
new file mode 100755
index 00000000..ddc1a654
--- /dev/null
+++ b/imports/codemirror/mode/ruby/ruby.js
@@ -0,0 +1,195 @@
1CodeMirror.defineMode("ruby", function(config, parserConfig) {
2 function wordObj(words) {
3 var o = {};
4 for (var i = 0, e = words.length; i < e; ++i) o[words[i]] = true;
5 return o;
6 }
7 var keywords = wordObj([
8 "alias", "and", "BEGIN", "begin", "break", "case", "class", "def", "defined?", "do", "else",
9 "elsif", "END", "end", "ensure", "false", "for", "if", "in", "module", "next", "not", "or",
10 "redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless",
11 "until", "when", "while", "yield", "nil", "raise", "throw", "catch", "fail", "loop", "callcc",
12 "caller", "lambda", "proc", "public", "protected", "private", "require", "load",
13 "require_relative", "extend", "autoload"
14 ]);
15 var indentWords = wordObj(["def", "class", "case", "for", "while", "do", "module", "then",
16 "unless", "catch", "loop", "proc"]);
17 var dedentWords = wordObj(["end", "until"]);
18 var matching = {"[": "]", "{": "}", "(": ")"};
19 var curPunc;
20
21 function chain(newtok, stream, state) {
22 state.tokenize.push(newtok);
23 return newtok(stream, state);
24 }
25
26 function tokenBase(stream, state) {
27 curPunc = null;
28 if (stream.sol() && stream.match("=begin") && stream.eol()) {
29 state.tokenize.push(readBlockComment);
30 return "comment";
31 }
32 if (stream.eatSpace()) return null;
33 var ch = stream.next();
34 if (ch == "`" || ch == "'" || ch == '"' || ch == "/") {
35 return chain(readQuoted(ch, "string", ch == '"'), stream, state);
36 } else if (ch == "%") {
37 var style, embed = false;
38 if (stream.eat("s")) style = "atom";
39 else if (stream.eat(/[WQ]/)) { style = "string"; embed = true; }
40 else if (stream.eat(/[wxqr]/)) style = "string";
41 var delim = stream.eat(/[^\w\s]/);
42 if (!delim) return "operator";
43 if (matching.propertyIsEnumerable(delim)) delim = matching[delim];
44 return chain(readQuoted(delim, style, embed, true), stream, state);
45 } else if (ch == "#") {
46 stream.skipToEnd();
47 return "comment";
48 } else if (ch == "<" && stream.eat("<")) {
49 stream.eat("-");
50 stream.eat(/[\'\"\`]/);
51 var match = stream.match(/^\w+/);
52 stream.eat(/[\'\"\`]/);
53 if (match) return chain(readHereDoc(match[0]), stream, state);
54 return null;
55 } else if (ch == "0") {
56 if (stream.eat("x")) stream.eatWhile(/[\da-fA-F]/);
57 else if (stream.eat("b")) stream.eatWhile(/[01]/);
58 else stream.eatWhile(/[0-7]/);
59 return "number";
60 } else if (/\d/.test(ch)) {
61 stream.match(/^[\d_]*(?:\.[\d_]+)?(?:[eE][+\-]?[\d_]+)?/);
62 return "number";
63 } else if (ch == "?") {
64 while (stream.match(/^\\[CM]-/)) {}
65 if (stream.eat("\\")) stream.eatWhile(/\w/);
66 else stream.next();
67 return "string";
68 } else if (ch == ":") {
69 if (stream.eat("'")) return chain(readQuoted("'", "atom", false), stream, state);
70 if (stream.eat('"')) return chain(readQuoted('"', "atom", true), stream, state);
71 stream.eatWhile(/[\w\?]/);
72 return "atom";
73 } else if (ch == "@") {
74 stream.eat("@");
75 stream.eatWhile(/[\w\?]/);
76 return "variable-2";
77 } else if (ch == "$") {
78 stream.next();
79 stream.eatWhile(/[\w\?]/);
80 return "variable-3";
81 } else if (/\w/.test(ch)) {
82 stream.eatWhile(/[\w\?]/);
83 if (stream.eat(":")) return "atom";
84 return "ident";
85 } else if (ch == "|" && (state.varList || state.lastTok == "{" || state.lastTok == "do")) {
86 curPunc = "|";
87 return null;
88 } else if (/[\(\)\[\]{}\\;]/.test(ch)) {
89 curPunc = ch;
90 return null;
91 } else if (ch == "-" && stream.eat(">")) {
92 return "arrow";
93 } else if (/[=+\-\/*:\.^%<>~|]/.test(ch)) {
94 stream.eatWhile(/[=+\-\/*:\.^%<>~|]/);
95 return "operator";
96 } else {
97 return null;
98 }
99 }
100
101 function tokenBaseUntilBrace() {
102 var depth = 1;
103 return function(stream, state) {
104 if (stream.peek() == "}") {
105 depth--;
106 if (depth == 0) {
107 state.tokenize.pop();
108 return state.tokenize[state.tokenize.length-1](stream, state);
109 }
110 } else if (stream.peek() == "{") {
111 depth++;
112 }
113 return tokenBase(stream, state);
114 };
115 }
116 function readQuoted(quote, style, embed, unescaped) {
117 return function(stream, state) {
118 var escaped = false, ch;
119 while ((ch = stream.next()) != null) {
120 if (ch == quote && (unescaped || !escaped)) {
121 state.tokenize.pop();
122 break;
123 }
124 if (embed && ch == "#" && !escaped && stream.eat("{")) {
125 state.tokenize.push(tokenBaseUntilBrace(arguments.callee));
126 break;
127 }
128 escaped = !escaped && ch == "\\";
129 }
130 return style;
131 };
132 }
133 function readHereDoc(phrase) {
134 return function(stream, state) {
135 if (stream.match(phrase)) state.tokenize.pop();
136 else stream.skipToEnd();
137 return "string";
138 };
139 }
140 function readBlockComment(stream, state) {
141 if (stream.sol() && stream.match("=end") && stream.eol())
142 state.tokenize.pop();
143 stream.skipToEnd();
144 return "comment";
145 }
146
147 return {
148 startState: function() {
149 return {tokenize: [tokenBase],
150 indented: 0,
151 context: {type: "top", indented: -config.indentUnit},
152 continuedLine: false,
153 lastTok: null,
154 varList: false};
155 },
156
157 token: function(stream, state) {
158 if (stream.sol()) state.indented = stream.indentation();
159 var style = state.tokenize[state.tokenize.length-1](stream, state), kwtype;
160 if (style == "ident") {
161 var word = stream.current();
162 style = keywords.propertyIsEnumerable(stream.current()) ? "keyword"
163 : /^[A-Z]/.test(word) ? "tag"
164 : (state.lastTok == "def" || state.lastTok == "class" || state.varList) ? "def"
165 : "variable";
166 if (indentWords.propertyIsEnumerable(word)) kwtype = "indent";
167 else if (dedentWords.propertyIsEnumerable(word)) kwtype = "dedent";
168 else if (word == "if" && stream.column() == stream.indentation()) kwtype = "indent";
169 }
170 if (curPunc || (style && style != "comment")) state.lastTok = word || curPunc || style;
171 if (curPunc == "|") state.varList = !state.varList;
172
173 if (kwtype == "indent" || /[\(\[\{]/.test(curPunc))
174 state.context = {prev: state.context, type: curPunc || style, indented: state.indented};
175 else if ((kwtype == "dedent" || /[\)\]\}]/.test(curPunc)) && state.context.prev)
176 state.context = state.context.prev;
177
178 if (stream.eol())
179 state.continuedLine = (curPunc == "\\" || style == "operator");
180 return style;
181 },
182
183 indent: function(state, textAfter) {
184 if (state.tokenize[state.tokenize.length-1] != tokenBase) return 0;
185 var firstChar = textAfter && textAfter.charAt(0);
186 var ct = state.context;
187 var closing = ct.type == matching[firstChar] ||
188 ct.type == "keyword" && /^(?:end|until|else|elsif|when)\b/.test(textAfter);
189 return ct.indented + (closing ? 0 : config.indentUnit) +
190 (state.continuedLine ? config.indentUnit : 0);
191 }
192 };
193});
194
195CodeMirror.defineMIME("text/x-ruby", "ruby");