codemirror-rails 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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");