|
|
CodeMirror.defineMode("css", function(config) {
|
|
|
var indentUnit = config.indentUnit, type;
|
|
|
function ret(style, tp) {type = tp; return style;}
|
|
|
|
|
|
function tokenBase(stream, state) {
|
|
|
var ch = stream.next();
|
|
|
if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("meta", stream.current());}
|
|
|
else if (ch == "/" && stream.eat("*")) {
|
|
|
state.tokenize = tokenCComment;
|
|
|
return tokenCComment(stream, state);
|
|
|
}
|
|
|
else if (ch == "<" && stream.eat("!")) {
|
|
|
state.tokenize = tokenSGMLComment;
|
|
|
return tokenSGMLComment(stream, state);
|
|
|
}
|
|
|
else if (ch == "=") ret(null, "compare");
|
|
|
else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
|
|
|
else if (ch == "\"" || ch == "'") {
|
|
|
state.tokenize = tokenString(ch);
|
|
|
return state.tokenize(stream, state);
|
|
|
}
|
|
|
else if (ch == "#") {
|
|
|
stream.eatWhile(/[\w\\\-]/);
|
|
|
return ret("atom", "hash");
|
|
|
}
|
|
|
else if (ch == "!") {
|
|
|
stream.match(/^\s*\w*/);
|
|
|
return ret("keyword", "important");
|
|
|
}
|
|
|
else if (/\d/.test(ch)) {
|
|
|
stream.eatWhile(/[\w.%]/);
|
|
|
return ret("number", "unit");
|
|
|
}
|
|
|
else if (/[,.+>*\/]/.test(ch)) {
|
|
|
return ret(null, "select-op");
|
|
|
}
|
|
|
else if (/[;{}:\[\]]/.test(ch)) {
|
|
|
return ret(null, ch);
|
|
|
}
|
|
|
else {
|
|
|
stream.eatWhile(/[\w\\\-]/);
|
|
|
return ret("variable", "variable");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
function tokenCComment(stream, state) {
|
|
|
var maybeEnd = false, ch;
|
|
|
while ((ch = stream.next()) != null) {
|
|
|
if (maybeEnd && ch == "/") {
|
|
|
state.tokenize = tokenBase;
|
|
|
break;
|
|
|
}
|
|
|
maybeEnd = (ch == "*");
|
|
|
}
|
|
|
return ret("comment", "comment");
|
|
|
}
|
|
|
|
|
|
function tokenSGMLComment(stream, state) {
|
|
|
var dashes = 0, ch;
|
|
|
while ((ch = stream.next()) != null) {
|
|
|
if (dashes >= 2 && ch == ">") {
|
|
|
state.tokenize = tokenBase;
|
|
|
break;
|
|
|
}
|
|
|
dashes = (ch == "-") ? dashes + 1 : 0;
|
|
|
}
|
|
|
return ret("comment", "comment");
|
|
|
}
|
|
|
|
|
|
function tokenString(quote) {
|
|
|
return function(stream, state) {
|
|
|
var escaped = false, ch;
|
|
|
while ((ch = stream.next()) != null) {
|
|
|
if (ch == quote && !escaped)
|
|
|
break;
|
|
|
escaped = !escaped && ch == "\\";
|
|
|
}
|
|
|
if (!escaped) state.tokenize = tokenBase;
|
|
|
return ret("string", "string");
|
|
|
};
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
startState: function(base) {
|
|
|
return {tokenize: tokenBase,
|
|
|
baseIndent: base || 0,
|
|
|
stack: []};
|
|
|
},
|
|
|
|
|
|
token: function(stream, state) {
|
|
|
if (stream.eatSpace()) return null;
|
|
|
var style = state.tokenize(stream, state);
|
|
|
|
|
|
var context = state.stack[state.stack.length-1];
|
|
|
if (type == "hash" && context == "rule") style = "atom";
|
|
|
else if (style == "variable") {
|
|
|
if (context == "rule") style = "number";
|
|
|
else if (!context || context == "@media{") style = "tag";
|
|
|
}
|
|
|
|
|
|
if (context == "rule" && /^[\{\};]$/.test(type))
|
|
|
state.stack.pop();
|
|
|
if (type == "{") {
|
|
|
if (context == "@media") state.stack[state.stack.length-1] = "@media{";
|
|
|
else state.stack.push("{");
|
|
|
}
|
|
|
else if (type == "}") state.stack.pop();
|
|
|
else if (type == "@media") state.stack.push("@media");
|
|
|
else if (context == "{" && type != "comment") state.stack.push("rule");
|
|
|
return style;
|
|
|
},
|
|
|
|
|
|
indent: function(state, textAfter) {
|
|
|
var n = state.stack.length;
|
|
|
if (/^\}/.test(textAfter))
|
|
|
n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1;
|
|
|
return state.baseIndent + n * indentUnit;
|
|
|
},
|
|
|
|
|
|
electricChars: "}"
|
|
|
};
|
|
|
});
|
|
|
|
|
|
CodeMirror.defineMIME("text/css", "css");
|
|
|
|