##// END OF EJS Templates
Move create pull request button in pull requests view into the top...
Move create pull request button in pull requests view into the top menu, and hide it when you're not logged in

File last commit:

r4026:a60a0e90 default
r4081:089fb21d default
Show More
sass.js
330 lines | 7.3 KiB | application/javascript | JavascriptLexer
CodeMirror.defineMode("sass", function(config) {
var tokenRegexp = function(words){
return new RegExp("^" + words.join("|"));
};
var keywords = ["true", "false", "null", "auto"];
var keywordsRegexp = new RegExp("^" + keywords.join("|"));
var operators = ["\\(", "\\)", "=", ">", "<", "==", ">=", "<=", "\\+", "-", "\\!=", "/", "\\*", "%", "and", "or", "not"];
var opRegexp = tokenRegexp(operators);
var pseudoElementsRegexp = /^::?[\w\-]+/;
var urlTokens = function(stream, state){
var ch = stream.peek();
if (ch === ")"){
stream.next();
state.tokenizer = tokenBase;
return "operator";
}else if (ch === "("){
stream.next();
stream.eatSpace();
return "operator";
}else if (ch === "'" || ch === '"'){
state.tokenizer = buildStringTokenizer(stream.next());
return "string";
}else{
state.tokenizer = buildStringTokenizer(")", false);
return "string";
}
};
var multilineComment = function(stream, state) {
if (stream.skipTo("*/")){
stream.next();
stream.next();
state.tokenizer = tokenBase;
}else {
stream.next();
}
return "comment";
};
var buildStringTokenizer = function(quote, greedy){
if(greedy == null){ greedy = true; }
function stringTokenizer(stream, state){
var nextChar = stream.next();
var peekChar = stream.peek();
var previousChar = stream.string.charAt(stream.pos-2);
var endingString = ((nextChar !== "\\" && peekChar === quote) || (nextChar === quote && previousChar !== "\\"));
/*
console.log("previousChar: " + previousChar);
console.log("nextChar: " + nextChar);
console.log("peekChar: " + peekChar);
console.log("ending: " + endingString);
*/
if (endingString){
if (nextChar !== quote && greedy) { stream.next(); }
state.tokenizer = tokenBase;
return "string";
}else if (nextChar === "#" && peekChar === "{"){
state.tokenizer = buildInterpolationTokenizer(stringTokenizer);
stream.next();
return "operator";
}else {
return "string";
}
}
return stringTokenizer;
};
var buildInterpolationTokenizer = function(currentTokenizer){
return function(stream, state){
if (stream.peek() === "}"){
stream.next();
state.tokenizer = currentTokenizer;
return "operator";
}else{
return tokenBase(stream, state);
}
};
};
var indent = function(state){
if (state.indentCount == 0){
state.indentCount++;
var lastScopeOffset = state.scopes[0].offset;
var currentOffset = lastScopeOffset + config.indentUnit;
state.scopes.unshift({ offset:currentOffset });
}
};
var dedent = function(state){
if (state.scopes.length == 1) { return; }
state.scopes.shift();
};
var tokenBase = function(stream, state) {
var ch = stream.peek();
// Single line Comment
if (stream.match('//')) {
stream.skipToEnd();
return "comment";
}
// Multiline Comment
if (stream.match('/*')){
state.tokenizer = multilineComment;
return state.tokenizer(stream, state);
}
// Interpolation
if (stream.match('#{')){
state.tokenizer = buildInterpolationTokenizer(tokenBase);
return "operator";
}
if (ch === "."){
stream.next();
// Match class selectors
if (stream.match(/^[\w-]+/)){
indent(state);
return "atom";
}else if (stream.peek() === "#"){
indent(state);
return "atom";
}else{
return "operator";
}
}
if (ch === "#"){
stream.next();
// Hex numbers
if (stream.match(/[0-9a-fA-F]{6}|[0-9a-fA-F]{3}/)){
return "number";
}
// ID selectors
if (stream.match(/^[\w-]+/)){
indent(state);
return "atom";
}
if (stream.peek() === "#"){
indent(state);
return "atom";
}
}
// Numbers
if (stream.match(/^-?[0-9\.]+/)){
return "number";
}
// Units
if (stream.match(/^(px|em|in)\b/)){
return "unit";
}
if (stream.match(keywordsRegexp)){
return "keyword";
}
if (stream.match(/^url/) && stream.peek() === "("){
state.tokenizer = urlTokens;
return "atom";
}
// Variables
if (ch === "$"){
stream.next();
stream.eatWhile(/[\w-]/);
if (stream.peek() === ":"){
stream.next();
return "variable-2";
}else{
return "variable-3";
}
}
if (ch === "!"){
stream.next();
if (stream.match(/^[\w]+/)){
return "keyword";
}
return "operator";
}
if (ch === "="){
stream.next();
// Match shortcut mixin definition
if (stream.match(/^[\w-]+/)){
indent(state);
return "meta";
}else {
return "operator";
}
}
if (ch === "+"){
stream.next();
// Match shortcut mixin definition
if (stream.match(/^[\w-]+/)){
return "variable-3";
}else {
return "operator";
}
}
// Indent Directives
if (stream.match(/^@(else if|if|media|else|for|each|while|mixin|function)/)){
indent(state);
return "meta";
}
// Other Directives
if (ch === "@"){
stream.next();
stream.eatWhile(/[\w-]/);
return "meta";
}
// Strings
if (ch === '"' || ch === "'"){
stream.next();
state.tokenizer = buildStringTokenizer(ch);
return "string";
}
// Pseudo element selectors
if (ch == ':' && stream.match(pseudoElementsRegexp)){
return "keyword";
}
// atoms
if (stream.eatWhile(/[\w-&]/)){
// matches a property definition
if (stream.peek() === ":" && !stream.match(pseudoElementsRegexp, false))
return "property";
else
return "atom";
}
if (stream.match(opRegexp)){
return "operator";
}
// If we haven't returned by now, we move 1 character
// and return an error
stream.next();
return null;
};
var tokenLexer = function(stream, state) {
if (stream.sol()){
state.indentCount = 0;
}
var style = state.tokenizer(stream, state);
var current = stream.current();
if (current === "@return"){
dedent(state);
}
if (style === "atom"){
indent(state);
}
if (style !== null){
var startOfToken = stream.pos - current.length;
var withCurrentIndent = startOfToken + (config.indentUnit * state.indentCount);
var newScopes = [];
for (var i = 0; i < state.scopes.length; i++){
var scope = state.scopes[i];
if (scope.offset <= withCurrentIndent){
newScopes.push(scope);
}
}
state.scopes = newScopes;
}
return style;
};
return {
startState: function() {
return {
tokenizer: tokenBase,
scopes: [{offset: 0, type: 'sass'}],
definedVars: [],
definedMixins: []
};
},
token: function(stream, state) {
var style = tokenLexer(stream, state);
state.lastToken = { style: style, content: stream.current() };
return style;
},
indent: function(state) {
return state.scopes[0].offset;
}
};
});
CodeMirror.defineMIME("text/x-sass", "sass");