UNPKG

nide

Version:

Beautiful IDE for Node.js

183 lines (173 loc) 6.72 kB
CodeMirror.defineMode("ruby", function(config, parserConfig) { function wordObj(words) { var o = {}; for (var i = 0, e = words.length; i < e; ++i) o[words[i]] = true; return o; } var keywords = wordObj([ "alias", "and", "BEGIN", "begin", "break", "case", "class", "def", "defined?", "do", "else", "elsif", "END", "end", "ensure", "false", "for", "if", "in", "module", "next", "not", "or", "redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless", "until", "when", "while", "yield", "nil", "raise", "throw", "catch", "fail", "loop", "callcc", "caller", "lambda", "proc", "public", "protected", "private", "require", "load", "require_relative", "extend", "autoload" ]); var indentWords = wordObj(["def", "class", "case", "for", "while", "do", "module", "then", "unless", "catch", "loop", "proc"]); var dedentWords = wordObj(["end", "until"]); var matching = {"[": "]", "{": "}", "(": ")"}; var curPunc; function chain(newtok, stream, state) { state.tokenize = newtok; return newtok(stream, state); } function tokenBase(stream, state) { curPunc = null; if (stream.sol() && stream.match("=begin") && stream.eol()) { state.tokenize = readBlockComment; return "comment"; } if (stream.eatSpace()) return null; var ch = stream.next(); if (ch == "`" || ch == "'" || ch == '"' || ch == "/") { return chain(readQuoted(ch, "string"), stream, state); } else if (ch == "%") { var style; if (stream.eat("s")) style = "atom"; else if (stream.eat(/[wWxqQr]/)) style = "string"; var delim = stream.eat(/[^\w\s]/); if (!delim) return "operator"; if (matching.propertyIsEnumerable(delim)) delim = matching[delim]; return chain(readPercentQuoted(delim, style), stream, state); } else if (ch == "#") { stream.skipToEnd(); return "comment"; } else if (ch == "<" && stream.eat("<")) { stream.eat("-"); stream.eat(/[\'\"\`]/); var match = stream.match(/^\w+/); stream.eat(/[\'\"\`]/); if (match) return chain(readHereDoc(match[0]), stream, state); return null; } else if (ch == "0") { if (stream.eat("x")) stream.eatWhile(/[\da-fA-F]/); else if (stream.eat("b")) stream.eatWhile(/[01]/); else stream.eatWhile(/[0-7]/); return "number"; } else if (/\d/.test(ch)) { stream.match(/^[\d_]*(?:\.[\d_]+)?(?:[eE][+\-]?[\d_]+)?/); return "number"; } else if (ch == "?") { while (stream.match(/^\\[CM]-/)) {} if (stream.eat("\\")) stream.eatWhile(/\w/); else stream.next(); return "string"; } else if (ch == ":") { if (stream.eat("'")) return chain(readQuoted("'", "atom"), stream, state); if (stream.eat('"')) return chain(readQuoted('"', "atom"), stream, state); stream.eatWhile(/[\w\?]/); return "atom"; } else if (ch == "@") { stream.eat("@"); stream.eatWhile(/[\w\?]/); return "variable-2"; } else if (ch == "$") { stream.next(); stream.eatWhile(/[\w\?]/); return "variable-3"; } else if (/\w/.test(ch)) { stream.eatWhile(/[\w\?]/); if (stream.eat(":")) return "atom"; return "ident"; } else if (ch == "|" && (state.varList || state.lastTok == "{" || state.lastTok == "do")) { curPunc = "|"; return null; } else if (/[\(\)\[\]{}\\;]/.test(ch)) { curPunc = ch; return null; } else if (ch == "-" && stream.eat(">")) { return "arrow"; } else if (/[=+\-\/*:\.^%<>~|]/.test(ch)) { stream.eatWhile(/[=+\-\/*:\.^%<>~|]/); return "operator"; } else { return null; } } function readQuoted(quote, style) { return function(stream, state) { var escaped = false, ch; while ((ch = stream.next()) != null) { if (ch == quote && !escaped) { state.tokenize = tokenBase; break; } escaped = !escaped && ch == "\\"; } return style; }; } function readPercentQuoted(quote, style) { return function(stream, state) { if (stream.skipTo(quote)) {stream.next(); state.tokenize = tokenBase;} else stream.skipToEnd(); return style; }; } function readHereDoc(phrase) { return function(stream, state) { if (stream.match(phrase)) state.tokenize = tokenBase; else stream.skipToEnd(); return "string"; }; } function readBlockComment(stream, state) { if (stream.sol() && stream.match("=end") && stream.eol()) state.tokenize = tokenBase; stream.skipToEnd(); return "comment"; } return { startState: function() { return {tokenize: tokenBase, indented: 0, context: {type: "top", indented: -config.indentUnit}, continuedLine: false, lastTok: null, varList: false}; }, token: function(stream, state) { if (stream.sol()) state.indented = stream.indentation(); var style = state.tokenize(stream, state), kwtype; if (style == "ident") { var word = stream.current(); style = keywords.propertyIsEnumerable(stream.current()) ? "keyword" : /^[A-Z]/.test(word) ? "tag" : (state.lastTok == "def" || state.lastTok == "class" || state.varList) ? "def" : "variable"; if (indentWords.propertyIsEnumerable(word)) kwtype = "indent"; else if (dedentWords.propertyIsEnumerable(word)) kwtype = "dedent"; else if (word == "if" && stream.column() == stream.indentation()) kwtype = "indent"; } if (curPunc || (style && style != "comment")) state.lastTok = word || curPunc || style; if (curPunc == "|") state.varList = !state.varList; if (kwtype == "indent" || /[\(\[\{]/.test(curPunc)) state.context = {prev: state.context, type: curPunc || style, indented: state.indented}; else if ((kwtype == "dedent" || /[\)\]\}]/.test(curPunc)) && state.context.prev) state.context = state.context.prev; if (stream.eol()) state.continuedLine = (curPunc == "\\" || style == "operator"); return style; }, indent: function(state, textAfter) { if (state.tokenize != tokenBase) return 0; var firstChar = textAfter && textAfter.charAt(0); var ct = state.context; var closing = ct.type == matching[firstChar] || ct.type == "keyword" && /^(?:end|until|else|elsif|when)\b/.test(textAfter); return ct.indented + (closing ? 0 : config.indentUnit) + (state.continuedLine ? config.indentUnit : 0); } }; }); CodeMirror.defineMIME("text/x-ruby", "ruby");