Project

General

Profile

Revision 229 trunk/scripts/codemirror/mode/less

View differences:

index.html
1

  
2 1
<!doctype html>
3 2
<html>
4 3
  <head>
......
6 5
    <link rel="stylesheet" href="../../lib/codemirror.css">
7 6
    <script src="../../lib/codemirror.js"></script>
8 7
    <script src="less.js"></script>
9
    <style>.CodeMirror {background: #f8f8f8; border: 1px solid #ddd;}</style>
8
    <style>.CodeMirror {background: #f8f8f8; border: 1px solid #ddd;} .CodeMirror-scroll {height: 400px}</style>
10 9
    <link rel="stylesheet" href="../../doc/docs.css">
10
    <link rel="stylesheet" href="../../theme/lesser-dark.css">
11 11
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
12 12
  </head>
13 13
  <body>
14 14
    <h1>CodeMirror: LESS mode</h1>
15
    <form><textarea id="code" name="code">
16
/* Some LESS code */
15
    <form><textarea id="code" name="code">/* Some LESS code */
17 16

  
17
button {
18
    width:  32px;
19
    height: 32px;
20
    border: 0;
21
    margin: 4px;
22
    cursor: pointer;
23
}
24
button.icon-plus { background: url(http://dahlström.net/tmp/sharp-icons/svg-icon-target.svg#plus) no-repeat; }
25
button.icon-chart { background: url(http://dahlström.net/tmp/sharp-icons/svg-icon-target.svg#chart) no-repeat; }
26

  
27
button:hover { background-color: #999; }
28
button:active { background-color: #666; }
29

  
30
@test_a: #eeeQQQ;//this is not a valid hex value and thus parsed as an element id
31
@test_b: #eeeFFF //this is a valid hex value but the declaration doesn't end with a semicolon and thus parsed as an element id
32

  
33
#eee aaa .box
34
{
35
  #test bbb {
36
    width: 500px;
37
    height: 250px;
38
    background-image: url(dir/output/sheep.png), url( betweengrassandsky.png );
39
    background-position: center bottom, left top;
40
    background-repeat: no-repeat;
41
  }
42
}
43

  
44
@base: #f938ab;
45

  
46
.box-shadow(@style, @c) when (iscolor(@c)) {
47
  box-shadow:         @style @c;
48
  -webkit-box-shadow: @style @c;
49
  -moz-box-shadow:    @style @c;
50
}
51
.box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) {
52
  .box-shadow(@style, rgba(0, 0, 0, @alpha));
53
}
54

  
18 55
@color: #4D926F;
19 56

  
20 57
#header {
......
160 197
body > footer {
161 198
  text-align: left;
162 199
  margin-left: 10px;
163
	font-style: italic;
200
  font-style: italic;
164 201
  font-size: 18px;
165 202
  color: #888;
166 203
}
......
569 606
}
570 607
</textarea></form>
571 608
    <script>
572
      var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
609
      var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
610
        theme: "lesser-dark",
611
        lineNumbers : true,
612
  		  matchBrackets : true
613
      });
573 614
    </script>
574 615

  
575
    <p><strong>MIME types defined:</strong> <code>text/less</code>.</p>
616
    <p><strong>MIME types defined:</strong> <code>text/x-less</code>, <code>text/css</code> (if not previously defined).</p>
576 617
  </body>
577 618
</html>
less.js
1
CodeMirror.defineMode("less", function(config) {
1
/*
2
LESS mode - http://www.lesscss.org/
3
Ported to CodeMirror by Peter Kroon
4
*/
5

  
6
CodeMirror.defineMode("css", function(config) {
2 7
  var indentUnit = config.indentUnit, type;
3 8
  function ret(style, tp) {type = tp; return style;}
4 9
  //html5 tags
5 10
  var tags = ["a","abbr","acronym","address","applet","area","article","aside","audio","b","base","basefont","bdi","bdo","big","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","command","datalist","dd","del","details","dfn","dir","div","dl","dt","em","embed","fieldset","figcaption","figure","font","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","keygen","kbd","label","legend","li","link","map","mark","menu","meta","meter","nav","noframes","noscript","object","ol","optgroup","option","output","p","param","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strike","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","tt","u","ul","var","video","wbr"];
6 11
  
7 12
  function inTagsArray(val){
8
    for(var i=0; i<tags.length; i++){
9
      if(val === tags[i]){
10
	return true;
11
      }
12
    }
13
	  for(var i=0; i<tags.length; i++){
14
		  if(val === tags[i]){
15
			  return true;
16
		  }
17
	  }
13 18
  }
14 19

  
15 20
  function tokenBase(stream, state) {
16 21
    var ch = stream.next();
17 22

  
18
    if (ch == "@") {stream.eatWhile(/[\w\-]/); return ret("meta", stream.current());}
23
	if (ch == "@") {stream.eatWhile(/[\w\-]/); return ret("meta", stream.current());}
19 24
    else if (ch == "/" && stream.eat("*")) {
20 25
      state.tokenize = tokenCComment;
21 26
      return tokenCComment(stream, state);
......
30 35
      state.tokenize = tokenString(ch);
31 36
      return state.tokenize(stream, state);
32 37
    }
33
    else if (ch == "/") { // lesscss e.g.: .png will not be parsed as a class
34
      if(stream.eat("/")){
35
	state.tokenize = tokenSComment
38
	else if (ch == "/") { // lesscss e.g.: .png will not be parsed as a class
39
	  if(stream.eat("/")){
40
		state.tokenize = tokenSComment
36 41
      	return tokenSComment(stream, state);
37
      }else{
38
	stream.eatWhile(/[\a-zA-Z0-9\-_.]/);
42
	  }else{
43
	    stream.eatWhile(/[\a-zA-Z0-9\-_.\s]/);
44
		if(/\/|\)|#/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == ")")))return ret("string", "string");//let url(/images/logo.png) without quotes return as string
39 45
        return ret("number", "unit");
40
      }
46
	  }
41 47
    }
42 48
    else if (ch == "!") {
43 49
      stream.match(/^\s*\w*/);
......
47 53
      stream.eatWhile(/[\w.%]/);
48 54
      return ret("number", "unit");
49 55
    }
50
    else if (/[,+>*\/]/.test(ch)) {//removed . dot character original was [,.+>*\/]
56
    else if (/[,+<>*\/]/.test(ch)) {//removed . dot character original was [,.+>*\/]
51 57
      return ret(null, "select-op");
52 58
    }
53 59
    else if (/[;{}:\[\]()]/.test(ch)) { //added () char for lesscss original was [;{}:\[\]]
54 60
      if(ch == ":"){
55
	stream.eatWhile(/[active|hover|link|visited]/);
56
	if( stream.current().match(/[active|hover|link|visited]/)){
57
	  return ret("tag", "tag");
58
	}else{
59
	  return ret(null, ch);	
60
	}
61
      }else{
62
  	return ret(null, ch);
63
      }
61
		stream.eatWhile(/[active|hover|link|visited]/);
62
		if( stream.current().match(/active|hover|link|visited/)){
63
		  return ret("tag", "tag");
64
		}else{
65
		  return ret(null, ch);	
66
		}
67
	  }else{
68
  	    return ret(null, ch);
69
	  }
64 70
    }
65
    else if (ch == ".") { // lesscss
66
      stream.eatWhile(/[\a-zA-Z0-9\-_]/);
71
	else if (ch == ".") { // lesscss
72
	  stream.eatWhile(/[\a-zA-Z0-9\-_]/);
67 73
      return ret("tag", "tag");
68 74
    }
69
    else if (ch == "#") { // lesscss
70
      stream.match(/([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/);
71
      if(stream.current().length >1){
72
	if(stream.current().match(/([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/) != null){
73
	  return ret("number", "unit");
74
	}else{
75
	else if (ch == "#") { // lesscss
76
	  //we don't eat white-space, we want the hex color and or id only
77
	  stream.eatWhile(/[A-Za-z0-9]/);
78
	  //check if there is a proper hex color length e.g. #eee || #eeeEEE
79
	  if(stream.current().length ===4 || stream.current().length ===7){
80
		  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
81
		  	//when not a valid hex value, parse as id
82
			if(stream.current().substring(1) != stream.current().match(/[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/,false))return ret("atom", "tag");
83
			//eat white-space
84
			stream.eatSpace();
85
			//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[;,]
86
			if( /[\/<>.(){!$%^&*_\-\\?=+\|#'~`]/.test(stream.peek()) )return ret("atom", "tag");
87
			//#time { color: #aaa }
88
			else if(stream.peek() == "}" )return ret("number", "unit");
89
			//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
90
			else if( /[a-zA-Z\\]/.test(stream.peek()) )return ret("atom", "tag");
91
			//when a hex value is on the end of a line, parse as id
92
			else if(stream.eol())return ret("atom", "tag");
93
			//default
94
			else return ret("number", "unit");
95
		  }else{//when not a valid hexvalue in the current stream e.g. #footer
96
			stream.eatWhile(/[\w\\\-]/);
97
			return ret("atom", "tag"); 
98
		  }
99
	  }else{
100
		stream.eatWhile(/[\w\\\-]/);		
101
		return ret("atom", "tag");
102
	  }
103
    }
104
	else if (ch == "&") {
75 105
	  stream.eatWhile(/[\w\-]/);
76
	  return ret("atom", "tag"); 
106
	  return ret(null, ch);
77 107
	}
78
      }else{
79
	stream.eatWhile(/[\w\-]/);
80
	return ret("atom", "tag");
81
      }
82
    }
83
    else if (ch == "&") {
84
      stream.eatWhile(/[\w\-]/);
85
      return ret(null, ch);
86
    }
87 108
    else {
88
      stream.eatWhile(/[\w\\\-_.%{]/);
89
      if( stream.eat("(") ){ // lesscss
90
	return ret(null, ch);
91
      }else if( stream.current().match(/\-\d|\-.\d/) ){ // lesscss match e.g.: -5px -0.4 etc...
92
	return ret("number", "unit");
93
      }else if( inTagsArray(stream.current()) ){ // lesscss match html tags
94
	return ret("tag", "tag");
95
      }else{
109
      stream.eatWhile(/[\w\\\-_%.{]/);
110
	  if(stream.current().match(/http|https/) != null){
111
		stream.eatWhile(/[\w\\\-_%.{:\/]/);
112
		return ret("string", "string");
113
	  }else if(stream.peek() == "<" || stream.peek() == ">"){
114
		return ret("tag", "tag");
115
	  }else if( stream.peek().match(/\(/) != null ){// lessc
116
		return ret(null, ch);
117
	  }else if (stream.peek() == "/" && state.stack[state.stack.length-1] != undefined){ // url(dir/center/image.png)
118
	  	return ret("string", "string");
119
	  }else if( stream.current().match(/\-\d|\-.\d/) ){ // lesscss match e.g.: -5px -0.4 etc... only colorize the minus sign
120
		//stream.backUp(stream.current().length-1); //commment out these 2 comment if you want the minus sign to be parsed as null -500px
121
	  	//return ret(null, ch);
122
		return ret("number", "unit");
123
	  }else if( inTagsArray(stream.current()) ){ // lesscss match html tags
124
	  	return ret("tag", "tag");
125
	  }else if( /\/|[\s\)]/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == "/")) && stream.current().indexOf(".") !== -1){
126
		if(stream.current().substring(stream.current().length-1,stream.current().length) == "{"){
127
			stream.backUp(1);
128
			return ret("tag", "tag");
129
		}//end if
130
		if( (stream.eatSpace() && stream.peek().match(/[{<>.a-zA-Z]/) != null)  || stream.eol() )return ret("tag", "tag");//e.g. button.icon-plus
131
		return ret("string", "string");//let url(/images/logo.png) without quotes return as string
132
	  }else if( stream.eol() ){
133
		  if(stream.current().substring(stream.current().length-1,stream.current().length) == "{")stream.backUp(1);
134
		  return ret("tag", "tag");
135
	  }else{
96 136
      	return ret("variable", "variable");
97
      }
137
	  }
98 138
    }
99 139
    
100 140
  }
101 141

  
102 142
  function tokenSComment(stream, state) {// SComment = Slash comment
103 143
    stream.skipToEnd();
104
    state.tokenize = tokenBase;
144
	state.tokenize = tokenBase;
105 145
    return ret("comment", "comment");
106 146
  }
107
  
147
    
108 148
  function tokenCComment(stream, state) {
109 149
    var maybeEnd = false, ch;
110 150
    while ((ch = stream.next()) != null) {
......
143 183
  }
144 184

  
145 185
  return {
146
    startState: function(base) {
186
    startState: function(base) { 
147 187
      return {tokenize: tokenBase,
148 188
              baseIndent: base || 0,
149 189
              stack: []};
......
157 197
      if (type == "hash" && context == "rule") style = "atom";
158 198
      else if (style == "variable") {
159 199
        if (context == "rule") style = null; //"tag"
160
        else if (!context || context == "@media{") style = "tag";
200
        else if (!context || context == "@media{"){ 
201
			style = stream.current() 	== "when" 	? "variable" 	: 
202
			stream.string.match(/#/g) 	!= undefined 	? null 		: 
203
			/[\s,|\s\)]/.test(stream.peek()) 		? "tag" 	: null;
204
		}
161 205
      }
162 206

  
163 207
      if (context == "rule" && /^[\{\};]$/.test(type))
......
183 227
  };
184 228
});
185 229

  
186
CodeMirror.defineMIME("text/less", "less");
230
CodeMirror.defineMIME("text/x-less", "less");
231
if (!CodeMirror.mimeModes.hasOwnProperty("text/css"))
232
  CodeMirror.defineMIME("text/css", "less");

Also available in: Unified diff