2013-03-28 15:29:40 -04:00
/ *
LESS mode - http : //www.lesscss.org/
Ported to CodeMirror by Peter Kroon < plakroon @ gmail . com >
2014-02-13 15:19:17 -04:00
Report bugs / issues here : https : //github.com/marijnh/CodeMirror/issues
GitHub : @ peterkroon
2013-03-28 15:29:40 -04:00
* /
CodeMirror . defineMode ( "less" , function ( config ) {
var indentUnit = config . indentUnit , type ;
function ret ( style , tp ) { type = tp ; return style ; }
2014-02-13 15:19:17 -04:00
2013-03-28 15:29:40 -04:00
var selectors = /(^\:root$|^\:nth\-child$|^\:nth\-last\-child$|^\:nth\-of\-type$|^\:nth\-last\-of\-type$|^\:first\-child$|^\:last\-child$|^\:first\-of\-type$|^\:last\-of\-type$|^\:only\-child$|^\:only\-of\-type$|^\:empty$|^\:link|^\:visited$|^\:active$|^\:hover$|^\:focus$|^\:target$|^\:lang$|^\:enabled^\:disabled$|^\:checked$|^\:first\-line$|^\:first\-letter$|^\:before$|^\:after$|^\:not$|^\:required$|^\:invalid$)/ ;
2014-02-13 15:19:17 -04:00
2013-03-28 15:29:40 -04:00
function tokenBase ( stream , state ) {
var ch = stream . next ( ) ;
2014-02-13 15:19:17 -04:00
2013-03-28 15:29:40 -04:00
if ( ch == "@" ) { stream . eatWhile ( /[\w\-]/ ) ; return ret ( "meta" , stream . current ( ) ) ; }
else if ( ch == "/" && stream . eat ( "*" ) ) {
state . tokenize = tokenCComment ;
return tokenCComment ( stream , state ) ;
2014-02-13 15:19:17 -04:00
} else if ( ch == "<" && stream . eat ( "!" ) ) {
2013-03-28 15:29:40 -04:00
state . tokenize = tokenSGMLComment ;
return tokenSGMLComment ( stream , state ) ;
2014-02-13 15:19:17 -04:00
} else if ( ch == "=" ) ret ( null , "compare" ) ;
2013-03-28 15:29:40 -04:00
else if ( ch == "|" && stream . eat ( "=" ) ) return ret ( null , "compare" ) ;
else if ( ch == "\"" || ch == "'" ) {
state . tokenize = tokenString ( ch ) ;
return state . tokenize ( stream , state ) ;
2014-02-13 15:19:17 -04:00
} else if ( ch == "/" ) { // e.g.: .png will not be parsed as a class
2013-03-28 15:29:40 -04:00
if ( stream . eat ( "/" ) ) {
state . tokenize = tokenSComment ;
return tokenSComment ( stream , state ) ;
2014-02-13 15:19:17 -04:00
} else {
if ( type == "string" || type == "(" ) return ret ( "string" , "string" ) ;
if ( state . stack [ state . stack . length - 1 ] !== undefined ) return ret ( null , ch ) ;
stream . eatWhile ( /[\a-zA-Z0-9\-_.\s]/ ) ;
if ( /\/|\)|#/ . test ( stream . peek ( ) || ( stream . eatSpace ( ) && stream . peek ( ) === ")" ) ) || stream . eol ( ) ) return ret ( "string" , "string" ) ; // let url(/images/logo.png) without quotes return as string
2013-03-28 15:29:40 -04:00
}
2014-02-13 15:19:17 -04:00
} else if ( ch == "!" ) {
2013-03-28 15:29:40 -04:00
stream . match ( /^\s*\w*/ ) ;
return ret ( "keyword" , "important" ) ;
2014-02-13 15:19:17 -04:00
} else if ( /\d/ . test ( ch ) ) {
2013-03-28 15:29:40 -04:00
stream . eatWhile ( /[\w.%]/ ) ;
return ret ( "number" , "unit" ) ;
2014-02-13 15:19:17 -04:00
} else if ( /[,+<>*\/]/ . test ( ch ) ) {
2013-03-28 15:29:40 -04:00
if ( stream . peek ( ) == "=" || type == "a" ) return ret ( "string" , "string" ) ;
2014-02-13 15:19:17 -04:00
if ( ch === "," ) return ret ( null , ch ) ;
2013-03-28 15:29:40 -04:00
return ret ( null , "select-op" ) ;
2014-02-13 15:19:17 -04:00
} else if ( /[;{}:\[\]()~\|]/ . test ( ch ) ) {
if ( ch == ":" ) {
2013-03-28 15:29:40 -04:00
stream . eatWhile ( /[a-z\\\-]/ ) ;
if ( selectors . test ( stream . current ( ) ) ) {
return ret ( "tag" , "tag" ) ;
2014-02-13 15:19:17 -04:00
} else if ( stream . peek ( ) == ":" ) { //::-webkit-search-decoration
2013-03-28 15:29:40 -04:00
stream . next ( ) ;
stream . eatWhile ( /[a-z\\\-]/ ) ;
if ( stream . current ( ) . match ( /\:\:\-(o|ms|moz|webkit)\-/ ) ) return ret ( "string" , "string" ) ;
if ( selectors . test ( stream . current ( ) . substring ( 1 ) ) ) return ret ( "tag" , "tag" ) ;
return ret ( null , ch ) ;
2014-02-13 15:19:17 -04:00
} else {
return ret ( null , ch ) ;
2013-03-28 15:29:40 -04:00
}
2014-02-13 15:19:17 -04:00
} else if ( ch == "~" ) {
2013-03-28 15:29:40 -04:00
if ( type == "r" ) return ret ( "string" , "string" ) ;
2014-02-13 15:19:17 -04:00
} else {
2013-03-28 15:29:40 -04:00
return ret ( null , ch ) ;
}
2014-02-13 15:19:17 -04:00
} else if ( ch == "." ) {
if ( type == "(" ) return ret ( "string" , "string" ) ; // allow url(../image.png)
2013-03-28 15:29:40 -04:00
stream . eatWhile ( /[\a-zA-Z0-9\-_]/ ) ;
2014-02-13 15:19:17 -04:00
if ( stream . peek ( ) === " " ) stream . eatSpace ( ) ;
if ( stream . peek ( ) === ")" || type === ":" ) return ret ( "number" , "unit" ) ; //rgba(0,0,0,.25);
else if ( stream . current ( ) . length > 1 ) {
if ( state . stack [ state . stack . length - 1 ] === "rule" && ! stream . match ( /^[{,+(]/ , false ) ) return ret ( "number" , "unit" ) ;
}
2013-03-28 15:29:40 -04:00
return ret ( "tag" , "tag" ) ;
2014-02-13 15:19:17 -04:00
} else if ( ch == "#" ) {
2013-03-28 15:29:40 -04:00
//we don't eat white-space, we want the hex color and or id only
stream . eatWhile ( /[A-Za-z0-9]/ ) ;
//check if there is a proper hex color length e.g. #eee || #eeeEEE
if ( stream . current ( ) . length == 4 || stream . current ( ) . length == 7 ) {
if ( stream . current ( ) . match ( /[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/ , false ) != null ) { //is there a valid hex color value present in the current stream
//when not a valid hex value, parse as id
if ( stream . current ( ) . substring ( 1 ) != stream . current ( ) . match ( /[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/ , false ) ) return ret ( "atom" , "tag" ) ;
//eat white-space
stream . eatSpace ( ) ;
//when hex value declaration doesn't end with [;,] but is does with a slash/cc comment treat it as an id, just like the other hex values that don't end with[;,]
2014-02-13 15:19:17 -04:00
if ( /[\/<>.(){!$%^&*_\-\\?=+\|#'~`]/ . test ( stream . peek ( ) ) ) {
if ( type === "select-op" ) return ret ( "number" , "unit" ) ; else return ret ( "atom" , "tag" ) ;
}
2013-03-28 15:29:40 -04:00
//#time { color: #aaa }
else if ( stream . peek ( ) == "}" ) return ret ( "number" , "unit" ) ;
//we have a valid hex color value, parse as id whenever an element/class is defined after the hex(id) value e.g. #eee aaa || #eee .aaa
else if ( /[a-zA-Z\\]/ . test ( stream . peek ( ) ) ) return ret ( "atom" , "tag" ) ;
//when a hex value is on the end of a line, parse as id
else if ( stream . eol ( ) ) return ret ( "atom" , "tag" ) ;
//default
else return ret ( "number" , "unit" ) ;
2014-02-13 15:19:17 -04:00
} else { //when not a valid hexvalue in the current stream e.g. #footer
2013-03-28 15:29:40 -04:00
stream . eatWhile ( /[\w\\\-]/ ) ;
2014-02-13 15:19:17 -04:00
return ret ( "atom" , stream . current ( ) ) ;
2013-03-28 15:29:40 -04:00
}
2014-02-13 15:19:17 -04:00
} else { //when not a valid hexvalue length
2013-03-28 15:29:40 -04:00
stream . eatWhile ( /[\w\\\-]/ ) ;
2014-02-13 15:19:17 -04:00
if ( state . stack [ state . stack . length - 1 ] === "rule" ) return ret ( "atom" , stream . current ( ) ) ; return ret ( "atom" , stream . current ( ) ) ;
2013-03-28 15:29:40 -04:00
return ret ( "atom" , "tag" ) ;
}
2014-02-13 15:19:17 -04:00
} else if ( ch == "&" ) {
2013-03-28 15:29:40 -04:00
stream . eatWhile ( /[\w\-]/ ) ;
return ret ( null , ch ) ;
2014-02-13 15:19:17 -04:00
} else {
2013-03-28 15:29:40 -04:00
stream . eatWhile ( /[\w\\\-_%.{]/ ) ;
2014-02-13 15:19:17 -04:00
if ( stream . current ( ) . match ( /\\/ ) !== null ) {
if ( stream . current ( ) . charAt ( stream . current ( ) . length - 1 ) === "\\" ) {
stream . eat ( /\'|\"|\)|\(/ ) ;
while ( stream . eatWhile ( /[\w\\\-_%.{]/ ) ) {
stream . eat ( /\'|\"|\)|\(/ ) ;
}
return ret ( "string" , stream . current ( ) ) ;
}
} //else if(type === "tag")return ret("tag", "tag");
else if ( type == "string" ) {
if ( state . stack [ state . stack . length - 1 ] === "{" && stream . peek ( ) === ":" ) return ret ( "variable" , "variable" ) ;
if ( stream . peek ( ) === "/" ) stream . eatWhile ( /[\w\\\-_%.{:\/]/ ) ;
return ret ( type , stream . current ( ) ) ;
} else if ( stream . current ( ) . match ( /(^http$|^https$)/ ) != null ) {
2013-03-28 15:29:40 -04:00
stream . eatWhile ( /[\w\\\-_%.{:\/]/ ) ;
2014-02-13 15:19:17 -04:00
if ( stream . peek ( ) === "/" ) stream . eatWhile ( /[\w\\\-_%.{:\/]/ ) ;
2013-03-28 15:29:40 -04:00
return ret ( "string" , "string" ) ;
2014-02-13 15:19:17 -04:00
} else if ( stream . peek ( ) == "<" || stream . peek ( ) == ">" || stream . peek ( ) == "+" ) {
if ( type === "(" && ( stream . current ( ) === "n" || stream . current ( ) === "-n" ) ) return ret ( "string" , stream . current ( ) ) ;
2013-03-28 15:29:40 -04:00
return ret ( "tag" , "tag" ) ;
2014-02-13 15:19:17 -04:00
} else if ( /\(/ . test ( stream . peek ( ) ) ) {
if ( stream . current ( ) === "when" ) return ret ( "variable" , "variable" ) ;
else if ( state . stack [ state . stack . length - 1 ] === "@media" && stream . current ( ) === "and" ) return ret ( "variable" , stream . current ( ) ) ;
2013-03-28 15:29:40 -04:00
return ret ( null , ch ) ;
2014-02-13 15:19:17 -04:00
} else if ( stream . peek ( ) == "/" && state . stack [ state . stack . length - 1 ] !== undefined ) { // url(dir/center/image.png)
if ( stream . peek ( ) === "/" ) stream . eatWhile ( /[\w\\\-_%.{:\/]/ ) ;
return ret ( "string" , stream . current ( ) ) ;
} else if ( stream . current ( ) . match ( /\-\d|\-.\d/ ) ) { // match e.g.: -5px -0.4 etc... only colorize the minus sign
2013-03-28 15:29:40 -04:00
//commment out these 2 comment if you want the minus sign to be parsed as null -500px
//stream.backUp(stream.current().length-1);
2014-02-13 15:19:17 -04:00
//return ret(null, ch);
2013-03-28 15:29:40 -04:00
return ret ( "number" , "unit" ) ;
2014-02-13 15:19:17 -04:00
} else if ( /\/|[\s\)]/ . test ( stream . peek ( ) || stream . eol ( ) || ( stream . eatSpace ( ) && stream . peek ( ) == "/" ) ) && stream . current ( ) . indexOf ( "." ) !== - 1 ) {
2013-03-28 15:29:40 -04:00
if ( stream . current ( ) . substring ( stream . current ( ) . length - 1 , stream . current ( ) . length ) == "{" ) {
stream . backUp ( 1 ) ;
return ret ( "tag" , "tag" ) ;
} //end if
stream . eatSpace ( ) ;
if ( /[{<>.a-zA-Z\/]/ . test ( stream . peek ( ) ) || stream . eol ( ) ) return ret ( "tag" , "tag" ) ; // e.g. button.icon-plus
return ret ( "string" , "string" ) ; // let url(/images/logo.png) without quotes return as string
2014-02-13 15:19:17 -04:00
} else if ( stream . eol ( ) || stream . peek ( ) == "[" || stream . peek ( ) == "#" || type == "tag" ) {
2013-03-28 15:29:40 -04:00
if ( stream . current ( ) . substring ( stream . current ( ) . length - 1 , stream . current ( ) . length ) == "{" ) stream . backUp ( 1 ) ;
2014-02-13 15:19:17 -04:00
else if ( state . stack [ state . stack . length - 1 ] === "border-color" || state . stack [ state . stack . length - 1 ] === "background-position" || state . stack [ state . stack . length - 1 ] === "font-family" ) return ret ( null , stream . current ( ) ) ;
else if ( type === "tag" ) return ret ( "tag" , "tag" ) ;
else if ( ( type === ":" || type === "unit" ) && state . stack [ state . stack . length - 1 ] === "rule" ) return ret ( null , stream . current ( ) ) ;
else if ( state . stack [ state . stack . length - 1 ] === "rule" && type === "tag" ) return ret ( "string" , stream . current ( ) ) ;
else if ( state . stack [ state . stack . length - 1 ] === ";" && type === ":" ) return ret ( null , stream . current ( ) ) ;
//else if(state.stack[state.stack.length-1] === ";" || type === "")return ret("variable", stream.current());
else if ( stream . peek ( ) === "#" && type !== undefined && type . match ( /\+|,|tag|select\-op|}|{|;/g ) === null ) return ret ( "string" , stream . current ( ) ) ;
else if ( type === "variable" ) return ret ( null , stream . current ( ) ) ;
else if ( state . stack [ state . stack . length - 1 ] === "{" && type === "comment" ) return ret ( "variable" , stream . current ( ) ) ;
else if ( state . stack . length === 0 && ( type === ";" || type === "comment" ) ) return ret ( "tag" , stream . current ( ) ) ;
else if ( ( state . stack [ state . stack . length - 1 ] === "{" || type === ";" ) && state . stack [ state . stack . length - 1 ] !== "@media{" ) return ret ( "variable" , stream . current ( ) ) ;
else if ( state . stack [ state . stack . length - 2 ] === "{" && state . stack [ state . stack . length - 1 ] === ";" ) return ret ( "variable" , stream . current ( ) ) ;
2013-03-28 15:29:40 -04:00
return ret ( "tag" , "tag" ) ;
2014-02-13 15:19:17 -04:00
} else if ( type == "compare" || type == "a" || type == "(" ) {
2013-03-28 15:29:40 -04:00
return ret ( "string" , "string" ) ;
2014-02-13 15:19:17 -04:00
} else if ( type == "|" || stream . current ( ) == "-" || type == "[" ) {
if ( type == "|" && stream . match ( /^[\]=~]/ , false ) ) return ret ( "number" , stream . current ( ) ) ;
else if ( type == "|" ) return ret ( "tag" , "tag" ) ;
else if ( type == "[" ) {
stream . eatWhile ( /\w\-/ ) ;
return ret ( "number" , stream . current ( ) ) ;
}
2013-03-28 15:29:40 -04:00
return ret ( null , ch ) ;
2014-02-13 15:19:17 -04:00
} else if ( ( stream . peek ( ) == ":" ) || ( stream . eatSpace ( ) && stream . peek ( ) == ":" ) ) {
2013-03-28 15:29:40 -04:00
stream . next ( ) ;
var t _v = stream . peek ( ) == ":" ? true : false ;
if ( ! t _v ) {
2014-02-13 15:19:17 -04:00
var old _pos = stream . pos ;
var sc = stream . current ( ) . length ;
stream . eatWhile ( /[a-z\\\-]/ ) ;
var new _pos = stream . pos ;
if ( stream . current ( ) . substring ( sc - 1 ) . match ( selectors ) != null ) {
stream . backUp ( new _pos - ( old _pos - 1 ) ) ;
return ret ( "tag" , "tag" ) ;
} else stream . backUp ( new _pos - ( old _pos - 1 ) ) ;
} else {
stream . backUp ( 1 ) ;
}
if ( t _v ) return ret ( "tag" , "tag" ) ; else return ret ( "variable" , "variable" ) ;
} else if ( state . stack [ state . stack . length - 1 ] === "font-family" || state . stack [ state . stack . length - 1 ] === "background-position" || state . stack [ state . stack . length - 1 ] === "border-color" ) {
return ret ( null , null ) ;
} else {
if ( state . stack [ state . stack . length - 1 ] === null && type === ":" ) return ret ( null , stream . current ( ) ) ;
//else if((type === ")" && state.stack[state.stack.length-1] === "rule") || (state.stack[state.stack.length-2] === "{" && state.stack[state.stack.length-1] === "rule" && type === "variable"))return ret(null, stream.current());
else if ( /\^|\$/ . test ( stream . current ( ) ) && stream . match ( /^[~=]/ , false ) ) return ret ( "string" , "string" ) ; //att^=val
else if ( type === "unit" && state . stack [ state . stack . length - 1 ] === "rule" ) return ret ( null , "unit" ) ;
else if ( type === "unit" && state . stack [ state . stack . length - 1 ] === ";" ) return ret ( null , "unit" ) ;
else if ( type === ")" && state . stack [ state . stack . length - 1 ] === "rule" ) return ret ( null , "unit" ) ;
else if ( type && type . match ( "@" ) !== null && state . stack [ state . stack . length - 1 ] === "rule" ) return ret ( null , "unit" ) ;
//else if(type === "unit" && state.stack[state.stack.length-1] === "rule")return ret(null, stream.current());
else if ( ( type === ";" || type === "}" || type === "," ) && state . stack [ state . stack . length - 1 ] === ";" ) return ret ( "tag" , stream . current ( ) ) ;
else if ( ( type === ";" && stream . peek ( ) !== undefined && ! stream . match ( /^[{\.]/ , false ) ) ||
( type === ";" && stream . eatSpace ( ) && ! stream . match ( /^[{\.]/ ) ) ) return ret ( "variable" , stream . current ( ) ) ;
else if ( ( type === "@media" && state . stack [ state . stack . length - 1 ] === "@media" ) || type === "@namespace" ) return ret ( "tag" , stream . current ( ) ) ;
else if ( type === "{" && state . stack [ state . stack . length - 1 ] === ";" && stream . peek ( ) === "{" ) return ret ( "tag" , "tag" ) ;
else if ( ( type === "{" || type === ":" ) && state . stack [ state . stack . length - 1 ] === ";" ) return ret ( null , stream . current ( ) ) ;
else if ( ( state . stack [ state . stack . length - 1 ] === "{" && stream . eatSpace ( ) && ! stream . match ( /^[\.#]/ ) ) || type === "select-op" || ( state . stack [ state . stack . length - 1 ] === "rule" && type === "," ) ) return ret ( "tag" , "tag" ) ;
else if ( type === "variable" && state . stack [ state . stack . length - 1 ] === "rule" ) return ret ( "tag" , "tag" ) ;
else if ( ( stream . eatSpace ( ) && stream . peek ( ) === "{" ) || stream . eol ( ) || stream . peek ( ) === "{" ) return ret ( "tag" , "tag" ) ;
//this one messes up indentation
//else if((type === "}" && stream.peek() !== ":") || (type === "}" && stream.eatSpace() && stream.peek() !== ":"))return(type, "tag");
else if ( type === ")" && ( stream . current ( ) == "and" || stream . current ( ) == "and " ) ) return ret ( "variable" , "variable" ) ;
else if ( type === ")" && ( stream . current ( ) == "when" || stream . current ( ) == "when " ) ) return ret ( "variable" , "variable" ) ;
else if ( type === ")" || type === "comment" || type === "{" ) return ret ( "tag" , "tag" ) ;
else if ( stream . sol ( ) ) return ret ( "tag" , "tag" ) ;
else if ( ( stream . eatSpace ( ) && stream . peek ( ) === "#" ) || stream . peek ( ) === "#" ) return ret ( "tag" , "tag" ) ;
else if ( state . stack . length === 0 ) return ret ( "tag" , "tag" ) ;
else if ( type === ";" && stream . peek ( ) !== undefined && stream . match ( /^[\.|#]/g ) ) return ret ( "tag" , "tag" ) ;
else if ( type === ":" ) { stream . eatSpace ( ) ; return ret ( null , stream . current ( ) ) ; }
else if ( stream . current ( ) === "and " || stream . current ( ) === "and" ) return ret ( "variable" , stream . current ( ) ) ;
else if ( type === ";" && state . stack [ state . stack . length - 1 ] === "{" ) return ret ( "variable" , stream . current ( ) ) ;
else if ( state . stack [ state . stack . length - 1 ] === "rule" ) return ret ( null , stream . current ( ) ) ;
return ret ( "tag" , stream . current ( ) ) ;
2013-03-28 15:29:40 -04:00
}
2014-02-13 15:19:17 -04:00
}
2013-03-28 15:29:40 -04:00
}
2014-02-13 15:19:17 -04:00
2013-03-28 15:29:40 -04:00
function tokenSComment ( stream , state ) { // SComment = Slash comment
stream . skipToEnd ( ) ;
state . tokenize = tokenBase ;
return ret ( "comment" , "comment" ) ;
}
2014-02-13 15:19:17 -04:00
2013-03-28 15:29:40 -04:00
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" ) ;
}
2014-02-13 15:19:17 -04:00
2013-03-28 15:29:40 -04:00
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" ) ;
}
2014-02-13 15:19:17 -04:00
2013-03-28 15:29:40 -04:00
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" ) ;
} ;
}
2014-02-13 15:19:17 -04:00
2013-03-28 15:29:40 -04:00
return {
2014-02-13 15:19:17 -04:00
startState : function ( base ) {
2013-03-28 15:29:40 -04:00
return { tokenize : tokenBase ,
baseIndent : base || 0 ,
stack : [ ] } ;
} ,
2014-02-13 15:19:17 -04:00
2013-03-28 15:29:40 -04:00
token : function ( stream , state ) {
if ( stream . eatSpace ( ) ) return null ;
var style = state . tokenize ( stream , state ) ;
2014-02-13 15:19:17 -04:00
2013-03-28 15:29:40 -04:00
var context = state . stack [ state . stack . length - 1 ] ;
if ( type == "hash" && context == "rule" ) style = "atom" ;
else if ( style == "variable" ) {
if ( context == "rule" ) style = null ; //"tag"
else if ( ! context || context == "@media{" ) {
style = stream . current ( ) == "when" ? "variable" :
/[\s,|\s\)|\s]/ . test ( stream . peek ( ) ) ? "tag" : type ;
}
}
2014-02-13 15:19:17 -04:00
2013-03-28 15:29:40 -04:00
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" ) ;
2014-02-13 15:19:17 -04:00
else if ( stream . current ( ) === "font-family" ) state . stack [ state . stack . length - 1 ] = "font-family" ;
else if ( stream . current ( ) === "background-position" ) state . stack [ state . stack . length - 1 ] = "background-position" ;
else if ( stream . current ( ) === "border-color" ) state . stack [ state . stack . length - 1 ] = "border-color" ;
else if ( context == "{" && type != "comment" && type !== "tag" ) state . stack . push ( "rule" ) ;
else if ( stream . peek ( ) === ":" && stream . current ( ) . match ( /@|#/ ) === null ) style = type ;
if ( type === ";" && ( state . stack [ state . stack . length - 1 ] == "font-family" || state . stack [ state . stack . length - 1 ] == "background-position" || state . stack [ state . stack . length - 1 ] == "border-color" ) ) state . stack [ state . stack . length - 1 ] = stream . current ( ) ;
else if ( type === "tag" && stream . peek ( ) === ")" && stream . current ( ) . match ( /\:/ ) === null ) { type = null ; style = null ; }
// ????
else if ( ( type === "variable" && stream . peek ( ) === ")" ) || ( type === "variable" && stream . eatSpace ( ) && stream . peek ( ) === ")" ) ) return ret ( null , stream . current ( ) ) ;
2013-03-28 15:29:40 -04:00
return style ;
} ,
2014-02-13 15:19:17 -04:00
2013-03-28 15:29:40 -04:00
indent : function ( state , textAfter ) {
var n = state . stack . length ;
if ( /^\}/ . test ( textAfter ) )
2014-02-13 15:19:17 -04:00
n -= state . stack [ state . stack . length - 1 ] === "rule" ? 2 : 1 ;
else if ( state . stack [ state . stack . length - 2 ] === "{" )
n -= state . stack [ state . stack . length - 1 ] === "rule" ? 1 : 0 ;
2013-03-28 15:29:40 -04:00
return state . baseIndent + n * indentUnit ;
} ,
2014-02-13 15:19:17 -04:00
electricChars : "}" ,
blockCommentStart : "/*" ,
blockCommentEnd : "*/" ,
lineComment : "//"
2013-03-28 15:29:40 -04:00
} ;
} ) ;
CodeMirror . defineMIME ( "text/x-less" , "less" ) ;
if ( ! CodeMirror . mimeModes . hasOwnProperty ( "text/css" ) )
2014-02-13 15:19:17 -04:00
CodeMirror . defineMIME ( "text/css" , "less" ) ;