Index: Source/devtools/front_end/cm/css.js |
diff --git a/Source/devtools/front_end/cm/css.js b/Source/devtools/front_end/cm/css.js |
index d8c30cf33d6fe1b5b452f39e6faa0aae9a361af4..2678c57d59adf10d728b402c4692a1f965a6b234 100644 |
--- a/Source/devtools/front_end/cm/css.js |
+++ b/Source/devtools/front_end/cm/css.js |
@@ -1,308 +1,341 @@ |
-CodeMirror.defineMode("css", function(config, parserConfig) { |
- "use strict"; |
+// CodeMirror, copyright (c) by Marijn Haverbeke and others |
+// Distributed under an MIT license: http://codemirror.net/LICENSE |
+ |
+(function(mod) { |
+ if (typeof exports == "object" && typeof module == "object") // CommonJS |
+ mod(require("../../lib/codemirror")); |
+ else if (typeof define == "function" && define.amd) // AMD |
+ define(["../../lib/codemirror"], mod); |
+ else // Plain browser env |
+ mod(CodeMirror); |
+})(function(CodeMirror) { |
+"use strict"; |
+CodeMirror.defineMode("css", function(config, parserConfig) { |
if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css"); |
- var indentUnit = config.indentUnit || config.tabSize || 2, |
- hooks = parserConfig.hooks || {}, |
- atMediaTypes = parserConfig.atMediaTypes || {}, |
- atMediaFeatures = parserConfig.atMediaFeatures || {}, |
+ var indentUnit = config.indentUnit, |
+ tokenHooks = parserConfig.tokenHooks, |
+ mediaTypes = parserConfig.mediaTypes || {}, |
+ mediaFeatures = parserConfig.mediaFeatures || {}, |
propertyKeywords = parserConfig.propertyKeywords || {}, |
+ nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {}, |
colorKeywords = parserConfig.colorKeywords || {}, |
valueKeywords = parserConfig.valueKeywords || {}, |
- allowNested = !!parserConfig.allowNested, |
- type = null; |
+ fontProperties = parserConfig.fontProperties || {}, |
+ allowNested = parserConfig.allowNested; |
+ var type, override; |
function ret(style, tp) { type = tp; return style; } |
+ // Tokenizers |
+ |
function tokenBase(stream, state) { |
var ch = stream.next(); |
- if (hooks[ch]) { |
- // result[0] is style and result[1] is type |
- var result = hooks[ch](stream, state); |
+ if (tokenHooks[ch]) { |
+ var result = tokenHooks[ch](stream, state); |
if (result !== false) return result; |
} |
- if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("def", stream.current());} |
- else if (ch == "=") ret(null, "compare"); |
- else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare"); |
- else if (ch == "\"" || ch == "'") { |
+ if (ch == "@") { |
+ stream.eatWhile(/[\w\\\-]/); |
+ return ret("def", stream.current()); |
+ } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) { |
+ return ret(null, "compare"); |
+ } else if (ch == "\"" || ch == "'") { |
state.tokenize = tokenString(ch); |
return state.tokenize(stream, state); |
- } |
- else if (ch == "#") { |
+ } else if (ch == "#") { |
stream.eatWhile(/[\w\\\-]/); |
return ret("atom", "hash"); |
- } |
- else if (ch == "!") { |
+ } else if (ch == "!") { |
stream.match(/^\s*\w*/); |
return ret("keyword", "important"); |
- } |
- else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) { |
+ } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) { |
stream.eatWhile(/[\w.%]/); |
return ret("number", "unit"); |
- } |
- else if (ch === "-") { |
- if (/\d/.test(stream.peek())) { |
+ } else if (ch === "-") { |
+ if (/[\d.]/.test(stream.peek())) { |
stream.eatWhile(/[\w.%]/); |
return ret("number", "unit"); |
- } else if (stream.match(/^[^-]+-/)) { |
+ } else if (stream.match(/^\w+-/)) { |
return ret("meta", "meta"); |
} |
- } |
- else if (/[,+>*\/]/.test(ch)) { |
+ } else if (/[,+>*\/]/.test(ch)) { |
return ret(null, "select-op"); |
- } |
- else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) { |
+ } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) { |
return ret("qualifier", "qualifier"); |
- } |
- else if (ch == ":") { |
- return ret("operator", ch); |
- } |
- else if (/[;{}\[\]\(\)]/.test(ch)) { |
+ } else if (/[:;{}\[\]\(\)]/.test(ch)) { |
return ret(null, ch); |
- } |
- else if (ch == "u" && stream.match("rl(")) { |
+ } else if (ch == "u" && stream.match("rl(")) { |
stream.backUp(1); |
state.tokenize = tokenParenthesized; |
- return ret("property", "variable"); |
- } |
- else { |
+ return ret("property", "word"); |
+ } else if (/[\w\\\-]/.test(ch)) { |
stream.eatWhile(/[\w\\\-]/); |
- return ret("property", "variable"); |
+ return ret("property", "word"); |
+ } else { |
+ return ret(null, null); |
} |
} |
- function tokenString(quote, nonInclusive) { |
+ function tokenString(quote) { |
return function(stream, state) { |
var escaped = false, ch; |
while ((ch = stream.next()) != null) { |
- if (ch == quote && !escaped) |
+ if (ch == quote && !escaped) { |
+ if (quote == ")") stream.backUp(1); |
break; |
+ } |
escaped = !escaped && ch == "\\"; |
} |
- if (!escaped) { |
- if (nonInclusive) stream.backUp(1); |
- state.tokenize = tokenBase; |
- } |
+ if (ch == quote || !escaped && quote != ")") state.tokenize = null; |
return ret("string", "string"); |
}; |
} |
function tokenParenthesized(stream, state) { |
stream.next(); // Must be '(' |
- if (!stream.match(/\s*[\"\']/, false)) |
- state.tokenize = tokenString(")", true); |
+ if (!stream.match(/\s*[\"\')]/, false)) |
+ state.tokenize = tokenString(")"); |
else |
- state.tokenize = tokenBase; |
+ state.tokenize = null; |
return ret(null, "("); |
} |
+ // Context management |
+ |
+ function Context(type, indent, prev) { |
+ this.type = type; |
+ this.indent = indent; |
+ this.prev = prev; |
+ } |
+ |
+ function pushContext(state, stream, type) { |
+ state.context = new Context(type, stream.indentation() + indentUnit, state.context); |
+ return type; |
+ } |
+ |
+ function popContext(state) { |
+ state.context = state.context.prev; |
+ return state.context.type; |
+ } |
+ |
+ function pass(type, stream, state) { |
+ return states[state.context.type](type, stream, state); |
+ } |
+ function popAndPass(type, stream, state, n) { |
+ for (var i = n || 1; i > 0; i--) |
+ state.context = state.context.prev; |
+ return pass(type, stream, state); |
+ } |
+ |
+ // Parser |
+ |
+ function wordAsValue(stream) { |
+ var word = stream.current().toLowerCase(); |
+ if (valueKeywords.hasOwnProperty(word)) |
+ override = "atom"; |
+ else if (colorKeywords.hasOwnProperty(word)) |
+ override = "keyword"; |
+ else |
+ override = "variable"; |
+ } |
+ |
+ var states = {}; |
+ |
+ states.top = function(type, stream, state) { |
+ if (type == "{") { |
+ return pushContext(state, stream, "block"); |
+ } else if (type == "}" && state.context.prev) { |
+ return popContext(state); |
+ } else if (type == "@media") { |
+ return pushContext(state, stream, "media"); |
+ } else if (type == "@font-face") { |
+ return "font_face_before"; |
+ } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) { |
+ return "keyframes"; |
+ } else if (type && type.charAt(0) == "@") { |
+ return pushContext(state, stream, "at"); |
+ } else if (type == "hash") { |
+ override = "builtin"; |
+ } else if (type == "word") { |
+ override = "tag"; |
+ } else if (type == "variable-definition") { |
+ return "maybeprop"; |
+ } else if (type == "interpolation") { |
+ return pushContext(state, stream, "interpolation"); |
+ } else if (type == ":") { |
+ return "pseudo"; |
+ } else if (allowNested && type == "(") { |
+ return pushContext(state, stream, "parens"); |
+ } |
+ return state.context.type; |
+ }; |
+ |
+ states.block = function(type, stream, state) { |
+ if (type == "word") { |
+ var word = stream.current().toLowerCase(); |
+ if (propertyKeywords.hasOwnProperty(word)) { |
+ override = "property"; |
+ return "maybeprop"; |
+ } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) { |
+ override = "string-2"; |
+ return "maybeprop"; |
+ } else if (allowNested) { |
+ override = stream.match(/^\s*:/, false) ? "property" : "tag"; |
+ return "block"; |
+ } else { |
+ override += " error"; |
+ return "maybeprop"; |
+ } |
+ } else if (type == "meta") { |
+ return "block"; |
+ } else if (!allowNested && (type == "hash" || type == "qualifier")) { |
+ override = "error"; |
+ return "block"; |
+ } else { |
+ return states.top(type, stream, state); |
+ } |
+ }; |
+ |
+ states.maybeprop = function(type, stream, state) { |
+ if (type == ":") return pushContext(state, stream, "prop"); |
+ return pass(type, stream, state); |
+ }; |
+ |
+ states.prop = function(type, stream, state) { |
+ if (type == ";") return popContext(state); |
+ if (type == "{" && allowNested) return pushContext(state, stream, "propBlock"); |
+ if (type == "}" || type == "{") return popAndPass(type, stream, state); |
+ if (type == "(") return pushContext(state, stream, "parens"); |
+ |
+ if (type == "hash" && !/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) { |
+ override += " error"; |
+ } else if (type == "word") { |
+ wordAsValue(stream); |
+ } else if (type == "interpolation") { |
+ return pushContext(state, stream, "interpolation"); |
+ } |
+ return "prop"; |
+ }; |
+ |
+ states.propBlock = function(type, _stream, state) { |
+ if (type == "}") return popContext(state); |
+ if (type == "word") { override = "property"; return "maybeprop"; } |
+ return state.context.type; |
+ }; |
+ |
+ states.parens = function(type, stream, state) { |
+ if (type == "{" || type == "}") return popAndPass(type, stream, state); |
+ if (type == ")") return popContext(state); |
+ if (type == "(") return pushContext(state, stream, "parens"); |
+ if (type == "word") wordAsValue(stream); |
+ return "parens"; |
+ }; |
+ |
+ states.pseudo = function(type, stream, state) { |
+ if (type == "word") { |
+ override = "variable-3"; |
+ return state.context.type; |
+ } |
+ return pass(type, stream, state); |
+ }; |
+ |
+ states.media = function(type, stream, state) { |
+ if (type == "(") return pushContext(state, stream, "media_parens"); |
+ if (type == "}") return popAndPass(type, stream, state); |
+ if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top"); |
+ |
+ if (type == "word") { |
+ var word = stream.current().toLowerCase(); |
+ if (word == "only" || word == "not" || word == "and") |
+ override = "keyword"; |
+ else if (mediaTypes.hasOwnProperty(word)) |
+ override = "attribute"; |
+ else if (mediaFeatures.hasOwnProperty(word)) |
+ override = "property"; |
+ else |
+ override = "error"; |
+ } |
+ return state.context.type; |
+ }; |
+ |
+ states.media_parens = function(type, stream, state) { |
+ if (type == ")") return popContext(state); |
+ if (type == "{" || type == "}") return popAndPass(type, stream, state, 2); |
+ return states.media(type, stream, state); |
+ }; |
+ |
+ states.font_face_before = function(type, stream, state) { |
+ if (type == "{") |
+ return pushContext(state, stream, "font_face"); |
+ return pass(type, stream, state); |
+ }; |
+ |
+ states.font_face = function(type, stream, state) { |
+ if (type == "}") return popContext(state); |
+ if (type == "word") { |
+ if (!fontProperties.hasOwnProperty(stream.current().toLowerCase())) |
+ override = "error"; |
+ else |
+ override = "property"; |
+ return "maybeprop"; |
+ } |
+ return "font_face"; |
+ }; |
+ |
+ states.keyframes = function(type, stream, state) { |
+ if (type == "word") { override = "variable"; return "keyframes"; } |
+ if (type == "{") return pushContext(state, stream, "top"); |
+ return pass(type, stream, state); |
+ }; |
+ |
+ states.at = function(type, stream, state) { |
+ if (type == ";") return popContext(state); |
+ if (type == "{" || type == "}") return popAndPass(type, stream, state); |
+ if (type == "word") override = "tag"; |
+ else if (type == "hash") override = "builtin"; |
+ return "at"; |
+ }; |
+ |
+ states.interpolation = function(type, stream, state) { |
+ if (type == "}") return popContext(state); |
+ if (type == "{" || type == ";") return popAndPass(type, stream, state); |
+ if (type != "variable") override = "error"; |
+ return "interpolation"; |
+ }; |
+ |
return { |
startState: function(base) { |
- return {tokenize: tokenBase, |
- baseIndent: base || 0, |
- stack: [], |
- lastToken: null}; |
+ return {tokenize: null, |
+ state: "top", |
+ context: new Context("top", base || 0, null)}; |
}, |
token: function(stream, state) { |
- |
- // Use these terms when applicable (see http://www.xanthir.com/blog/b4E50) |
- // |
- // rule** or **ruleset: |
- // A selector + braces combo, or an at-rule. |
- // |
- // declaration block: |
- // A sequence of declarations. |
- // |
- // declaration: |
- // A property + colon + value combo. |
- // |
- // property value: |
- // The entire value of a property. |
- // |
- // component value: |
- // A single piece of a property value. Like the 5px in |
- // text-shadow: 0 0 5px blue;. Can also refer to things that are |
- // multiple terms, like the 1-4 terms that make up the background-size |
- // portion of the background shorthand. |
- // |
- // term: |
- // The basic unit of author-facing CSS, like a single number (5), |
- // dimension (5px), string ("foo"), or function. Officially defined |
- // by the CSS 2.1 grammar (look for the 'term' production) |
- // |
- // |
- // simple selector: |
- // A single atomic selector, like a type selector, an attr selector, a |
- // class selector, etc. |
- // |
- // compound selector: |
- // One or more simple selectors without a combinator. div.example is |
- // compound, div > .example is not. |
- // |
- // complex selector: |
- // One or more compound selectors chained with combinators. |
- // |
- // combinator: |
- // The parts of selectors that express relationships. There are four |
- // currently - the space (descendant combinator), the greater-than |
- // bracket (child combinator), the plus sign (next sibling combinator), |
- // and the tilda (following sibling combinator). |
- // |
- // sequence of selectors: |
- // One or more of the named type of selector chained with commas. |
- |
- state.tokenize = state.tokenize || tokenBase; |
- if (state.tokenize == tokenBase && stream.eatSpace()) return null; |
- var style = state.tokenize(stream, state); |
- if (style && typeof style != "string") style = ret(style[0], style[1]); |
- |
- // Changing style returned based on context |
- var context = state.stack[state.stack.length-1]; |
- if (style == "variable") { |
- if (type == "variable-definition") state.stack.push("propertyValue"); |
- return state.lastToken = "variable-2"; |
- } else if (style == "property") { |
- var word = stream.current().toLowerCase(); |
- if (context == "propertyValue") { |
- if (valueKeywords.hasOwnProperty(word)) { |
- style = "string-2"; |
- } else if (colorKeywords.hasOwnProperty(word)) { |
- style = "keyword"; |
- } else { |
- style = "variable-2"; |
- } |
- } else if (context == "rule") { |
- if (!propertyKeywords.hasOwnProperty(word)) { |
- style += " error"; |
- } |
- } else if (context == "block") { |
- // if a value is present in both property, value, or color, the order |
- // of preference is property -> color -> value |
- if (propertyKeywords.hasOwnProperty(word)) { |
- style = "property"; |
- } else if (colorKeywords.hasOwnProperty(word)) { |
- style = "keyword"; |
- } else if (valueKeywords.hasOwnProperty(word)) { |
- style = "string-2"; |
- } else { |
- style = "tag"; |
- } |
- } else if (!context || context == "@media{") { |
- style = "tag"; |
- } else if (context == "@media") { |
- if (atMediaTypes[stream.current()]) { |
- style = "attribute"; // Known attribute |
- } else if (/^(only|not)$/.test(word)) { |
- style = "keyword"; |
- } else if (word == "and") { |
- style = "error"; // "and" is only allowed in @mediaType |
- } else if (atMediaFeatures.hasOwnProperty(word)) { |
- style = "error"; // Known property, should be in @mediaType( |
- } else { |
- // Unknown, expecting keyword or attribute, assuming attribute |
- style = "attribute error"; |
- } |
- } else if (context == "@mediaType") { |
- if (atMediaTypes.hasOwnProperty(word)) { |
- style = "attribute"; |
- } else if (word == "and") { |
- style = "operator"; |
- } else if (/^(only|not)$/.test(word)) { |
- style = "error"; // Only allowed in @media |
- } else { |
- // Unknown attribute or property, but expecting property (preceded |
- // by "and"). Should be in parentheses |
- style = "error"; |
- } |
- } else if (context == "@mediaType(") { |
- if (propertyKeywords.hasOwnProperty(word)) { |
- // do nothing, remains "property" |
- } else if (atMediaTypes.hasOwnProperty(word)) { |
- style = "error"; // Known property, should be in parentheses |
- } else if (word == "and") { |
- style = "operator"; |
- } else if (/^(only|not)$/.test(word)) { |
- style = "error"; // Only allowed in @media |
- } else { |
- style += " error"; |
- } |
- } else if (context == "@import") { |
- style = "tag"; |
- } else { |
- style = "error"; |
- } |
- } else if (style == "atom") { |
- if(!context || context == "@media{" || context == "block") { |
- style = "builtin"; |
- } else if (context == "propertyValue") { |
- if (!/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) { |
- style += " error"; |
- } |
- } else { |
- style = "error"; |
- } |
- } else if (context == "@media" && type == "{") { |
- style = "error"; |
+ if (!state.tokenize && stream.eatSpace()) return null; |
+ var style = (state.tokenize || tokenBase)(stream, state); |
+ if (style && typeof style == "object") { |
+ type = style[1]; |
+ style = style[0]; |
} |
- |
- // Push/pop context stack |
- if (type == "{") { |
- if (context == "@media" || context == "@mediaType") { |
- state.stack[state.stack.length-1] = "@media{"; |
- } |
- else { |
- var newContext = allowNested ? "block" : "rule"; |
- state.stack.push(newContext); |
- } |
- } |
- else if (type == "}") { |
- if (context == "interpolation") style = "operator"; |
- // Pop off end of array until { is reached |
- while(state.stack.length){ |
- var removed = state.stack.pop(); |
- if(removed.indexOf("{") > -1 || removed == "block" || removed == "rule"){ |
- break; |
- } |
- } |
- } |
- else if (type == "interpolation") state.stack.push("interpolation"); |
- else if (type == "@media") state.stack.push("@media"); |
- else if (type == "@import") state.stack.push("@import"); |
- else if (context == "@media" && /\b(keyword|attribute)\b/.test(style)) |
- state.stack[state.stack.length-1] = "@mediaType"; |
- else if (context == "@mediaType" && stream.current() == ",") |
- state.stack[state.stack.length-1] = "@media"; |
- else if (type == "(") { |
- if (context == "@media" || context == "@mediaType") { |
- // Make sure @mediaType is used to avoid error on { |
- state.stack[state.stack.length-1] = "@mediaType"; |
- state.stack.push("@mediaType("); |
- } |
- else state.stack.push("("); |
- } |
- else if (type == ")") { |
- // Pop off end of array until ( is reached |
- while(state.stack.length){ |
- var removed = state.stack.pop(); |
- if(removed.indexOf("(") > -1){ |
- break; |
- } |
- } |
- } |
- else if (type == ":" && state.lastToken == "property") state.stack.push("propertyValue"); |
- else if (context == "propertyValue" && type == ";") state.stack.pop(); |
- else if (context == "@import" && type == ";") state.stack.pop(); |
- |
- return state.lastToken = style; |
+ override = style; |
+ state.state = states[state.state](type, stream, state); |
+ return override; |
}, |
indent: function(state, textAfter) { |
- var n = state.stack.length; |
- if (/^\}/.test(textAfter)) |
- n -= state.stack[n-1] == "propertyValue" ? 2 : 1; |
- return state.baseIndent + n * indentUnit; |
+ var cx = state.context, ch = textAfter && textAfter.charAt(0); |
+ var indent = cx.indent; |
+ if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev; |
+ if (cx.prev && |
+ (ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "font_face") || |
+ ch == ")" && (cx.type == "parens" || cx.type == "media_parens") || |
+ ch == "{" && (cx.type == "at" || cx.type == "media"))) { |
+ indent = cx.indent - indentUnit; |
+ cx = cx.prev; |
+ } |
+ return indent; |
}, |
electricChars: "}", |
@@ -312,7 +345,6 @@ CodeMirror.defineMode("css", function(config, parserConfig) { |
}; |
}); |
-(function() { |
function keySet(array) { |
var keys = {}; |
for (var i = 0; i < array.length; ++i) { |
@@ -321,12 +353,12 @@ CodeMirror.defineMode("css", function(config, parserConfig) { |
return keys; |
} |
- var atMediaTypes = keySet([ |
+ var mediaTypes_ = [ |
"all", "aural", "braille", "handheld", "print", "projection", "screen", |
"tty", "tv", "embossed" |
- ]); |
+ ], mediaTypes = keySet(mediaTypes_); |
- var atMediaFeatures = keySet([ |
+ var mediaFeatures_ = [ |
"width", "min-width", "max-width", "height", "min-height", "max-height", |
"device-width", "min-device-width", "max-device-width", "device-height", |
"min-device-height", "max-device-height", "aspect-ratio", |
@@ -335,15 +367,15 @@ CodeMirror.defineMode("css", function(config, parserConfig) { |
"max-color", "color-index", "min-color-index", "max-color-index", |
"monochrome", "min-monochrome", "max-monochrome", "resolution", |
"min-resolution", "max-resolution", "scan", "grid" |
- ]); |
+ ], mediaFeatures = keySet(mediaFeatures_); |
- var propertyKeywords = keySet([ |
+ var propertyKeywords_ = [ |
"align-content", "align-items", "align-self", "alignment-adjust", |
"alignment-baseline", "anchor-point", "animation", "animation-delay", |
- "animation-direction", "animation-duration", "animation-iteration-count", |
- "animation-name", "animation-play-state", "animation-timing-function", |
- "appearance", "azimuth", "backface-visibility", "background", |
- "background-attachment", "background-clip", "background-color", |
+ "animation-direction", "animation-duration", "animation-fill-mode", |
+ "animation-iteration-count", "animation-name", "animation-play-state", |
+ "animation-timing-function", "appearance", "azimuth", "backface-visibility", |
+ "background", "background-attachment", "background-clip", "background-color", |
"background-image", "background-origin", "background-position", |
"background-repeat", "background-size", "baseline-shift", "binding", |
"bleed", "bookmark-label", "bookmark-level", "bookmark-state", |
@@ -374,10 +406,11 @@ CodeMirror.defineMode("css", function(config, parserConfig) { |
"font-stretch", "font-style", "font-synthesis", "font-variant", |
"font-variant-alternates", "font-variant-caps", "font-variant-east-asian", |
"font-variant-ligatures", "font-variant-numeric", "font-variant-position", |
- "font-weight", "grid-cell", "grid-column", "grid-column-align", |
- "grid-column-sizing", "grid-column-span", "grid-columns", "grid-flow", |
- "grid-row", "grid-row-align", "grid-row-sizing", "grid-row-span", |
- "grid-rows", "grid-template", "hanging-punctuation", "height", "hyphens", |
+ "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow", |
+ "grid-auto-position", "grid-auto-rows", "grid-column", "grid-column-end", |
+ "grid-column-start", "grid-row", "grid-row-end", "grid-row-start", |
+ "grid-template", "grid-template-areas", "grid-template-columns", |
+ "grid-template-rows", "hanging-punctuation", "height", "hyphens", |
"icon", "image-orientation", "image-rendering", "image-resolution", |
"inline-box-align", "justify-content", "left", "letter-spacing", |
"line-break", "line-height", "line-stacking", "line-stacking-ruby", |
@@ -387,7 +420,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) { |
"marker-offset", "marks", "marquee-direction", "marquee-loop", |
"marquee-play-count", "marquee-speed", "marquee-style", "max-height", |
"max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index", |
- "nav-left", "nav-right", "nav-up", "opacity", "order", "orphans", "outline", |
+ "nav-left", "nav-right", "nav-up", "object-fit", "object-position", |
+ "opacity", "order", "orphans", "outline", |
"outline-color", "outline-offset", "outline-style", "outline-width", |
"overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y", |
"padding", "padding-bottom", "padding-left", "padding-right", "padding-top", |
@@ -398,8 +432,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) { |
"region-break-before", "region-break-inside", "region-fragment", |
"rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness", |
"right", "rotation", "rotation-point", "ruby-align", "ruby-overhang", |
- "ruby-position", "ruby-span", "shape-inside", "shape-outside", "size", |
- "speak", "speak-as", "speak-header", |
+ "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin", |
+ "shape-outside", "size", "speak", "speak-as", "speak-header", |
"speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set", |
"tab-size", "table-layout", "target", "target-name", "target-new", |
"target-position", "text-align", "text-align-last", "text-decoration", |
@@ -414,20 +448,28 @@ CodeMirror.defineMode("css", function(config, parserConfig) { |
"vertical-align", "visibility", "voice-balance", "voice-duration", |
"voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", |
"voice-volume", "volume", "white-space", "widows", "width", "word-break", |
- "word-spacing", "word-wrap", "z-index", "zoom", |
+ "word-spacing", "word-wrap", "z-index", |
// SVG-specific |
"clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", |
"flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", |
- "color-interpolation", "color-interpolation-filters", "color-profile", |
+ "color-interpolation", "color-interpolation-filters", |
"color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering", |
"marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke", |
"stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", |
"stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering", |
"baseline-shift", "dominant-baseline", "glyph-orientation-horizontal", |
- "glyph-orientation-vertical", "kerning", "text-anchor", "writing-mode" |
- ]); |
+ "glyph-orientation-vertical", "text-anchor", "writing-mode" |
+ ], propertyKeywords = keySet(propertyKeywords_); |
+ |
+ var nonStandardPropertyKeywords = [ |
+ "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color", |
+ "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color", |
+ "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside", |
+ "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", |
+ "searchfield-results-decoration", "zoom" |
+ ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords); |
- var colorKeywords = keySet([ |
+ var colorKeywords_ = [ |
"aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", |
"bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", |
"burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", |
@@ -449,14 +491,14 @@ CodeMirror.defineMode("css", function(config, parserConfig) { |
"navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", |
"orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", |
"papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", |
- "purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", |
- "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", |
+ "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", |
+ "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", |
"slateblue", "slategray", "snow", "springgreen", "steelblue", "tan", |
"teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", |
"whitesmoke", "yellow", "yellowgreen" |
- ]); |
+ ], colorKeywords = keySet(colorKeywords_); |
- var valueKeywords = keySet([ |
+ var valueKeywords_ = [ |
"above", "absolute", "activeborder", "activecaption", "afar", |
"after-white-space", "ahead", "alias", "all", "all-scroll", "alternate", |
"always", "amharic", "amharic-abegede", "antialiased", "appworkspace", |
@@ -539,7 +581,16 @@ CodeMirror.defineMode("css", function(config, parserConfig) { |
"visibleStroke", "visual", "w-resize", "wait", "wave", "wider", |
"window", "windowframe", "windowtext", "x-large", "x-small", "xor", |
"xx-large", "xx-small" |
- ]); |
+ ], valueKeywords = keySet(valueKeywords_); |
+ |
+ var fontProperties_ = [ |
+ "font-family", "src", "unicode-range", "font-variant", "font-feature-settings", |
+ "font-stretch", "font-weight", "font-style" |
+ ], fontProperties = keySet(fontProperties_); |
+ |
+ var allWords = mediaTypes_.concat(mediaFeatures_).concat(propertyKeywords_) |
+ .concat(nonStandardPropertyKeywords).concat(colorKeywords_).concat(valueKeywords_); |
+ CodeMirror.registerHelper("hintWords", "css", allWords); |
function tokenCComment(stream, state) { |
var maybeEnd = false, ch; |
@@ -553,67 +604,90 @@ CodeMirror.defineMode("css", function(config, parserConfig) { |
return ["comment", "comment"]; |
} |
+ function tokenSGMLComment(stream, state) { |
+ if (stream.skipTo("-->")) { |
+ stream.match("-->"); |
+ state.tokenize = null; |
+ } else { |
+ stream.skipToEnd(); |
+ } |
+ return ["comment", "comment"]; |
+ } |
+ |
CodeMirror.defineMIME("text/css", { |
- atMediaTypes: atMediaTypes, |
- atMediaFeatures: atMediaFeatures, |
+ mediaTypes: mediaTypes, |
+ mediaFeatures: mediaFeatures, |
propertyKeywords: propertyKeywords, |
+ nonStandardPropertyKeywords: nonStandardPropertyKeywords, |
colorKeywords: colorKeywords, |
valueKeywords: valueKeywords, |
- hooks: { |
+ fontProperties: fontProperties, |
+ tokenHooks: { |
"<": function(stream, state) { |
- function tokenSGMLComment(stream, state) { |
- var dashes = 0, ch; |
- while ((ch = stream.next()) != null) { |
- if (dashes >= 2 && ch == ">") { |
- state.tokenize = null; |
- break; |
- } |
- dashes = (ch == "-") ? dashes + 1 : 0; |
- } |
- return ["comment", "comment"]; |
- } |
- if (stream.eat("!")) { |
- state.tokenize = tokenSGMLComment; |
- return tokenSGMLComment(stream, state); |
- } |
+ if (!stream.match("!--")) return false; |
+ state.tokenize = tokenSGMLComment; |
+ return tokenSGMLComment(stream, state); |
}, |
"/": function(stream, state) { |
- if (stream.eat("*")) { |
- state.tokenize = tokenCComment; |
- return tokenCComment(stream, state); |
- } |
- return false; |
+ if (!stream.eat("*")) return false; |
+ state.tokenize = tokenCComment; |
+ return tokenCComment(stream, state); |
} |
}, |
name: "css" |
}); |
CodeMirror.defineMIME("text/x-scss", { |
- atMediaTypes: atMediaTypes, |
- atMediaFeatures: atMediaFeatures, |
+ mediaTypes: mediaTypes, |
+ mediaFeatures: mediaFeatures, |
propertyKeywords: propertyKeywords, |
+ nonStandardPropertyKeywords: nonStandardPropertyKeywords, |
colorKeywords: colorKeywords, |
valueKeywords: valueKeywords, |
+ fontProperties: fontProperties, |
allowNested: true, |
- hooks: { |
+ tokenHooks: { |
+ "/": function(stream, state) { |
+ if (stream.eat("/")) { |
+ stream.skipToEnd(); |
+ return ["comment", "comment"]; |
+ } else if (stream.eat("*")) { |
+ state.tokenize = tokenCComment; |
+ return tokenCComment(stream, state); |
+ } else { |
+ return ["operator", "operator"]; |
+ } |
+ }, |
":": function(stream) { |
- if (stream.match(/\s*{/)) { |
+ if (stream.match(/\s*\{/)) |
return [null, "{"]; |
- } |
return false; |
}, |
"$": function(stream) { |
stream.match(/^[\w-]+/); |
- if (stream.peek() == ":") { |
- return ["variable", "variable-definition"]; |
- } |
- return ["variable", "variable"]; |
- }, |
- ",": function(stream, state) { |
- if (state.stack[state.stack.length - 1] == "propertyValue" && stream.match(/^ *\$/, false)) { |
- return ["operator", ";"]; |
- } |
+ if (stream.match(/^\s*:/, false)) |
+ return ["variable-2", "variable-definition"]; |
+ return ["variable-2", "variable"]; |
}, |
+ "#": function(stream) { |
+ if (!stream.eat("{")) return false; |
+ return [null, "interpolation"]; |
+ } |
+ }, |
+ name: "css", |
+ helperType: "scss" |
+ }); |
+ |
+ CodeMirror.defineMIME("text/x-less", { |
+ mediaTypes: mediaTypes, |
+ mediaFeatures: mediaFeatures, |
+ propertyKeywords: propertyKeywords, |
+ nonStandardPropertyKeywords: nonStandardPropertyKeywords, |
+ colorKeywords: colorKeywords, |
+ valueKeywords: valueKeywords, |
+ fontProperties: fontProperties, |
+ allowNested: true, |
+ tokenHooks: { |
"/": function(stream, state) { |
if (stream.eat("/")) { |
stream.skipToEnd(); |
@@ -625,15 +699,19 @@ CodeMirror.defineMode("css", function(config, parserConfig) { |
return ["operator", "operator"]; |
} |
}, |
- "#": function(stream) { |
- if (stream.eat("{")) { |
- return ["operator", "interpolation"]; |
- } else { |
- stream.eatWhile(/[\w\\\-]/); |
- return ["atom", "hash"]; |
- } |
+ "@": function(stream) { |
+ if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false; |
+ stream.eatWhile(/[\w\\\-]/); |
+ if (stream.match(/^\s*:/, false)) |
+ return ["variable-2", "variable-definition"]; |
+ return ["variable-2", "variable"]; |
+ }, |
+ "&": function() { |
+ return ["atom", "atom"]; |
} |
}, |
- name: "css" |
+ name: "css", |
+ helperType: "less" |
}); |
-})(); |
+ |
+}); |