X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=third-party%2Fcodemirror-3.15%2Fmode%2Fless%2Fless.js;fp=third-party%2Fcodemirror-3.15%2Fmode%2Fless%2Fless.js;h=09f510e03296635b626d14bca007c7183b02e8c5;hb=75d3bceb8e1d168e83982f910a916aee3bab7981;hp=0000000000000000000000000000000000000000;hpb=302dd5bda1297ed6579ca26da35ee67f8d35d934;p=unfold.git diff --git a/third-party/codemirror-3.15/mode/less/less.js b/third-party/codemirror-3.15/mode/less/less.js new file mode 100644 index 00000000..09f510e0 --- /dev/null +++ b/third-party/codemirror-3.15/mode/less/less.js @@ -0,0 +1,258 @@ +/* + LESS mode - http://www.lesscss.org/ + Ported to CodeMirror by Peter Kroon + Report bugs/issues here: https://github.com/marijnh/CodeMirror/issues GitHub: @peterkroon +*/ + +CodeMirror.defineMode("less", function(config) { + var indentUnit = config.indentUnit, type; + function ret(style, tp) {type = tp; return style;} + + 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$)/; + + 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 == "|" && stream.eat("=")) return ret(null, "compare"); + else if (ch == "\"" || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + else if (ch == "/") { // e.g.: .png will not be parsed as a class + if(stream.eat("/")){ + state.tokenize = tokenSComment; + return tokenSComment(stream, state); + }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 + } + } + 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)) { + if(stream.peek() == "=" || type == "a")return ret("string", "string"); + return ret(null, "select-op"); + } + else if (/[;{}:\[\]()~\|]/.test(ch)) { + if(ch == ":"){ + stream.eatWhile(/[a-z\\\-]/); + if( selectors.test(stream.current()) ){ + return ret("tag", "tag"); + }else if(stream.peek() == ":"){//::-webkit-search-decoration + 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); + }else{ + return ret(null, ch); + } + }else if(ch == "~"){ + if(type == "r")return ret("string", "string"); + }else{ + return ret(null, ch); + } + } + else if (ch == ".") { + if(type == "(" || type == "string")return ret("string", "string"); // allow url(../image.png) + stream.eatWhile(/[\a-zA-Z0-9\-_]/); + if(stream.peek() == " ")stream.eatSpace(); + if(stream.peek() == ")")return ret("number", "unit");//rgba(0,0,0,.25); + return ret("tag", "tag"); + } + else if (ch == "#") { + //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[;,] + if( /[\/<>.(){!$%^&*_\-\\?=+\|#'~`]/.test(stream.peek()) )return ret("atom", "tag"); + //#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"); + }else{//when not a valid hexvalue in the current stream e.g. #footer + stream.eatWhile(/[\w\\\-]/); + return ret("atom", "tag"); + } + }else{//when not a valid hexvalue length + stream.eatWhile(/[\w\\\-]/); + return ret("atom", "tag"); + } + } + else if (ch == "&") { + stream.eatWhile(/[\w\-]/); + return ret(null, ch); + } + else { + stream.eatWhile(/[\w\\\-_%.{]/); + if(type == "string"){ + return ret("string", "string"); + }else if(stream.current().match(/(^http$|^https$)/) != null){ + stream.eatWhile(/[\w\\\-_%.{:\/]/); + return ret("string", "string"); + }else if(stream.peek() == "<" || stream.peek() == ">"){ + return ret("tag", "tag"); + }else if( /\(/.test(stream.peek()) ){ + return ret(null, ch); + }else if (stream.peek() == "/" && state.stack[state.stack.length-1] != undefined){ // url(dir/center/image.png) + return ret("string", "string"); + }else if( stream.current().match(/\-\d|\-.\d/) ){ // match e.g.: -5px -0.4 etc... only colorize the minus sign + //commment out these 2 comment if you want the minus sign to be parsed as null -500px + //stream.backUp(stream.current().length-1); + //return ret(null, ch); //console.log( stream.current() ); + return ret("number", "unit"); + }else if( /\/|[\s\)]/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == "/")) && stream.current().indexOf(".") !== -1){ + 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 + }else if( stream.eol() || stream.peek() == "[" || stream.peek() == "#" || type == "tag" ){ + if(stream.current().substring(stream.current().length-1,stream.current().length) == "{")stream.backUp(1); + return ret("tag", "tag"); + }else if(type == "compare" || type == "a" || type == "("){ + return ret("string", "string"); + }else if(type == "|" || stream.current() == "-" || type == "["){ + return ret(null, ch); + }else if(stream.peek() == ":") { + stream.next(); + var t_v = stream.peek() == ":" ? true : false; + if(!t_v){ + 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{ + return ret("variable", "variable"); + } + } + } + + function tokenSComment(stream, state) { // SComment = Slash comment + stream.skipToEnd(); + state.tokenize = tokenBase; + return ret("comment", "comment"); + } + + 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 = null; //"tag" + else if (!context || context == "@media{") { + style = stream.current() == "when" ? "variable" : + /[\s,|\s\)|\s]/.test(stream.peek()) ? "tag" : type; + } + } + + 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/x-less", "less"); +if (!CodeMirror.mimeModes.hasOwnProperty("text/css")) + CodeMirror.defineMIME("text/css", "less");