GPQAPP
359 строк · 9.8 Кб
1// CodeMirror, copyright (c) by Marijn Haverbeke and others
2// Distributed under an MIT license: https://codemirror.net/LICENSE
3
4/**
5* Link to the project's GitHub page:
6* https://github.com/pickhardt/coffeescript-codemirror-mode
7*/
8(function(mod) {9if (typeof exports == "object" && typeof module == "object") // CommonJS10mod(require("../../lib/codemirror"));11else if (typeof define == "function" && define.amd) // AMD12define(["../../lib/codemirror"], mod);13else // Plain browser env14mod(CodeMirror);15})(function(CodeMirror) {16"use strict";17
18CodeMirror.defineMode("coffeescript", function(conf, parserConf) {19var ERRORCLASS = "error";20
21function wordRegexp(words) {22return new RegExp("^((" + words.join(")|(") + "))\\b");23}24
25var operators = /^(?:->|=>|\+[+=]?|-[\-=]?|\*[\*=]?|\/[\/=]?|[=!]=|<[><]?=?|>>?=?|%=?|&=?|\|=?|\^=?|\~|!|\?|(or|and|\|\||&&|\?)=)/;26var delimiters = /^(?:[()\[\]{},:`=;]|\.\.?\.?)/;27var identifiers = /^[_A-Za-z$][_A-Za-z$0-9]*/;28var atProp = /^@[_A-Za-z$][_A-Za-z$0-9]*/;29
30var wordOperators = wordRegexp(["and", "or", "not",31"is", "isnt", "in",32"instanceof", "typeof"]);33var indentKeywords = ["for", "while", "loop", "if", "unless", "else",34"switch", "try", "catch", "finally", "class"];35var commonKeywords = ["break", "by", "continue", "debugger", "delete",36"do", "in", "of", "new", "return", "then",37"this", "@", "throw", "when", "until", "extends"];38
39var keywords = wordRegexp(indentKeywords.concat(commonKeywords));40
41indentKeywords = wordRegexp(indentKeywords);42
43
44var stringPrefixes = /^('{3}|\"{3}|['\"])/;45var regexPrefixes = /^(\/{3}|\/)/;46var commonConstants = ["Infinity", "NaN", "undefined", "null", "true", "false", "on", "off", "yes", "no"];47var constants = wordRegexp(commonConstants);48
49// Tokenizers50function tokenBase(stream, state) {51// Handle scope changes52if (stream.sol()) {53if (state.scope.align === null) state.scope.align = false;54var scopeOffset = state.scope.offset;55if (stream.eatSpace()) {56var lineOffset = stream.indentation();57if (lineOffset > scopeOffset && state.scope.type == "coffee") {58return "indent";59} else if (lineOffset < scopeOffset) {60return "dedent";61}62return null;63} else {64if (scopeOffset > 0) {65dedent(stream, state);66}67}68}69if (stream.eatSpace()) {70return null;71}72
73var ch = stream.peek();74
75// Handle docco title comment (single line)76if (stream.match("####")) {77stream.skipToEnd();78return "comment";79}80
81// Handle multi line comments82if (stream.match("###")) {83state.tokenize = longComment;84return state.tokenize(stream, state);85}86
87// Single line comment88if (ch === "#") {89stream.skipToEnd();90return "comment";91}92
93// Handle number literals94if (stream.match(/^-?[0-9\.]/, false)) {95var floatLiteral = false;96// Floats97if (stream.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i)) {98floatLiteral = true;99}100if (stream.match(/^-?\d+\.\d*/)) {101floatLiteral = true;102}103if (stream.match(/^-?\.\d+/)) {104floatLiteral = true;105}106
107if (floatLiteral) {108// prevent from getting extra . on 1..109if (stream.peek() == "."){110stream.backUp(1);111}112return "number";113}114// Integers115var intLiteral = false;116// Hex117if (stream.match(/^-?0x[0-9a-f]+/i)) {118intLiteral = true;119}120// Decimal121if (stream.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/)) {122intLiteral = true;123}124// Zero by itself with no other piece of number.125if (stream.match(/^-?0(?![\dx])/i)) {126intLiteral = true;127}128if (intLiteral) {129return "number";130}131}132
133// Handle strings134if (stream.match(stringPrefixes)) {135state.tokenize = tokenFactory(stream.current(), false, "string");136return state.tokenize(stream, state);137}138// Handle regex literals139if (stream.match(regexPrefixes)) {140if (stream.current() != "/" || stream.match(/^.*\//, false)) { // prevent highlight of division141state.tokenize = tokenFactory(stream.current(), true, "string-2");142return state.tokenize(stream, state);143} else {144stream.backUp(1);145}146}147
148
149
150// Handle operators and delimiters151if (stream.match(operators) || stream.match(wordOperators)) {152return "operator";153}154if (stream.match(delimiters)) {155return "punctuation";156}157
158if (stream.match(constants)) {159return "atom";160}161
162if (stream.match(atProp) || state.prop && stream.match(identifiers)) {163return "property";164}165
166if (stream.match(keywords)) {167return "keyword";168}169
170if (stream.match(identifiers)) {171return "variable";172}173
174// Handle non-detected items175stream.next();176return ERRORCLASS;177}178
179function tokenFactory(delimiter, singleline, outclass) {180return function(stream, state) {181while (!stream.eol()) {182stream.eatWhile(/[^'"\/\\]/);183if (stream.eat("\\")) {184stream.next();185if (singleline && stream.eol()) {186return outclass;187}188} else if (stream.match(delimiter)) {189state.tokenize = tokenBase;190return outclass;191} else {192stream.eat(/['"\/]/);193}194}195if (singleline) {196if (parserConf.singleLineStringErrors) {197outclass = ERRORCLASS;198} else {199state.tokenize = tokenBase;200}201}202return outclass;203};204}205
206function longComment(stream, state) {207while (!stream.eol()) {208stream.eatWhile(/[^#]/);209if (stream.match("###")) {210state.tokenize = tokenBase;211break;212}213stream.eatWhile("#");214}215return "comment";216}217
218function indent(stream, state, type) {219type = type || "coffee";220var offset = 0, align = false, alignOffset = null;221for (var scope = state.scope; scope; scope = scope.prev) {222if (scope.type === "coffee" || scope.type == "}") {223offset = scope.offset + conf.indentUnit;224break;225}226}227if (type !== "coffee") {228align = null;229alignOffset = stream.column() + stream.current().length;230} else if (state.scope.align) {231state.scope.align = false;232}233state.scope = {234offset: offset,235type: type,236prev: state.scope,237align: align,238alignOffset: alignOffset239};240}241
242function dedent(stream, state) {243if (!state.scope.prev) return;244if (state.scope.type === "coffee") {245var _indent = stream.indentation();246var matched = false;247for (var scope = state.scope; scope; scope = scope.prev) {248if (_indent === scope.offset) {249matched = true;250break;251}252}253if (!matched) {254return true;255}256while (state.scope.prev && state.scope.offset !== _indent) {257state.scope = state.scope.prev;258}259return false;260} else {261state.scope = state.scope.prev;262return false;263}264}265
266function tokenLexer(stream, state) {267var style = state.tokenize(stream, state);268var current = stream.current();269
270// Handle scope changes.271if (current === "return") {272state.dedent = true;273}274if (((current === "->" || current === "=>") && stream.eol())275|| style === "indent") {276indent(stream, state);277}278var delimiter_index = "[({".indexOf(current);279if (delimiter_index !== -1) {280indent(stream, state, "])}".slice(delimiter_index, delimiter_index+1));281}282if (indentKeywords.exec(current)){283indent(stream, state);284}285if (current == "then"){286dedent(stream, state);287}288
289
290if (style === "dedent") {291if (dedent(stream, state)) {292return ERRORCLASS;293}294}295delimiter_index = "])}".indexOf(current);296if (delimiter_index !== -1) {297while (state.scope.type == "coffee" && state.scope.prev)298state.scope = state.scope.prev;299if (state.scope.type == current)300state.scope = state.scope.prev;301}302if (state.dedent && stream.eol()) {303if (state.scope.type == "coffee" && state.scope.prev)304state.scope = state.scope.prev;305state.dedent = false;306}307
308return style;309}310
311var external = {312startState: function(basecolumn) {313return {314tokenize: tokenBase,315scope: {offset:basecolumn || 0, type:"coffee", prev: null, align: false},316prop: false,317dedent: 0318};319},320
321token: function(stream, state) {322var fillAlign = state.scope.align === null && state.scope;323if (fillAlign && stream.sol()) fillAlign.align = false;324
325var style = tokenLexer(stream, state);326if (style && style != "comment") {327if (fillAlign) fillAlign.align = true;328state.prop = style == "punctuation" && stream.current() == "."329}330
331return style;332},333
334indent: function(state, text) {335if (state.tokenize != tokenBase) return 0;336var scope = state.scope;337var closer = text && "])}".indexOf(text.charAt(0)) > -1;338if (closer) while (scope.type == "coffee" && scope.prev) scope = scope.prev;339var closes = closer && scope.type === text.charAt(0);340if (scope.align)341return scope.alignOffset - (closes ? 1 : 0);342else343return (closes ? scope.prev : scope).offset;344},345
346lineComment: "#",347fold: "indent"348};349return external;350});351
352// IANA registered media type
353// https://www.iana.org/assignments/media-types/
354CodeMirror.defineMIME("application/vnd.coffeescript", "coffeescript");355
356CodeMirror.defineMIME("text/x-coffeescript", "coffeescript");357CodeMirror.defineMIME("text/coffeescript", "coffeescript");358
359});360