PluginProbe ʕ •ᴥ•ʔ
SiteOrigin CSS / 1.0.2
SiteOrigin CSS v1.0.2
1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.10 1.5.11 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 trunk 1.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.2.0
so-css / lib / codemirror / mode / sass / sass.js
so-css / lib / codemirror / mode / sass Last commit date
index.html 11 years ago sass.js 11 years ago sass.min.js 11 years ago
sass.js
415 lines
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
3
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
6 mod(require("../../lib/codemirror"));
7 else if (typeof define == "function" && define.amd) // AMD
8 define(["../../lib/codemirror"], mod);
9 else // Plain browser env
10 mod(CodeMirror);
11 })(function(CodeMirror) {
12 "use strict";
13
14 CodeMirror.defineMode("sass", function(config) {
15 function tokenRegexp(words) {
16 return new RegExp("^" + words.join("|"));
17 }
18
19 var keywords = ["true", "false", "null", "auto"];
20 var keywordsRegexp = new RegExp("^" + keywords.join("|"));
21
22 var operators = ["\\(", "\\)", "=", ">", "<", "==", ">=", "<=", "\\+", "-",
23 "\\!=", "/", "\\*", "%", "and", "or", "not", ";","\\{","\\}",":"];
24 var opRegexp = tokenRegexp(operators);
25
26 var pseudoElementsRegexp = /^::?[a-zA-Z_][\w\-]*/;
27
28 function urlTokens(stream, state) {
29 var ch = stream.peek();
30
31 if (ch === ")") {
32 stream.next();
33 state.tokenizer = tokenBase;
34 return "operator";
35 } else if (ch === "(") {
36 stream.next();
37 stream.eatSpace();
38
39 return "operator";
40 } else if (ch === "'" || ch === '"') {
41 state.tokenizer = buildStringTokenizer(stream.next());
42 return "string";
43 } else {
44 state.tokenizer = buildStringTokenizer(")", false);
45 return "string";
46 }
47 }
48 function comment(indentation, multiLine) {
49 return function(stream, state) {
50 if (stream.sol() && stream.indentation() <= indentation) {
51 state.tokenizer = tokenBase;
52 return tokenBase(stream, state);
53 }
54
55 if (multiLine && stream.skipTo("*/")) {
56 stream.next();
57 stream.next();
58 state.tokenizer = tokenBase;
59 } else {
60 stream.skipToEnd();
61 }
62
63 return "comment";
64 };
65 }
66
67 function buildStringTokenizer(quote, greedy) {
68 if (greedy == null) { greedy = true; }
69
70 function stringTokenizer(stream, state) {
71 var nextChar = stream.next();
72 var peekChar = stream.peek();
73 var previousChar = stream.string.charAt(stream.pos-2);
74
75 var endingString = ((nextChar !== "\\" && peekChar === quote) || (nextChar === quote && previousChar !== "\\"));
76
77 if (endingString) {
78 if (nextChar !== quote && greedy) { stream.next(); }
79 state.tokenizer = tokenBase;
80 return "string";
81 } else if (nextChar === "#" && peekChar === "{") {
82 state.tokenizer = buildInterpolationTokenizer(stringTokenizer);
83 stream.next();
84 return "operator";
85 } else {
86 return "string";
87 }
88 }
89
90 return stringTokenizer;
91 }
92
93 function buildInterpolationTokenizer(currentTokenizer) {
94 return function(stream, state) {
95 if (stream.peek() === "}") {
96 stream.next();
97 state.tokenizer = currentTokenizer;
98 return "operator";
99 } else {
100 return tokenBase(stream, state);
101 }
102 };
103 }
104
105 function indent(state) {
106 if (state.indentCount == 0) {
107 state.indentCount++;
108 var lastScopeOffset = state.scopes[0].offset;
109 var currentOffset = lastScopeOffset + config.indentUnit;
110 state.scopes.unshift({ offset:currentOffset });
111 }
112 }
113
114 function dedent(state) {
115 if (state.scopes.length == 1) return;
116
117 state.scopes.shift();
118 }
119
120 function tokenBase(stream, state) {
121 var ch = stream.peek();
122
123 // Comment
124 if (stream.match("/*")) {
125 state.tokenizer = comment(stream.indentation(), true);
126 return state.tokenizer(stream, state);
127 }
128 if (stream.match("//")) {
129 state.tokenizer = comment(stream.indentation(), false);
130 return state.tokenizer(stream, state);
131 }
132
133 // Interpolation
134 if (stream.match("#{")) {
135 state.tokenizer = buildInterpolationTokenizer(tokenBase);
136 return "operator";
137 }
138
139 // Strings
140 if (ch === '"' || ch === "'") {
141 stream.next();
142 state.tokenizer = buildStringTokenizer(ch);
143 return "string";
144 }
145
146 if(!state.cursorHalf){// state.cursorHalf === 0
147 // first half i.e. before : for key-value pairs
148 // including selectors
149
150 if (ch === ".") {
151 stream.next();
152 if (stream.match(/^[\w-]+/)) {
153 indent(state);
154 return "atom";
155 } else if (stream.peek() === "#") {
156 indent(state);
157 return "atom";
158 }
159 }
160
161 if (ch === "#") {
162 stream.next();
163 // ID selectors
164 if (stream.match(/^[\w-]+/)) {
165 indent(state);
166 return "atom";
167 }
168 if (stream.peek() === "#") {
169 indent(state);
170 return "atom";
171 }
172 }
173
174 // Variables
175 if (ch === "$") {
176 stream.next();
177 stream.eatWhile(/[\w-]/);
178 return "variable-2";
179 }
180
181 // Numbers
182 if (stream.match(/^-?[0-9\.]+/))
183 return "number";
184
185 // Units
186 if (stream.match(/^(px|em|in)\b/))
187 return "unit";
188
189 if (stream.match(keywordsRegexp))
190 return "keyword";
191
192 if (stream.match(/^url/) && stream.peek() === "(") {
193 state.tokenizer = urlTokens;
194 return "atom";
195 }
196
197 if (ch === "=") {
198 // Match shortcut mixin definition
199 if (stream.match(/^=[\w-]+/)) {
200 indent(state);
201 return "meta";
202 }
203 }
204
205 if (ch === "+") {
206 // Match shortcut mixin definition
207 if (stream.match(/^\+[\w-]+/)){
208 return "variable-3";
209 }
210 }
211
212 if(ch === "@"){
213 if(stream.match(/@extend/)){
214 if(!stream.match(/\s*[\w]/))
215 dedent(state);
216 }
217 }
218
219
220 // Indent Directives
221 if (stream.match(/^@(else if|if|media|else|for|each|while|mixin|function)/)) {
222 indent(state);
223 return "meta";
224 }
225
226 // Other Directives
227 if (ch === "@") {
228 stream.next();
229 stream.eatWhile(/[\w-]/);
230 return "meta";
231 }
232
233 if (stream.eatWhile(/[\w-]/)){
234 if(stream.match(/ *: *[\w-\+\$#!\("']/,false)){
235 return "property";
236 }
237 else if(stream.match(/ *:/,false)){
238 indent(state);
239 state.cursorHalf = 1;
240 return "atom";
241 }
242 else if(stream.match(/ *,/,false)){
243 return "atom";
244 }
245 else{
246 indent(state);
247 return "atom";
248 }
249 }
250
251 if(ch === ":"){
252 if (stream.match(pseudoElementsRegexp)){ // could be a pseudo-element
253 return "keyword";
254 }
255 stream.next();
256 state.cursorHalf=1;
257 return "operator";
258 }
259
260 } // cursorHalf===0 ends here
261 else{
262
263 if (ch === "#") {
264 stream.next();
265 // Hex numbers
266 if (stream.match(/[0-9a-fA-F]{6}|[0-9a-fA-F]{3}/)){
267 if(!stream.peek()){
268 state.cursorHalf = 0;
269 }
270 return "number";
271 }
272 }
273
274 // Numbers
275 if (stream.match(/^-?[0-9\.]+/)){
276 if(!stream.peek()){
277 state.cursorHalf = 0;
278 }
279 return "number";
280 }
281
282 // Units
283 if (stream.match(/^(px|em|in)\b/)){
284 if(!stream.peek()){
285 state.cursorHalf = 0;
286 }
287 return "unit";
288 }
289
290 if (stream.match(keywordsRegexp)){
291 if(!stream.peek()){
292 state.cursorHalf = 0;
293 }
294 return "keyword";
295 }
296
297 if (stream.match(/^url/) && stream.peek() === "(") {
298 state.tokenizer = urlTokens;
299 if(!stream.peek()){
300 state.cursorHalf = 0;
301 }
302 return "atom";
303 }
304
305 // Variables
306 if (ch === "$") {
307 stream.next();
308 stream.eatWhile(/[\w-]/);
309 if(!stream.peek()){
310 state.cursorHalf = 0;
311 }
312 return "variable-3";
313 }
314
315 // bang character for !important, !default, etc.
316 if (ch === "!") {
317 stream.next();
318 if(!stream.peek()){
319 state.cursorHalf = 0;
320 }
321 return stream.match(/^[\w]+/) ? "keyword": "operator";
322 }
323
324 if (stream.match(opRegexp)){
325 if(!stream.peek()){
326 state.cursorHalf = 0;
327 }
328 return "operator";
329 }
330
331 // attributes
332 if (stream.eatWhile(/[\w-]/)) {
333 if(!stream.peek()){
334 state.cursorHalf = 0;
335 }
336 return "attribute";
337 }
338
339 //stream.eatSpace();
340 if(!stream.peek()){
341 state.cursorHalf = 0;
342 return null;
343 }
344
345 } // else ends here
346
347 if (stream.match(opRegexp))
348 return "operator";
349
350 // If we haven't returned by now, we move 1 character
351 // and return an error
352 stream.next();
353 return null;
354 }
355
356 function tokenLexer(stream, state) {
357 if (stream.sol()) state.indentCount = 0;
358 var style = state.tokenizer(stream, state);
359 var current = stream.current();
360
361 if (current === "@return" || current === "}"){
362 dedent(state);
363 }
364
365 if (style !== null) {
366 var startOfToken = stream.pos - current.length;
367
368 var withCurrentIndent = startOfToken + (config.indentUnit * state.indentCount);
369
370 var newScopes = [];
371
372 for (var i = 0; i < state.scopes.length; i++) {
373 var scope = state.scopes[i];
374
375 if (scope.offset <= withCurrentIndent)
376 newScopes.push(scope);
377 }
378
379 state.scopes = newScopes;
380 }
381
382
383 return style;
384 }
385
386 return {
387 startState: function() {
388 return {
389 tokenizer: tokenBase,
390 scopes: [{offset: 0, type: "sass"}],
391 indentCount: 0,
392 cursorHalf: 0, // cursor half tells us if cursor lies after (1)
393 // or before (0) colon (well... more or less)
394 definedVars: [],
395 definedMixins: []
396 };
397 },
398 token: function(stream, state) {
399 var style = tokenLexer(stream, state);
400
401 state.lastToken = { style: style, content: stream.current() };
402
403 return style;
404 },
405
406 indent: function(state) {
407 return state.scopes[0].offset;
408 }
409 };
410 });
411
412 CodeMirror.defineMIME("text/x-sass", "sass");
413
414 });
415