Files @ ad49bbd8f984
Branch filter:

Location: kallithea/rhodecode/public/js/mode/sass/sass.js - annotation

Bradley M. Kuhn
changelog - should refer to Mercurial repository logs instead
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
a60a0e9092c6
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");