diff options
Diffstat (limited to 'imports/codemirror/mode/ruby/ruby.js')
-rwxr-xr-x | imports/codemirror/mode/ruby/ruby.js | 195 |
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 @@ | |||
1 | CodeMirror.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 | |||
195 | CodeMirror.defineMIME("text/x-ruby", "ruby"); | ||