Index: Source/devtools/front_end/cm/coffeescript.js |
diff --git a/Source/devtools/front_end/cm/coffeescript.js b/Source/devtools/front_end/cm/coffeescript.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..509d9207bb7077540bdc890f061602eeb63df61b |
--- /dev/null |
+++ b/Source/devtools/front_end/cm/coffeescript.js |
@@ -0,0 +1,347 @@ |
+/** |
+ * Link to the project's GitHub page: |
+ * https://github.com/pickhardt/coffeescript-codemirror-mode |
+ */ |
+CodeMirror.defineMode('coffeescript', function(conf) { |
+ var ERRORCLASS = 'error'; |
+ |
+ function wordRegexp(words) { |
+ return new RegExp("^((" + words.join(")|(") + "))\\b"); |
+ } |
+ |
+ var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!\?]"); |
+ var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\},:`=;\\.]'); |
+ var doubleOperators = new RegExp("^((\->)|(\=>)|(\\+\\+)|(\\+\\=)|(\\-\\-)|(\\-\\=)|(\\*\\*)|(\\*\\=)|(\\/\\/)|(\\/\\=)|(==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//))"); |
+ var doubleDelimiters = new RegExp("^((\\.\\.)|(\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))"); |
+ var tripleDelimiters = new RegExp("^((\\.\\.\\.)|(//=)|(>>=)|(<<=)|(\\*\\*=))"); |
+ var identifiers = new RegExp("^[_A-Za-z$][_A-Za-z$0-9]*"); |
+ var properties = new RegExp("^(@|this\.)[_A-Za-z$][_A-Za-z$0-9]*"); |
+ |
+ var wordOperators = wordRegexp(['and', 'or', 'not', |
+ 'is', 'isnt', 'in', |
+ 'instanceof', 'typeof']); |
+ var indentKeywords = ['for', 'while', 'loop', 'if', 'unless', 'else', |
+ 'switch', 'try', 'catch', 'finally', 'class']; |
+ var commonKeywords = ['break', 'by', 'continue', 'debugger', 'delete', |
+ 'do', 'in', 'of', 'new', 'return', 'then', |
+ 'this', 'throw', 'when', 'until']; |
+ |
+ var keywords = wordRegexp(indentKeywords.concat(commonKeywords)); |
+ |
+ indentKeywords = wordRegexp(indentKeywords); |
+ |
+ |
+ var stringPrefixes = new RegExp("^('{3}|\"{3}|['\"])"); |
+ var regexPrefixes = new RegExp("^(/{3}|/)"); |
+ var commonConstants = ['Infinity', 'NaN', 'undefined', 'null', 'true', 'false', 'on', 'off', 'yes', 'no']; |
+ var constants = wordRegexp(commonConstants); |
+ |
+ // Tokenizers |
+ function tokenBase(stream, state) { |
+ // Handle scope changes |
+ if (stream.sol()) { |
+ var scopeOffset = state.scopes[0].offset; |
+ if (stream.eatSpace()) { |
+ var lineOffset = stream.indentation(); |
+ if (lineOffset > scopeOffset) { |
+ return 'indent'; |
+ } else if (lineOffset < scopeOffset) { |
+ return 'dedent'; |
+ } |
+ return null; |
+ } else { |
+ if (scopeOffset > 0) { |
+ dedent(stream, state); |
+ } |
+ } |
+ } |
+ if (stream.eatSpace()) { |
+ return null; |
+ } |
+ |
+ var ch = stream.peek(); |
+ |
+ // Handle docco title comment (single line) |
+ if (stream.match("####")) { |
+ stream.skipToEnd(); |
+ return 'comment'; |
+ } |
+ |
+ // Handle multi line comments |
+ if (stream.match("###")) { |
+ state.tokenize = longComment; |
+ return state.tokenize(stream, state); |
+ } |
+ |
+ // Single line comment |
+ if (ch === '#') { |
+ stream.skipToEnd(); |
+ return 'comment'; |
+ } |
+ |
+ // Handle number literals |
+ if (stream.match(/^-?[0-9\.]/, false)) { |
+ var floatLiteral = false; |
+ // Floats |
+ if (stream.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i)) { |
+ floatLiteral = true; |
+ } |
+ if (stream.match(/^-?\d+\.\d*/)) { |
+ floatLiteral = true; |
+ } |
+ if (stream.match(/^-?\.\d+/)) { |
+ floatLiteral = true; |
+ } |
+ |
+ if (floatLiteral) { |
+ // prevent from getting extra . on 1.. |
+ if (stream.peek() == "."){ |
+ stream.backUp(1); |
+ } |
+ return 'number'; |
+ } |
+ // Integers |
+ var intLiteral = false; |
+ // Hex |
+ if (stream.match(/^-?0x[0-9a-f]+/i)) { |
+ intLiteral = true; |
+ } |
+ // Decimal |
+ if (stream.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/)) { |
+ intLiteral = true; |
+ } |
+ // Zero by itself with no other piece of number. |
+ if (stream.match(/^-?0(?![\dx])/i)) { |
+ intLiteral = true; |
+ } |
+ if (intLiteral) { |
+ return 'number'; |
+ } |
+ } |
+ |
+ // Handle strings |
+ if (stream.match(stringPrefixes)) { |
+ state.tokenize = tokenFactory(stream.current(), 'string'); |
+ return state.tokenize(stream, state); |
+ } |
+ // Handle regex literals |
+ if (stream.match(regexPrefixes)) { |
+ if (stream.current() != '/' || stream.match(/^.*\//, false)) { // prevent highlight of division |
+ state.tokenize = tokenFactory(stream.current(), 'string-2'); |
+ return state.tokenize(stream, state); |
+ } else { |
+ stream.backUp(1); |
+ } |
+ } |
+ |
+ // Handle operators and delimiters |
+ if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) { |
+ return 'punctuation'; |
+ } |
+ if (stream.match(doubleOperators) |
+ || stream.match(singleOperators) |
+ || stream.match(wordOperators)) { |
+ return 'operator'; |
+ } |
+ if (stream.match(singleDelimiters)) { |
+ return 'punctuation'; |
+ } |
+ |
+ if (stream.match(constants)) { |
+ return 'atom'; |
+ } |
+ |
+ if (stream.match(keywords)) { |
+ return 'keyword'; |
+ } |
+ |
+ if (stream.match(identifiers)) { |
+ return 'variable'; |
+ } |
+ |
+ if (stream.match(properties)) { |
+ return 'property'; |
+ } |
+ |
+ // Handle non-detected items |
+ stream.next(); |
+ return ERRORCLASS; |
+ } |
+ |
+ function tokenFactory(delimiter, outclass) { |
+ var singleline = delimiter.length == 1; |
+ return function(stream, state) { |
+ while (!stream.eol()) { |
+ stream.eatWhile(/[^'"\/\\]/); |
+ if (stream.eat('\\')) { |
+ stream.next(); |
+ if (singleline && stream.eol()) { |
+ return outclass; |
+ } |
+ } else if (stream.match(delimiter)) { |
+ state.tokenize = tokenBase; |
+ return outclass; |
+ } else { |
+ stream.eat(/['"\/]/); |
+ } |
+ } |
+ if (singleline) { |
+ if (conf.mode.singleLineStringErrors) { |
+ outclass = ERRORCLASS; |
+ } else { |
+ state.tokenize = tokenBase; |
+ } |
+ } |
+ return outclass; |
+ }; |
+ } |
+ |
+ function longComment(stream, state) { |
+ while (!stream.eol()) { |
+ stream.eatWhile(/[^#]/); |
+ if (stream.match("###")) { |
+ state.tokenize = tokenBase; |
+ break; |
+ } |
+ stream.eatWhile("#"); |
+ } |
+ return "comment"; |
+ } |
+ |
+ function indent(stream, state, type) { |
+ type = type || 'coffee'; |
+ var indentUnit = 0; |
+ if (type === 'coffee') { |
+ for (var i = 0; i < state.scopes.length; i++) { |
+ if (state.scopes[i].type === 'coffee') { |
+ indentUnit = state.scopes[i].offset + conf.indentUnit; |
+ break; |
+ } |
+ } |
+ } else { |
+ indentUnit = stream.column() + stream.current().length; |
+ } |
+ state.scopes.unshift({ |
+ offset: indentUnit, |
+ type: type |
+ }); |
+ } |
+ |
+ function dedent(stream, state) { |
+ if (state.scopes.length == 1) return; |
+ if (state.scopes[0].type === 'coffee') { |
+ var _indent = stream.indentation(); |
+ var _indent_index = -1; |
+ for (var i = 0; i < state.scopes.length; ++i) { |
+ if (_indent === state.scopes[i].offset) { |
+ _indent_index = i; |
+ break; |
+ } |
+ } |
+ if (_indent_index === -1) { |
+ return true; |
+ } |
+ while (state.scopes[0].offset !== _indent) { |
+ state.scopes.shift(); |
+ } |
+ return false; |
+ } else { |
+ state.scopes.shift(); |
+ return false; |
+ } |
+ } |
+ |
+ function tokenLexer(stream, state) { |
+ var style = state.tokenize(stream, state); |
+ var current = stream.current(); |
+ |
+ // Handle '.' connected identifiers |
+ if (current === '.') { |
+ style = state.tokenize(stream, state); |
+ current = stream.current(); |
+ if (style === 'variable') { |
+ return 'variable'; |
+ } else { |
+ return ERRORCLASS; |
+ } |
+ } |
+ |
+ // Handle scope changes. |
+ if (current === 'return') { |
+ state.dedent += 1; |
+ } |
+ if (((current === '->' || current === '=>') && |
+ !state.lambda && |
+ state.scopes[0].type == 'coffee' && |
+ stream.peek() === '') |
+ || style === 'indent') { |
+ indent(stream, state); |
+ } |
+ var delimiter_index = '[({'.indexOf(current); |
+ if (delimiter_index !== -1) { |
+ indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1)); |
+ } |
+ if (indentKeywords.exec(current)){ |
+ indent(stream, state); |
+ } |
+ if (current == 'then'){ |
+ dedent(stream, state); |
+ } |
+ |
+ |
+ if (style === 'dedent') { |
+ if (dedent(stream, state)) { |
+ return ERRORCLASS; |
+ } |
+ } |
+ delimiter_index = '])}'.indexOf(current); |
+ if (delimiter_index !== -1) { |
+ if (dedent(stream, state)) { |
+ return ERRORCLASS; |
+ } |
+ } |
+ if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'coffee') { |
+ if (state.scopes.length > 1) state.scopes.shift(); |
+ state.dedent -= 1; |
+ } |
+ |
+ return style; |
+ } |
+ |
+ var external = { |
+ startState: function(basecolumn) { |
+ return { |
+ tokenize: tokenBase, |
+ scopes: [{offset:basecolumn || 0, type:'coffee'}], |
+ lastToken: null, |
+ lambda: false, |
+ dedent: 0 |
+ }; |
+ }, |
+ |
+ token: function(stream, state) { |
+ var style = tokenLexer(stream, state); |
+ |
+ state.lastToken = {style:style, content: stream.current()}; |
+ |
+ if (stream.eol() && stream.lambda) { |
+ state.lambda = false; |
+ } |
+ |
+ return style; |
+ }, |
+ |
+ indent: function(state) { |
+ if (state.tokenize != tokenBase) { |
+ return 0; |
+ } |
+ |
+ return state.scopes[0].offset; |
+ }, |
+ |
+ lineComment: "#" |
+ }; |
+ return external; |
+}); |
+ |
+CodeMirror.defineMIME('text/x-coffeescript', 'coffeescript'); |