codemirror-rails 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. data/codemirror-rails-0.0.0.gem +0 -0
  2. data/codemirror-rails-0.1.gem +0 -0
  3. data/lib/codemirror/rails/version.rb +2 -2
  4. data/vendor/assets/javascripts/codemirror.js +122 -63
  5. data/vendor/assets/javascripts/codemirror/modes/clike.js +221 -0
  6. data/vendor/assets/javascripts/codemirror/modes/css.js +124 -0
  7. data/vendor/assets/javascripts/codemirror/modes/diff.js +13 -0
  8. data/vendor/assets/javascripts/codemirror/modes/haskell.js +242 -0
  9. data/vendor/assets/javascripts/codemirror/modes/htmlmixed.js +79 -0
  10. data/vendor/assets/javascripts/codemirror/modes/javascript.js +348 -0
  11. data/vendor/assets/javascripts/codemirror/modes/lua.js +138 -0
  12. data/vendor/assets/javascripts/codemirror/modes/php.js +111 -0
  13. data/vendor/assets/javascripts/codemirror/modes/plsql.js +217 -0
  14. data/vendor/assets/javascripts/codemirror/modes/python.js +321 -0
  15. data/vendor/assets/javascripts/codemirror/modes/rst.js +333 -0
  16. data/vendor/assets/javascripts/codemirror/modes/scheme.js +181 -0
  17. data/vendor/assets/javascripts/codemirror/modes/smalltalk.js +122 -0
  18. data/vendor/assets/javascripts/codemirror/modes/stex.js +167 -0
  19. data/vendor/assets/javascripts/codemirror/modes/xml.js +227 -0
  20. data/vendor/assets/javascripts/codemirror/modes/yaml.js +95 -0
  21. data/vendor/assets/javascripts/codemirror/overlay.js +51 -0
  22. data/vendor/assets/javascripts/codemirror/runmode.js +27 -0
  23. data/vendor/assets/stylesheets/codemirror.css +3 -0
  24. data/vendor/assets/stylesheets/codemirror/modes/clike.css +7 -0
  25. data/vendor/assets/stylesheets/codemirror/modes/diff.css +3 -0
  26. data/vendor/assets/stylesheets/codemirror/modes/rst.css +75 -0
  27. metadata +25 -3
  28. data/codemirror-rails-0.1.1.gem +0 -0
@@ -0,0 +1,111 @@
1
+ (function() {
2
+ function keywords(str) {
3
+ var obj = {}, words = str.split(" ");
4
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
5
+ return obj;
6
+ }
7
+ var phpKeywords =
8
+ keywords("abstract and array as break case catch cfunction class clone const continue declare " +
9
+ "default do else elseif enddeclare endfor endforeach endif endswitch endwhile extends " +
10
+ "final for foreach function global goto if implements interface instanceof namespace " +
11
+ "new or private protected public static switch throw try use var while xor return");
12
+ function heredoc(delim) {
13
+ return function(stream, state) {
14
+ if (stream.match(delim)) state.tokenize = null;
15
+ else stream.skipToEnd();
16
+ return "string";
17
+ }
18
+ }
19
+ var phpConfig = {
20
+ name: "clike",
21
+ keywords: phpKeywords,
22
+ atoms: keywords("true false null"),
23
+ multiLineStrings: true,
24
+ hooks: {
25
+ "$": function(stream, state) {
26
+ stream.eatWhile(/[\w\$_]/);
27
+ return "variable-2";
28
+ },
29
+ "<": function(stream, state) {
30
+ if (stream.match(/<</)) {
31
+ stream.eatWhile(/[\w\.]/);
32
+ state.tokenize = heredoc(stream.current().slice(3));
33
+ return state.tokenize(stream, state);
34
+ }
35
+ return false;
36
+ }
37
+ }
38
+ };
39
+
40
+ CodeMirror.defineMode("php", function(config, parserConfig) {
41
+ var htmlMode = CodeMirror.getMode(config, "text/html");
42
+ var jsMode = CodeMirror.getMode(config, "text/javascript");
43
+ var cssMode = CodeMirror.getMode(config, "text/css");
44
+ var phpMode = CodeMirror.getMode(config, phpConfig);
45
+
46
+ function dispatch(stream, state) { // TODO open PHP inside text/css
47
+ if (state.curMode == htmlMode) {
48
+ var style = htmlMode.token(stream, state.curState);
49
+ if (style == "meta" && /^<\?/.test(stream.current())) {
50
+ state.curMode = phpMode;
51
+ state.curState = state.php;
52
+ state.curClose = /^\?>/;
53
+ }
54
+ else if (style == "tag" && stream.current() == ">" && state.curState.context) {
55
+ if (/^script$/i.test(state.curState.context.tagName)) {
56
+ state.curMode = jsMode;
57
+ state.curState = jsMode.startState(htmlMode.indent(state.curState, ""));
58
+ state.curClose = /^<\/\s*script\s*>/i;
59
+ }
60
+ else if (/^style$/i.test(state.curState.context.tagName)) {
61
+ state.curMode = cssMode;
62
+ state.curState = cssMode.startState(htmlMode.indent(state.curState, ""));
63
+ state.curClose = /^<\/\s*style\s*>/i;
64
+ }
65
+ }
66
+ return style;
67
+ }
68
+ else if (stream.match(state.curClose, false)) {
69
+ state.curMode = htmlMode;
70
+ state.curState = state.html;
71
+ state.curClose = null;
72
+ return dispatch(stream, state);
73
+ }
74
+ else return state.curMode.token(stream, state.curState);
75
+ }
76
+
77
+ return {
78
+ startState: function() {
79
+ var html = htmlMode.startState();
80
+ return {html: html,
81
+ php: phpMode.startState(),
82
+ curMode: parserConfig.startOpen ? phpMode : htmlMode,
83
+ curState: parserConfig.startOpen ? phpMode.startState() : html,
84
+ curClose: parserConfig.startOpen ? /^\?>/ : null}
85
+ },
86
+
87
+ copyState: function(state) {
88
+ var html = state.html, htmlNew = CodeMirror.copyState(htmlMode, html),
89
+ php = state.php, phpNew = CodeMirror.copyState(phpMode, php), cur;
90
+ if (state.curState == html) cur = htmlNew;
91
+ else if (state.curState == php) cur = phpNew;
92
+ else cur = CodeMirror.copyState(state.curMode, state.curState);
93
+ return {html: htmlNew, php: phpNew, curMode: state.curMode, curState: cur, curClose: state.curClose};
94
+ },
95
+
96
+ token: dispatch,
97
+
98
+ indent: function(state, textAfter) {
99
+ if ((state.curMode != phpMode && /^\s*<\//.test(textAfter)) ||
100
+ (state.curMode == phpMode && /^\?>/.test(textAfter)))
101
+ return htmlMode.indent(state.html, textAfter);
102
+ return state.curMode.indent(state.curState, textAfter);
103
+ },
104
+
105
+ electricChars: "/{}:"
106
+ }
107
+ });
108
+ CodeMirror.defineMIME("application/x-httpd-php", "php");
109
+ CodeMirror.defineMIME("application/x-httpd-php-open", {name: "php", startOpen: true});
110
+ CodeMirror.defineMIME("text/x-php", phpConfig);
111
+ })();
@@ -0,0 +1,217 @@
1
+ CodeMirror.defineMode("plsql", function(config, parserConfig) {
2
+ var indentUnit = config.indentUnit,
3
+ keywords = parserConfig.keywords,
4
+ functions = parserConfig.functions,
5
+ types = parserConfig.types,
6
+ sqlplus = parserConfig.sqlplus,
7
+ multiLineStrings = parserConfig.multiLineStrings;
8
+ var isOperatorChar = /[+\-*&%=<>!?:\/|]/;
9
+ function chain(stream, state, f) {
10
+ state.tokenize = f;
11
+ return f(stream, state);
12
+ }
13
+
14
+ var type;
15
+ function ret(tp, style) {
16
+ type = tp;
17
+ return style;
18
+ }
19
+
20
+ function tokenBase(stream, state) {
21
+ var ch = stream.next();
22
+ // start of string?
23
+ if (ch == '"' || ch == "'")
24
+ return chain(stream, state, tokenString(ch));
25
+ // is it one of the special signs []{}().,;? Seperator?
26
+ else if (/[\[\]{}\(\),;\.]/.test(ch))
27
+ return ret(ch);
28
+ // start of a number value?
29
+ else if (/\d/.test(ch)) {
30
+ stream.eatWhile(/[\w\.]/);
31
+ return ret("number", "number");
32
+ }
33
+ // multi line comment or simple operator?
34
+ else if (ch == "/") {
35
+ if (stream.eat("*")) {
36
+ return chain(stream, state, tokenComment);
37
+ }
38
+ else {
39
+ stream.eatWhile(isOperatorChar);
40
+ return ret("operator", "operator");
41
+ }
42
+ }
43
+ // single line comment or simple operator?
44
+ else if (ch == "-") {
45
+ if (stream.eat("-")) {
46
+ stream.skipToEnd();
47
+ return ret("comment", "comment");
48
+ }
49
+ else {
50
+ stream.eatWhile(isOperatorChar);
51
+ return ret("operator", "operator");
52
+ }
53
+ }
54
+ // pl/sql variable?
55
+ else if (ch == "@" || ch == "$") {
56
+ stream.eatWhile(/[\w\d\$_]/);
57
+ return ret("word", "variable");
58
+ }
59
+ // is it a operator?
60
+ else if (isOperatorChar.test(ch)) {
61
+ stream.eatWhile(isOperatorChar);
62
+ return ret("operator", "operator");
63
+ }
64
+ else {
65
+ // get the whole word
66
+ stream.eatWhile(/[\w\$_]/);
67
+ // is it one of the listed keywords?
68
+ if (keywords && keywords.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "keyword");
69
+ // is it one of the listed functions?
70
+ if (functions && functions.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "builtin");
71
+ // is it one of the listed types?
72
+ if (types && types.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "variable-2");
73
+ // is it one of the listed sqlplus keywords?
74
+ if (sqlplus && sqlplus.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "variable-3");
75
+ // default: just a "word"
76
+ return ret("word", "plsql-word");
77
+ }
78
+ }
79
+
80
+ function tokenString(quote) {
81
+ return function(stream, state) {
82
+ var escaped = false, next, end = false;
83
+ while ((next = stream.next()) != null) {
84
+ if (next == quote && !escaped) {end = true; break;}
85
+ escaped = !escaped && next == "\\";
86
+ }
87
+ if (end || !(escaped || multiLineStrings))
88
+ state.tokenize = tokenBase;
89
+ return ret("string", "plsql-string");
90
+ };
91
+ }
92
+
93
+ function tokenComment(stream, state) {
94
+ var maybeEnd = false, ch;
95
+ while (ch = stream.next()) {
96
+ if (ch == "/" && maybeEnd) {
97
+ state.tokenize = tokenBase;
98
+ break;
99
+ }
100
+ maybeEnd = (ch == "*");
101
+ }
102
+ return ret("comment", "plsql-comment");
103
+ }
104
+
105
+ // Interface
106
+
107
+ return {
108
+ startState: function(basecolumn) {
109
+ return {
110
+ tokenize: tokenBase,
111
+ startOfLine: true
112
+ };
113
+ },
114
+
115
+ token: function(stream, state) {
116
+ if (stream.eatSpace()) return null;
117
+ var style = state.tokenize(stream, state);
118
+ return style;
119
+ }
120
+ };
121
+ });
122
+
123
+ (function() {
124
+ function keywords(str) {
125
+ var obj = {}, words = str.split(" ");
126
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
127
+ return obj;
128
+ }
129
+ var cKeywords = "abort accept access add all alter and any array arraylen as asc assert assign at attributes audit " +
130
+ "authorization avg " +
131
+ "base_table begin between binary_integer body boolean by " +
132
+ "case cast char char_base check close cluster clusters colauth column comment commit compress connect " +
133
+ "connected constant constraint crash create current currval cursor " +
134
+ "data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete " +
135
+ "desc digits dispose distinct do drop " +
136
+ "else elsif enable end entry escape exception exception_init exchange exclusive exists exit external " +
137
+ "fast fetch file for force form from function " +
138
+ "generic goto grant group " +
139
+ "having " +
140
+ "identified if immediate in increment index indexes indicator initial initrans insert interface intersect " +
141
+ "into is " +
142
+ "key " +
143
+ "level library like limited local lock log logging long loop " +
144
+ "master maxextents maxtrans member minextents minus mislabel mode modify multiset " +
145
+ "new next no noaudit nocompress nologging noparallel not nowait number_base " +
146
+ "object of off offline on online only open option or order out " +
147
+ "package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior " +
148
+ "private privileges procedure public " +
149
+ "raise range raw read rebuild record ref references refresh release rename replace resource restrict return " +
150
+ "returning reverse revoke rollback row rowid rowlabel rownum rows run " +
151
+ "savepoint schema segment select separate session set share snapshot some space split sql start statement " +
152
+ "storage subtype successful synonym " +
153
+ "tabauth table tables tablespace task terminate then to trigger truncate type " +
154
+ "union unique unlimited unrecoverable unusable update use using " +
155
+ "validate value values variable view views " +
156
+ "when whenever where while with work";
157
+
158
+ var cFunctions = "abs acos add_months ascii asin atan atan2 average " +
159
+ "bfilename " +
160
+ "ceil chartorowid chr concat convert cos cosh count " +
161
+ "decode deref dual dump dup_val_on_index " +
162
+ "empty error exp " +
163
+ "false floor found " +
164
+ "glb greatest " +
165
+ "hextoraw " +
166
+ "initcap instr instrb isopen " +
167
+ "last_day least lenght lenghtb ln lower lpad ltrim lub " +
168
+ "make_ref max min mod months_between " +
169
+ "new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower " +
170
+ "nls_sort nls_upper nlssort no_data_found notfound null nvl " +
171
+ "others " +
172
+ "power " +
173
+ "rawtohex reftohex round rowcount rowidtochar rpad rtrim " +
174
+ "sign sin sinh soundex sqlcode sqlerrm sqrt stddev substr substrb sum sysdate " +
175
+ "tan tanh to_char to_date to_label to_multi_byte to_number to_single_byte translate true trunc " +
176
+ "uid upper user userenv " +
177
+ "variance vsize";
178
+
179
+ var cTypes = "bfile blob " +
180
+ "character clob " +
181
+ "dec " +
182
+ "float " +
183
+ "int integer " +
184
+ "mlslabel " +
185
+ "natural naturaln nchar nclob number numeric nvarchar2 " +
186
+ "real rowtype " +
187
+ "signtype smallint string " +
188
+ "varchar varchar2";
189
+
190
+ var cSqlplus = "appinfo arraysize autocommit autoprint autorecovery autotrace " +
191
+ "blockterminator break btitle " +
192
+ "cmdsep colsep compatibility compute concat copycommit copytypecheck " +
193
+ "define describe " +
194
+ "echo editfile embedded escape exec execute " +
195
+ "feedback flagger flush " +
196
+ "heading headsep " +
197
+ "instance " +
198
+ "linesize lno loboffset logsource long longchunksize " +
199
+ "markup " +
200
+ "native newpage numformat numwidth " +
201
+ "pagesize pause pno " +
202
+ "recsep recsepchar release repfooter repheader " +
203
+ "serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber " +
204
+ "sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix " +
205
+ "tab term termout time timing trimout trimspool ttitle " +
206
+ "underline " +
207
+ "verify version " +
208
+ "wrap";
209
+
210
+ CodeMirror.defineMIME("text/x-plsql", {
211
+ name: "plsql",
212
+ keywords: keywords(cKeywords),
213
+ functions: keywords(cFunctions),
214
+ types: keywords(cTypes),
215
+ sqlplus: keywords(cSqlplus)
216
+ });
217
+ }());
@@ -0,0 +1,321 @@
1
+ CodeMirror.defineMode("python", function(conf) {
2
+ var ERRORCLASS = 'error';
3
+
4
+ function wordRegexp(words) {
5
+ return new RegExp("^((" + words.join(")|(") + "))\\b");
6
+ }
7
+
8
+ var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
9
+ var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
10
+ var doubleOperators = new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
11
+ var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
12
+ var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
13
+ var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
14
+
15
+ var wordOperators = wordRegexp(['and', 'or', 'not', 'is', 'in']);
16
+ var commonkeywords = ['as', 'assert', 'break', 'class', 'continue',
17
+ 'def', 'del', 'elif', 'else', 'except', 'finally',
18
+ 'for', 'from', 'global', 'if', 'import',
19
+ 'lambda', 'pass', 'raise', 'return',
20
+ 'try', 'while', 'with', 'yield'];
21
+ var commontypes = ['bool', 'classmethod', 'complex', 'dict', 'enumerate',
22
+ 'float', 'frozenset', 'int', 'list', 'object',
23
+ 'property', 'reversed', 'set', 'slice', 'staticmethod',
24
+ 'str', 'super', 'tuple', 'type'];
25
+ var py2 = {'types': ['basestring', 'buffer', 'file', 'long', 'unicode',
26
+ 'xrange'],
27
+ 'keywords': ['exec', 'print']};
28
+ var py3 = {'types': ['bytearray', 'bytes', 'filter', 'map', 'memoryview',
29
+ 'open', 'range', 'zip'],
30
+ 'keywords': ['nonlocal']};
31
+
32
+ if (!!conf.mode.version && parseInt(conf.mode.version, 10) === 3) {
33
+ commonkeywords = commonkeywords.concat(py3.keywords);
34
+ commontypes = commontypes.concat(py3.types);
35
+ var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i");
36
+ } else {
37
+ commonkeywords = commonkeywords.concat(py2.keywords);
38
+ commontypes = commontypes.concat(py2.types);
39
+ var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
40
+ }
41
+ var keywords = wordRegexp(commonkeywords);
42
+ var types = wordRegexp(commontypes);
43
+
44
+ var indentInfo = null;
45
+
46
+ // tokenizers
47
+ function tokenBase(stream, state) {
48
+ // Handle scope changes
49
+ if (stream.sol()) {
50
+ var scopeOffset = state.scopes[0].offset;
51
+ if (stream.eatSpace()) {
52
+ var lineOffset = stream.indentation();
53
+ if (lineOffset > scopeOffset) {
54
+ indentInfo = 'indent';
55
+ } else if (lineOffset < scopeOffset) {
56
+ indentInfo = 'dedent';
57
+ }
58
+ return null;
59
+ } else {
60
+ if (scopeOffset > 0) {
61
+ dedent(stream, state);
62
+ }
63
+ }
64
+ }
65
+ if (stream.eatSpace()) {
66
+ return null;
67
+ }
68
+
69
+ var ch = stream.peek();
70
+
71
+ // Handle Comments
72
+ if (ch === '#') {
73
+ stream.skipToEnd();
74
+ return 'comment';
75
+ }
76
+
77
+ // Handle Number Literals
78
+ if (stream.match(/^[0-9\.]/, false)) {
79
+ var floatLiteral = false;
80
+ // Floats
81
+ if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; }
82
+ if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
83
+ if (stream.match(/^\.\d+/)) { floatLiteral = true; }
84
+ if (floatLiteral) {
85
+ // Float literals may be "imaginary"
86
+ stream.eat(/J/i);
87
+ return 'number';
88
+ }
89
+ // Integers
90
+ var intLiteral = false;
91
+ // Hex
92
+ if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; }
93
+ // Binary
94
+ if (stream.match(/^0b[01]+/i)) { intLiteral = true; }
95
+ // Octal
96
+ if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; }
97
+ // Decimal
98
+ if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
99
+ // Decimal literals may be "imaginary"
100
+ stream.eat(/J/i);
101
+ // TODO - Can you have imaginary longs?
102
+ intLiteral = true;
103
+ }
104
+ // Zero by itself with no other piece of number.
105
+ if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
106
+ if (intLiteral) {
107
+ // Integer literals may be "long"
108
+ stream.eat(/L/i);
109
+ return 'number';
110
+ }
111
+ }
112
+
113
+ // Handle Strings
114
+ if (stream.match(stringPrefixes)) {
115
+ state.tokenize = tokenStringFactory(stream.current());
116
+ return state.tokenize(stream, state);
117
+ }
118
+
119
+ // Handle operators and Delimiters
120
+ if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
121
+ return null;
122
+ }
123
+ if (stream.match(doubleOperators)
124
+ || stream.match(singleOperators)
125
+ || stream.match(wordOperators)) {
126
+ return 'operator';
127
+ }
128
+ if (stream.match(singleDelimiters)) {
129
+ return null;
130
+ }
131
+
132
+ if (stream.match(types)) {
133
+ return 'builtin';
134
+ }
135
+
136
+ if (stream.match(keywords)) {
137
+ return 'keyword';
138
+ }
139
+
140
+ if (stream.match(identifiers)) {
141
+ return 'variable';
142
+ }
143
+
144
+ // Handle non-detected items
145
+ stream.next();
146
+ return ERRORCLASS;
147
+ }
148
+
149
+ function tokenStringFactory(delimiter) {
150
+ while ('rub'.indexOf(delimiter[0].toLowerCase()) >= 0) {
151
+ delimiter = delimiter.substr(1);
152
+ }
153
+ var delim_re = new RegExp(delimiter);
154
+ var singleline = delimiter.length == 1;
155
+ var OUTCLASS = 'string';
156
+
157
+ return function tokenString(stream, state) {
158
+ while (!stream.eol()) {
159
+ stream.eatWhile(/[^'"\\]/);
160
+ if (stream.eat('\\')) {
161
+ stream.next();
162
+ if (singleline && stream.eol()) {
163
+ return OUTCLASS;
164
+ }
165
+ } else if (stream.match(delim_re)) {
166
+ state.tokenize = tokenBase;
167
+ return OUTCLASS;
168
+ } else {
169
+ stream.eat(/['"]/);
170
+ }
171
+ }
172
+ if (singleline) {
173
+ if (conf.mode.singleLineStringErrors) {
174
+ OUTCLASS = ERRORCLASS
175
+ } else {
176
+ state.tokenize = tokenBase;
177
+ }
178
+ }
179
+ return OUTCLASS;
180
+ };
181
+ }
182
+
183
+ function indent(stream, state, type) {
184
+ type = type || 'py';
185
+ var indentUnit = 0;
186
+ if (type === 'py') {
187
+ for (var i = 0; i < state.scopes.length; ++i) {
188
+ if (state.scopes[i].type === 'py') {
189
+ indentUnit = state.scopes[i].offset + conf.indentUnit;
190
+ break;
191
+ }
192
+ }
193
+ } else {
194
+ indentUnit = stream.column() + stream.current().length;
195
+ }
196
+ state.scopes.unshift({
197
+ offset: indentUnit,
198
+ type: type
199
+ });
200
+ }
201
+
202
+ function dedent(stream, state) {
203
+ if (state.scopes.length == 1) return;
204
+ if (state.scopes[0].type === 'py') {
205
+ var _indent = stream.indentation();
206
+ var _indent_index = -1;
207
+ for (var i = 0; i < state.scopes.length; ++i) {
208
+ if (_indent === state.scopes[i].offset) {
209
+ _indent_index = i;
210
+ break;
211
+ }
212
+ }
213
+ if (_indent_index === -1) {
214
+ return true;
215
+ }
216
+ while (state.scopes[0].offset !== _indent) {
217
+ state.scopes.shift();
218
+ }
219
+ return false
220
+ } else {
221
+ state.scopes.shift();
222
+ return false;
223
+ }
224
+ }
225
+
226
+ function tokenLexer(stream, state) {
227
+ indentInfo = null;
228
+ var style = state.tokenize(stream, state);
229
+ var current = stream.current();
230
+
231
+ // Handle '.' connected identifiers
232
+ if (current === '.') {
233
+ style = state.tokenize(stream, state);
234
+ current = stream.current();
235
+ if (style === 'variable') {
236
+ return 'variable';
237
+ } else {
238
+ return ERRORCLASS;
239
+ }
240
+ }
241
+
242
+ // Handle decorators
243
+ if (current === '@') {
244
+ style = state.tokenize(stream, state);
245
+ current = stream.current();
246
+ if (style === 'variable'
247
+ || current === '@staticmethod'
248
+ || current === '@classmethod') {
249
+ return 'meta';
250
+ } else {
251
+ return ERRORCLASS;
252
+ }
253
+ }
254
+
255
+ // Handle scope changes.
256
+ if (current === 'pass' || current === 'return') {
257
+ state.dedent += 1;
258
+ }
259
+ if ((current === ':' && !state.lambda && state.scopes[0].type == 'py')
260
+ || indentInfo === 'indent') {
261
+ indent(stream, state);
262
+ }
263
+ var delimiter_index = '[({'.indexOf(current);
264
+ if (delimiter_index !== -1) {
265
+ indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
266
+ }
267
+ if (indentInfo === 'dedent') {
268
+ if (dedent(stream, state)) {
269
+ return ERRORCLASS;
270
+ }
271
+ }
272
+ delimiter_index = '])}'.indexOf(current);
273
+ if (delimiter_index !== -1) {
274
+ if (dedent(stream, state)) {
275
+ return ERRORCLASS;
276
+ }
277
+ }
278
+ if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'py') {
279
+ if (state.scopes.length > 1) state.scopes.shift();
280
+ state.dedent -= 1;
281
+ }
282
+
283
+ return style;
284
+ }
285
+
286
+ var external = {
287
+ startState: function(basecolumn) {
288
+ return {
289
+ tokenize: tokenBase,
290
+ scopes: [{offset:basecolumn || 0, type:'py'}],
291
+ lastToken: null,
292
+ lambda: false,
293
+ dedent: 0
294
+ };
295
+ },
296
+
297
+ token: function(stream, state) {
298
+ var style = tokenLexer(stream, state);
299
+
300
+ state.lastToken = {style:style, content: stream.current()};
301
+
302
+ if (stream.eol() && stream.lambda) {
303
+ state.lambda = false;
304
+ }
305
+
306
+ return style;
307
+ },
308
+
309
+ indent: function(state, textAfter) {
310
+ if (state.tokenize != tokenBase) {
311
+ return 0;
312
+ }
313
+
314
+ return state.scopes[0].offset;
315
+ }
316
+
317
+ };
318
+ return external;
319
+ });
320
+
321
+ CodeMirror.defineMIME("text/x-python", "python");