: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// Stylus mode created by Dmitry Kiselyov http://git.io/AaRB
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
})(function(CodeMirror) {
CodeMirror.defineMode("stylus", function(config) {
var indentUnit = config.indentUnit,
tagKeywords = keySet(tagKeywords_),
tagVariablesRegexp = /^(a|b|i|s|col|em)$/i,
propertyKeywords = keySet(propertyKeywords_),
nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_),
valueKeywords = keySet(valueKeywords_),
colorKeywords = keySet(colorKeywords_),
documentTypes = keySet(documentTypes_),
documentTypesRegexp = wordRegexp(documentTypes_),
mediaFeatures = keySet(mediaFeatures_),
mediaTypes = keySet(mediaTypes_),
fontProperties = keySet(fontProperties_),
operatorsRegexp = /^\s*([.]{2,3}|&&|\|\||\*\*|[?!=:]?=|[-+*\/%<>]=?|\?:|\~)/,
wordOperatorKeywordsRegexp = wordRegexp(wordOperatorKeywords_),
blockKeywords = keySet(blockKeywords_),
vendorPrefixesRegexp = new RegExp(/^\-(moz|ms|o|webkit)-/i),
commonAtoms = keySet(commonAtoms_),
function tokenBase(stream, state) {
firstWordMatch = stream.string.match(/(^[\w-]+\s*=\s*$)|(^\s*[\w-]+\s*=\s*[\w-])|(^\s*(\.|#|@|\$|\&|\[|\d|\+|::?|\{|\>|~|\/)?\s*[\w-]*([a-z0-9-]|\*|\/\*)(\(|,)?)/);
state.context.line.firstWord = firstWordMatch ? firstWordMatch[0].replace(/^\s*/, "") : "";
state.context.line.indent = stream.indentation();
if (stream.match("//")) {
return ["comment", "comment"];
if (stream.match("/*")) {
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
if (ch == "\"" || ch == "'") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
stream.eatWhile(/[\w\\-]/);
return ["def", stream.current()];
// ID selector or Hex color
if (stream.match(/^[0-9a-f]{6}|[0-9a-f]{3}/i)) {
if (stream.match(/^[a-z][\w-]*/i)) {
return ["builtin", "hash"];
if (stream.match(vendorPrefixesRegexp)) {
return ["meta", "vendor-prefixes"];
if (stream.match(/^-?[0-9]?\.?[0-9]/)) {
stream.eatWhile(/[a-z%]/i);
return ["number", "unit"];
return [stream.match(/^(important|optional)/i) ? "keyword": "operator", "important"];
if (ch == "." && stream.match(/^\.[a-z][\w-]*/i)) {
return ["qualifier", "qualifier"];
// url url-prefix domain regexp
if (stream.match(documentTypesRegexp)) {
if (stream.peek() == "(") state.tokenize = tokenParenthesized;
return ["property", "word"];
if (stream.match(/^[a-z][\w-]*\(/i)) {
return ["keyword", "mixin"];
if (stream.match(/^(\+|-)[a-z][\w-]*\(/i)) {
return ["keyword", "block-mixin"];
// Parent Reference BEM naming
if (stream.string.match(/^\s*&/) && stream.match(/^[-_]+[a-z][\w-]*/)) {
return ["qualifier", "qualifier"];
// / Root Reference & Parent Reference
if (stream.match(/^(\/|&)(-|_|:|\.|#|[a-z])/)) {
return ["variable-3", "reference"];
if (stream.match(/^&{1}\s*$/)) {
return ["variable-3", "reference"];
if (stream.match(wordOperatorKeywordsRegexp)) {
return ["operator", "operator"];
if (stream.match(/^\$?[-_]*[a-z0-9]+[\w-]*/i)) {
if (stream.match(/^(\.|\[)[\w-\'\"\]]+/i, false)) {
if (!wordIsTag(stream.current())) {
return ["variable-2", "variable-name"];
return ["variable-2", "word"];
if (stream.match(operatorsRegexp)) {
return ["operator", stream.current()];
if (/[:;,{}\[\]\(\)]/.test(ch)) {
function tokenCComment(stream, state) {
var maybeEnd = false, ch;
while ((ch = stream.next()) != null) {
if (maybeEnd && ch == "/") {
return ["comment", "comment"];
function tokenString(quote) {
return function(stream, state) {
while ((ch = stream.next()) != null) {
if (ch == quote && !escaped) {
if (quote == ")") stream.backUp(1);
escaped = !escaped && ch == "\\";
if (ch == quote || !escaped && quote != ")") state.tokenize = null;
return ["string", "string"];
function tokenParenthesized(stream, state) {
stream.next(); // Must be "("
if (!stream.match(/\s*[\"\')]/, false))
state.tokenize = tokenString(")");
function Context(type, indent, prev, line) {
this.line = line || {firstWord: "", indent: 0};
function pushContext(state, stream, type, indent) {
indent = indent >= 0 ? indent : indentUnit;
state.context = new Context(type, stream.indentation() + indent, state.context);
function popContext(state, currentIndent) {
var contextIndent = state.context.indent - indentUnit;
currentIndent = currentIndent || false;
state.context = state.context.prev;
if (currentIndent) state.context.indent = contextIndent;
return state.context.type;
function pass(type, stream, state) {
return states[state.context.type](type, stream, state);
function popAndPass(type, stream, state, n) {
for (var i = n || 1; i > 0; i--)
state.context = state.context.prev;
return pass(type, stream, state);
function wordIsTag(word) {
return word.toLowerCase() in tagKeywords;
function wordIsProperty(word) {
word = word.toLowerCase();
return word in propertyKeywords || word in fontProperties;
function wordIsBlock(word) {
return word.toLowerCase() in blockKeywords;
function wordIsVendorPrefix(word) {
return word.toLowerCase().match(vendorPrefixesRegexp);
function wordAsValue(word) {
var wordLC = word.toLowerCase();
var override = "variable-2";
if (wordIsTag(word)) override = "tag";
else if (wordIsBlock(word)) override = "block-keyword";
else if (wordIsProperty(word)) override = "property";
else if (wordLC in valueKeywords || wordLC in commonAtoms) override = "atom";
else if (wordLC == "return" || wordLC in colorKeywords) override = "keyword";
else if (word.match(/^[A-Z]/)) override = "string";
function typeIsBlock(type, stream) {
return ((endOfLine(stream) && (type == "{" || type == "]" || type == "hash" || type == "qualifier")) || type == "block-mixin");
function typeIsInterpolation(type, stream) {
return type == "{" && stream.match(/^\s*\$?[\w-]+/i, false);
function typeIsPseudo(type, stream) {
return type == ":" && stream.match(/^[a-z-]+/, false);
function startOfLine(stream) {
return stream.sol() || stream.string.match(new RegExp("^\\s*" + escapeRegExp(stream.current())));
function endOfLine(stream) {
return stream.eol() || stream.match(/^\s*$/, false);
function firstWordOfLine(line) {
var re = /^\s*[-_]*[a-z0-9]+[\w-]*/i;
var result = typeof line == "string" ? line.match(re) : line.string.match(re);
return result ? result[0].replace(/^\s*/, "") : "";
states.block = function(type, stream, state) {
if ((type == "comment" && startOfLine(stream)) ||
(type == "," && endOfLine(stream)) ||
return pushContext(state, stream, "block", 0);
if (typeIsInterpolation(type, stream)) {
return pushContext(state, stream, "interpolation");
if (endOfLine(stream) && type == "]") {
if (!/^\s*(\.|#|:|\[|\*|&)/.test(stream.string) && !wordIsTag(firstWordOfLine(stream))) {
return pushContext(state, stream, "block", 0);
if (typeIsBlock(type, stream, state)) {
return pushContext(state, stream, "block");
if (type == "}" && endOfLine(stream)) {
return pushContext(state, stream, "block", 0);
if (type == "variable-name") {
if (stream.string.match(/^\s?\$[\w-\.\[\]\'\"]+$/) || wordIsBlock(firstWordOfLine(stream))) {
return pushContext(state, stream, "variableName");
return pushContext(state, stream, "variableName", 0);
if (!endOfLine(stream) && !wordIsBlock(firstWordOfLine(stream))) {
return pushContext(state, stream, "block", 0);
return pushContext(state, stream, "block");
if (endOfLine(stream) || stream.match(/\s*(,|\.|#|\[|:|{)/,false)) {
return pushContext(state, stream, "block");
if (typeIsPseudo(type, stream)) {
return pushContext(state, stream, "pseudo");
if (/@(font-face|media|supports|(-moz-)?document)/.test(type)) {
return pushContext(state, stream, endOfLine(stream) ? "block" : "atBlock");
if (/@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
return pushContext(state, stream, "keyframes");
if (/@extends?/.test(type)) {
return pushContext(state, stream, "extend", 0);
if (type && type.charAt(0) == "@") {
if (stream.indentation() > 0 && wordIsProperty(stream.current().slice(1))) {
if (/(@import|@require|@charset)/.test(type)) {
return pushContext(state, stream, "block", 0);
return pushContext(state, stream, "block");
if (type == "reference" && endOfLine(stream)) {
return pushContext(state, stream, "block");
return pushContext(state, stream, "parens");
if (type == "vendor-prefixes") {
return pushContext(state, stream, "vendorPrefixes");
var word = stream.current();
override = wordAsValue(word);
if (override == "property") {
if (startOfLine(stream)) {
return pushContext(state, stream, "block", 0);
if (/embed|menu|pre|progress|sub|table/.test(word)) {
if (wordIsProperty(firstWordOfLine(stream))) {
if (stream.string.match(new RegExp("\\[\\s*" + word + "|" + word +"\\s*\\]"))) {
if (tagVariablesRegexp.test(word)) {
if ((startOfLine(stream) && stream.string.match(/=/)) ||
!stream.string.match(/^(\s*\.|#|\&|\[|\/|>|\*)/) &&
!wordIsTag(firstWordOfLine(stream)))) {
if (wordIsBlock(firstWordOfLine(stream))) return "block";
return pushContext(state, stream, "block", 0);
if (endOfLine(stream)) return pushContext(state, stream, "block");
if (override == "block-keyword") {
if (stream.current(/(if|unless)/) && !startOfLine(stream)) {
return pushContext(state, stream, "block");
if (word == "return") return pushContext(state, stream, "block", 0);
if (override == "variable-2" && stream.string.match(/^\s?\$[\w-\.\[\]\'\"]+$/)) {
return pushContext(state, stream, "block");
return state.context.type;
states.parens = function(type, stream, state) {
if (type == "(") return pushContext(state, stream, "parens");
if (state.context.prev.type == "parens") {
return popContext(state);
if ((stream.string.match(/^[a-z][\w-]*\(/i) && endOfLine(stream)) ||
wordIsBlock(firstWordOfLine(stream)) ||
/(\.|#|:|\[|\*|&|>|~|\+|\/)/.test(firstWordOfLine(stream)) ||
(!stream.string.match(/^-?[a-z][\w-\.\[\]\'\"]*\s*=/) &&
wordIsTag(firstWordOfLine(stream)))) {
return pushContext(state, stream, "block");
if (stream.string.match(/^[\$-]?[a-z][\w-\.\[\]\'\"]*\s*=/) ||
stream.string.match(/^\s*(\(|\)|[0-9])/) ||
stream.string.match(/^\s+[a-z][\w-]*\(/i) ||
stream.string.match(/^\s+[\$-]?[a-z]/i)) {
return pushContext(state, stream, "block", 0);
if (endOfLine(stream)) return pushContext(state, stream, "block");
else return pushContext(state, stream, "block", 0);
if (type && type.charAt(0) == "@" && wordIsProperty(stream.current().slice(1))) {
var word = stream.current();
override = wordAsValue(word);
if (override == "tag" && tagVariablesRegexp.test(word)) {
if (override == "property" || word == "to") override = "atom";
if (type == "variable-name") {
return pushContext(state, stream, "variableName");
if (typeIsPseudo(type, stream)) {
return pushContext(state, stream, "pseudo");
return state.context.type;
states.vendorPrefixes = function(type, stream, state) {
return pushContext(state, stream, "block", 0);
return popContext(state);
states.pseudo = function(type, stream, state) {