Skip to content
Snippets Groups Projects
Commit 9e56052a authored by Ankit's avatar Ankit Committed by Marijn Haverbeke
Browse files

[sass mode] Fixed bug #2156 and syntax highlighting too

To fix this I had to introduce new state parameter that tells if
cursor is before colon or not.
parent d0a2ddaa
No related branches found
No related tags found
Loading
...@@ -19,10 +19,11 @@ CodeMirror.defineMode("sass", function(config) { ...@@ -19,10 +19,11 @@ CodeMirror.defineMode("sass", function(config) {
var keywords = ["true", "false", "null", "auto"]; var keywords = ["true", "false", "null", "auto"];
var keywordsRegexp = new RegExp("^" + keywords.join("|")); var keywordsRegexp = new RegExp("^" + keywords.join("|"));
var operators = ["\\(", "\\)", "=", ">", "<", "==", ">=", "<=", "\\+", "-", "\\!=", "/", "\\*", "%", "and", "or", "not"]; var operators = ["\\(", "\\)", "=", ">", "<", "==", ">=", "<=", "\\+", "-",
"\\!=", "/", "\\*", "%", "and", "or", "not", ";","\\{","\\}",":"];
var opRegexp = tokenRegexp(operators); var opRegexp = tokenRegexp(operators);
var pseudoElementsRegexp = /^::[\w\-]+/; var pseudoElementsRegexp = /^::?[a-zA-Z_][\w\-]*/;
function urlTokens(stream, state) { function urlTokens(stream, state) {
var ch = stream.peek(); var ch = stream.peek();
...@@ -56,7 +57,7 @@ CodeMirror.defineMode("sass", function(config) { ...@@ -56,7 +57,7 @@ CodeMirror.defineMode("sass", function(config) {
stream.next(); stream.next();
state.tokenizer = tokenBase; state.tokenizer = tokenBase;
} else { } else {
stream.next(); stream.skipToEnd();
} }
return "comment"; return "comment";
...@@ -135,178 +136,216 @@ CodeMirror.defineMode("sass", function(config) { ...@@ -135,178 +136,216 @@ CodeMirror.defineMode("sass", function(config) {
return "operator"; return "operator";
} }
if (ch === ".") { // Strings
if (ch === '"' || ch === "'") {
stream.next(); stream.next();
state.tokenizer = buildStringTokenizer(ch);
// Match class selectors return "string";
if (stream.match(/^[\w-]+/)) {
indent(state);
return "atom";
} else if (stream.peek() === "#") {
indent(state);
return "atom";
} else {
return "operator";
}
} }
if (ch === "#") { if(!state.cursorHalf){// state.cursorHalf === 0
stream.next(); // first half i.e. before : for key-value pairs
// including selectors
// Hex numbers if (ch === ".") {
if (stream.match(/[0-9a-fA-F]{6}|[0-9a-fA-F]{3}/)) stream.next();
return "number"; if (stream.match(/^[\w-]+/)) {
indent(state);
return "atom";
} else if (stream.peek() === "#") {
indent(state);
return "atom";
}
}
// ID selectors if (ch === "#") {
if (stream.match(/^[\w-]+/)) { stream.next();
indent(state); // ID selectors
return "atom"; if (stream.match(/^[\w-]+/)) {
indent(state);
return "atom";
}
if (stream.peek() === "#") {
indent(state);
return "atom";
}
} }
if (stream.peek() === "#") { // Variables
indent(state); if (ch === "$") {
return "atom"; stream.next();
stream.eatWhile(/[\w-]/);
return "variable-2";
} }
}
// Numbers // Numbers
if (stream.match(/^-?[0-9\.]+/)) if (stream.match(/^-?[0-9\.]+/))
return "number"; return "number";
// Units
if (stream.match(/^(px|em|in)\b/))
return "unit";
// Units if (stream.match(keywordsRegexp))
if (stream.match(/^(px|em|in)\b/)) return "keyword";
return "unit";
if (stream.match(keywordsRegexp)) if (stream.match(/^url/) && stream.peek() === "(") {
return "keyword"; state.tokenizer = urlTokens;
return "atom";
}
if (stream.match(/^url/) && stream.peek() === "(") { if (ch === "=") {
state.tokenizer = urlTokens; // Match shortcut mixin definition
return "atom"; if (stream.match(/^=[\w-]+/)) {
} indent(state);
return "meta";
}
}
// Variables if (ch === "+") {
if (ch === "$") { // Match shortcut mixin definition
stream.next(); if (stream.match(/^\+[\w-]+/)){
stream.eatWhile(/[\w-]/); return "variable-3";
stream.eatSpace(); }
if (stream.peek() === ":") }
return "variable-2";
else
return "variable-3";
}
if (ch === "!") { if(ch === "@"){
stream.next(); if(stream.match(/@extend/)){
return stream.match(/^[\w]+/) ? "keyword": "operator"; if(!stream.match(/\s*[\w]/))
} dedent(state);
}
}
if (ch === "=") {
stream.next();
// Match shortcut mixin definition // Indent Directives
if (stream.match(/^[\w-]+/)) { if (stream.match(/^@(else if|if|media|else|for|each|while|mixin|function)/)) {
indent(state); indent(state);
return "meta"; return "meta";
} else {
return "operator";
} }
}
if (ch === "+") { // Other Directives
stream.next(); if (ch === "@") {
stream.next();
stream.eatWhile(/[\w-]/);
return "meta";
}
// Match shortcut mixin definition if (stream.eatWhile(/[\w-]/)){
if (stream.match(/^[\w-]+/)) if(stream.match(/ *: *[\w-\+\$#!\("']/,false)){
return "variable-3"; return "propery";
else }
else if(stream.match(/ *:/,false)){
indent(state);
state.cursorHalf = 1;
return "atom";
}
else if(stream.match(/ *,/,false)){
return "atom";
}
else{
indent(state);
return "atom";
}
}
if(ch === ":"){
if (stream.match(pseudoElementsRegexp)){ // could be a pseudo-element
return "keyword";
}
stream.next();
state.cursorHalf=1;
return "operator"; return "operator";
} }
// Indent Directives } // cursorHalf===0 ends here
if (stream.match(/^@(else if|if|media|else|for|each|while|mixin|function)/)) { else{
indent(state);
return "meta";
}
// Other Directives if (ch === "#") {
if (ch === "@") { stream.next();
stream.next(); // Hex numbers
stream.eatWhile(/[\w-]/); if (stream.match(/[0-9a-fA-F]{6}|[0-9a-fA-F]{3}/)){
return "meta"; if(!stream.peek()){
} state.cursorHalf = 0;
}
return "number";
}
}
// Strings // Numbers
if (ch === '"' || ch === "'") { if (stream.match(/^-?[0-9\.]+/)){
stream.next(); if(!stream.peek()){
state.tokenizer = buildStringTokenizer(ch); state.cursorHalf = 0;
return "string"; }
} return "number";
}
// Units
if (stream.match(/^(px|em|in)\b/)){
if(!stream.peek()){
state.cursorHalf = 0;
}
return "unit";
}
// Pseudo element selectors and values after colon if (stream.match(keywordsRegexp)){
if (ch === ":"){ if(!stream.peek()){
if (stream.match(pseudoElementsRegexp)) state.cursorHalf = 0;
}
return "keyword"; return "keyword";
stream.next();
stream.eatSpace();
if (stream.peek() === null){
// if there is no more space after it
indent(state);
return "atom";
} }
// all posible tokens after colon if (stream.match(/^url/) && stream.peek() === "(") {
if (stream.match(/\$[\w-]+/)){
// variables
return "variable-3";
} else if (stream.match(/^url/) && stream.peek() === "(") {
//urls
state.tokenizer = urlTokens; state.tokenizer = urlTokens;
return "atom"; if(!stream.peek()){
} else if (stream.match(/#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3}/)){ state.cursorHalf = 0;
//hexadecimal value }
return "number";
} else if (stream.match(/^-?[0-9\.]+/)){
return "number";
} else if (stream.match(keywordsRegexp)){
return "keyword";
} else if (stream.match(/[\w-,\s]+/)){
// other text
return "atom"; return "atom";
} }
}
if (stream.match(opRegexp)) // Variables
return "operator"; if (ch === "$") {
stream.next();
stream.eatWhile(/[\w-]/);
if(!stream.peek()){
state.cursorHalf = 0;
}
return "variable-3";
}
// atoms // bang character for !important, !default, etc.
if (stream.eatWhile(/[\w-&]/)) { if (ch === "!") {
stream.eatSpace(); stream.next();
// matches a property definition if(!stream.peek()){
if (stream.peek() === ":" ){ state.cursorHalf = 0;
if (!stream.match(/:[ ]*[\d\w-\$\+#!\("']/,false)){
//for cases where line ends after colon
// eg
// font:
// | <-----cursor
indent(state);
return "property";
} else if (!stream.match(pseudoElementsRegexp, false)){
return "property";
} }
} else { return stream.match(/^[\w]+/) ? "keyword": "operator";
stream.eatSpace(); }
if (stream.peek() !== "," ){
//for cases where line ends after comma if (stream.match(opRegexp)){
//eg if(!stream.peek()){
//head, state.cursorHalf = 0;
//body,
//| <-----cursor
indent(state);
} }
return "atom"; return "operator";
}
// attributes
if (stream.eatWhile(/[\w-]/)) {
if(!stream.peek()){
state.cursorHalf = 0;
}
return "attribute";
} }
}
//stream.eatSpace();
if(!stream.peek()){
state.cursorHalf = 0;
return null;
}
} // else ends here
if (stream.match(opRegexp))
return "operator";
// If we haven't returned by now, we move 1 character // If we haven't returned by now, we move 1 character
// and return an error // and return an error
...@@ -319,11 +358,13 @@ CodeMirror.defineMode("sass", function(config) { ...@@ -319,11 +358,13 @@ CodeMirror.defineMode("sass", function(config) {
var style = state.tokenizer(stream, state); var style = state.tokenizer(stream, state);
var current = stream.current(); var current = stream.current();
if (current === "@return") if (current === "@return" || current === "}"){
dedent(state); dedent(state);
}
if (style !== null) { if (style !== null) {
var startOfToken = stream.pos - current.length; var startOfToken = stream.pos - current.length;
var withCurrentIndent = startOfToken + (config.indentUnit * state.indentCount); var withCurrentIndent = startOfToken + (config.indentUnit * state.indentCount);
var newScopes = []; var newScopes = [];
...@@ -348,6 +389,8 @@ CodeMirror.defineMode("sass", function(config) { ...@@ -348,6 +389,8 @@ CodeMirror.defineMode("sass", function(config) {
tokenizer: tokenBase, tokenizer: tokenBase,
scopes: [{offset: 0, type: "sass"}], scopes: [{offset: 0, type: "sass"}],
indentCount: 0, indentCount: 0,
cursorHalf: 0, // cursor half tells us if cursor lies after (1)
// or before (0) colon (well... more or less)
definedVars: [], definedVars: [],
definedMixins: [] definedMixins: []
}; };
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment