Web Inspector: CSS autofill suggests properties instead of values when values are...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 Apr 2014 22:29:16 +0000 (22:29 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 Apr 2014 22:29:16 +0000 (22:29 +0000)
https://bugs.webkit.org/show_bug.cgi?id=132090

Patch by Jonathan Wells <jonowells@apple.com> on 2014-04-24
Reviewed by Joseph Pecoraro.

Updates are required to the CodeMirror helpers to be compatible with
CodeMirror 4. Some of those changes have been made to fix an issue
with CSS autofill, CSS code coloring, and also
https://bugs.webkit.org/show_bug.cgi?id=131859. The main issue is that
CodeMirror 4's CSS mode (css.js) stores its parsing modes in a different
data structure. All references to state.stack are obscelete. Many
are fixed here and more will be in an upcoming patch.

* Tools/PrettyPrinting/CodeMirrorFormatters.js: Removed exception for checking state.stack properties.
* UserInterface/Controllers/CodeMirrorCompletionController.js:
(WebInspector.CodeMirrorCompletionController.prototype._generateCSSCompletions): Corrected "block" state detection.
* UserInterface/External/CodeMirror/less.js: Removed.
* UserInterface/Views/CodeMirrorAdditions.js: Sets default state of "block" correctly.
* UserInterface/Views/CodeMirrorFormatters.js: Removed exception for checking state.stack properties.
* UserInterface/Views/SyntaxHighlightingDefaultTheme.css: Fix styles to match CSS mode changes.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@167779 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Tools/PrettyPrinting/CodeMirrorFormatters.js
Source/WebInspectorUI/UserInterface/Controllers/CodeMirrorCompletionController.js
Source/WebInspectorUI/UserInterface/External/CodeMirror/less.js [deleted file]
Source/WebInspectorUI/UserInterface/Views/CodeMirrorAdditions.js
Source/WebInspectorUI/UserInterface/Views/CodeMirrorFormatters.js
Source/WebInspectorUI/UserInterface/Views/SyntaxHighlightingDefaultTheme.css

index 17c1fed..b10fb9c 100644 (file)
@@ -1,3 +1,26 @@
+2014-04-24  Jonathan Wells  <jonowells@apple.com>
+
+        Web Inspector: CSS autofill suggests properties instead of values when values are needed
+        https://bugs.webkit.org/show_bug.cgi?id=132090
+
+        Reviewed by Joseph Pecoraro.
+
+        Updates are required to the CodeMirror helpers to be compatible with
+        CodeMirror 4. Some of those changes have been made to fix an issue
+        with CSS autofill, CSS code coloring, and also
+        https://bugs.webkit.org/show_bug.cgi?id=131859. The main issue is that
+        CodeMirror 4's CSS mode (css.js) stores its parsing modes in a different
+        data structure. All references to state.stack are obscelete. Many
+        are fixed here and more will be in an upcoming patch.
+
+        * Tools/PrettyPrinting/CodeMirrorFormatters.js: Removed exception for checking state.stack properties.
+        * UserInterface/Controllers/CodeMirrorCompletionController.js:
+        (WebInspector.CodeMirrorCompletionController.prototype._generateCSSCompletions): Corrected "block" state detection.
+        * UserInterface/External/CodeMirror/less.js: Removed.
+        * UserInterface/Views/CodeMirrorAdditions.js: Sets default state of "block" correctly.
+        * UserInterface/Views/CodeMirrorFormatters.js: Removed exception for checking state.stack properties.
+        * UserInterface/Views/SyntaxHighlightingDefaultTheme.css: Fix styles to match CSS mode changes.
+
 2014-04-24  Antoine Quint  <graouts@webkit.org>
 
         Web Inspector: gradient editor does not appear for linear-gradient with no specified angle
         * Localizations/en.lproj/localizedStrings.js:
         * UserInterface/Models/DOMNode.js:
         * UserInterface/Views/DOMNodeDetailsSidebarPanel.js:
-        * UserInterface/Views/Main.css: 
+        * UserInterface/Views/Main.css:
 
 2014-03-28  Joseph Pecoraro  <pecoraro@apple.com>
 
 
         * UserInterface/Views/DataGrid.js:
         (WebInspector.DataGrid.prototype.removeChild):
-        Add missing semicolon.        
+        Add missing semicolon.
 
 2014-03-12  Brian Burg  <bburg@apple.com>
 
         of linear gradients, we parse all values, save for lengths, and in the case of radial gradients, we preserve the
         sizing information as a string and parse only the gradient stops as the sizing information is only useful to show
         in an editor if attached to an element with metrics.
-        
+
         Since instances of Gradient are used as the .value property of CodeMirrorGradientEditingController, we implement
         the required .copy() and .toString() methods. The .toString() implementations are aware of default values for angles
         and color stop offsets and only print those as necessary and use shorthands when possible.
         * UserInterface/CodeMirrorEditingController.js: Copied from Source/WebInspectorUI/UserInterface/CodeMirrorColorEditingController.js.
         New class meant to be subclassed by any future editing controller, and already subclassed by
         CodeMirrorColorEditingController. This class exposes several hooks for subclasses to customize its behavior:
-        
+
         .initialValue: a value we can revert to if the editing is canceled
         .cssClassName: a CSS class name that can be added to the editing controller's container
         .popoverPreferredEdges: a list of preferredEdges as passed to Popover.prototype.present() with a sensible default
         .popoverDidPresent: called as the popover just was presented, typically overridden when content needs to tuned only after
         being added to the DOM and setting of the necessary machinery to update the serialized value in the editor based on interaction
         within the popover without changing the serialized value upon showing the popover the very first time.
-        
+
         Additionally, the .value property must be an object supporting .toString() and .copy() method.
 
         Finally, the .editingControllerDidStartEditing() and .editingControllerDidFinishEditing() delegate methods are fired
-        as editing begins and finishes. 
+        as editing begins and finishes.
 
         (WebInspector.CodeMirrorEditingController):
         (WebInspector.CodeMirrorEditingController.prototype.get marker):
         * UserInterface/HoverMenu.js:
         We remove the assumption that a HoverMenu is only used to draw a single rounded rect based on a simple
         Rect and instead support presentation based on an array of Rects where we either:
-        
+
         - draw a single rounded rectangle if there is only a single Rect provided
         - draw two disconnected open-ended rects if we're provided with two non-overlapping Rects
         - draw a polygon surrounding all provided Rects in all other cases
 
         Reviewed by Timothy Hatcher.
 
-        Add a RuntimeManager event that the scope chain details sidebar can 
+        Add a RuntimeManager event that the scope chain details sidebar can
         listen to to trigger refresh.
 
         Testing on this is blocked by http://webkit.org/b/128724
 
         * UserInterface/DebuggerSidebarPanel.js:
         (WebInspector.DebuggerSidebarPanel.prototype.restoreStateFromCookie):
-        Drive-by fix to pass along relaxedMatchDelay to the superclass. 
+        Drive-by fix to pass along relaxedMatchDelay to the superclass.
 
         * UserInterface/Main.js:
         (WebInspector.loaded):
         Stop using __markedColor to identify a color marker and instead use the type on the matching
         WebInspector.TextMarker. Additionally, create a WebInspector.TextMarker with type
         WebInspector.TextMarker.Type.Color in createColorMarkers().
-        
+
         * UserInterface/CodeMirrorColorEditingController.js:
         (WebInspector.CodeMirrorColorEditingController):
         Use a WebInspector.TextRange to track the edited range and obtain it directly from the
         to retrieve an object with the following structure:
         {
              "regionFlow": <Reference to the ContentFlow object referenced by the -webkit-flow-from property of the node>,
-             "contentFlow": <Reference to the ContentFlow object referenced by the -webkit-flow-into property of 
+             "contentFlow": <Reference to the ContentFlow object referenced by the -webkit-flow-into property of
                              the node or a parent of the node>,
              "regions": [ list of DOMNodes representing the regions containers of the node. The node is split across all these regions. ]
         }
 
         Automatically dispatch a contextmenu event in case WebInspector.ContextMenu.prototype.show()
         is called outside of a contextmenu event handler and would therefore not show the expected
-        context menu (except in the Remote Web Inspector where this already works). 
+        context menu (except in the Remote Web Inspector where this already works).
 
         * UserInterface/ContextMenu.js:
         (WebInspector.ContextMenu.prototype.show):
         the arrow within the center of the attachment edge, we get in situations where we may
         shrink the popover instead of shifting it to fit within the container frame. We now first
         shift the preferred frame before getting its intersection with the container frame to
-        avoid such situations. 
+        avoid such situations.
 
         * UserInterface/Popover.js:
         (WebInspector.Popover.prototype._bestMetricsForEdge):
 
 2013-11-06  Timothy Hatcher  <timothy@apple.com>
 
-        Fix the display of query parameters when the value is missing. 
+        Fix the display of query parameters when the value is missing.
 
         https://bugs.webkit.org/show_bug.cgi?id=123920
 
 
         Reviewed by Timothy Hatcher.
 
-        Moved some global functions out of Main.js, so that they can be used in the 
+        Moved some global functions out of Main.js, so that they can be used in the
         layout tests without including Main.js.
 
         * UserInterface/Main.html: Referenced the new JS files.
         CSSStyleDeclarationTextEditor when the Cmd key is pressed and in the SourceCodeTextEditor
         when either the Cmd key is pressed (NonSymbolTokens mode) or when the debugger is paused
         (JavaScriptExpression mode).
-        
+
         The tokenTrackingController is now smarter about how it tracks mouse events when it's enabled,
         tracking "mouseenter" and "mouseleave" events to enable tracking allowing immediate detection of
         tokens being hovered or no longer being hovered even with quick mouse movements. Additioanlly,
index 3d99cb6..840c0b3 100644 (file)
@@ -337,7 +337,7 @@ CodeMirror.extendMode("css", {
             if (content === ";")
                 return 1;
             if (content === ",") { // "a,b,c,...,z{}" rule list at top level or in @media top level and only if the line length will be large.
-                if ((!state.stack.length || state.stack.lastValue === "@media{") && state._cssPrettyPrint.lineLength > 60) {
+                if ((!state.stack || !state.stack.length || state.stack.lastValue === "@media{") && state._cssPrettyPrint.lineLength > 60) {
                     state._cssPrettyPrint.lineLength = 0;
                     return 1;
                 }
@@ -395,7 +395,7 @@ CodeMirror.extendMode("css", {
         // In order insert newlines in selector lists we need keep track of the length of the current line.
         // This isn't exact line length, only the builder knows that, but it is good enough to get an idea.
         // If we are at a top level, keep track of the current line length, otherwise we reset to 0.
-        if (!state.stack.length || state.stack.lastValue === "@media{")
+        if (!state.stack || !state.stack.length || state.stack.lastValue === "@media{")
             state._cssPrettyPrint.lineLength += content.length;
         else
             state._cssPrettyPrint.lineLength = 0;
index c27e16b..849e902 100644 (file)
@@ -518,15 +518,15 @@ WebInspector.CodeMirrorCompletionController.prototype = {
 
     _generateCSSCompletions: function(mainToken, base, suffix)
     {
-        // We only support completion inside CSS rules.
-        if (!mainToken.state || !mainToken.state.stack || !mainToken.state.stack.contains("rule"))
+        // We only support completion inside CSS block context.
+        if (!mainToken.state || !mainToken.state.state || !mainToken.state.state === "block")
             return [];
 
         var token = mainToken;
         var lineNumber = this._lineNumber;
 
         // Scan backwards looking for the current property.
-        while (token.state.stack.lastValue === "propertyValue") {
+        while (token.state.state === "prop") {
             // Found the beginning of the line. Go to the previous line.
             if (!token.start) {
                 --lineNumber;
diff --git a/Source/WebInspectorUI/UserInterface/External/CodeMirror/less.js b/Source/WebInspectorUI/UserInterface/External/CodeMirror/less.js
deleted file mode 100644 (file)
index da39074..0000000
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
-  LESS mode - http://www.lesscss.org/
-  Ported to CodeMirror by Peter Kroon <plakroon@gmail.com>
-  Report bugs/issues here: https://github.com/marijnh/CodeMirror/issues
-  GitHub: @peterkroon
-*/
-
-CodeMirror.defineMode("less", function(config) {
-  var indentUnit = config.indentUnit, type;
-  function ret(style, tp) {type = tp; return style;}
-
-  var selectors = /(^\:root$|^\:nth\-child$|^\:nth\-last\-child$|^\:nth\-of\-type$|^\:nth\-last\-of\-type$|^\:first\-child$|^\:last\-child$|^\:first\-of\-type$|^\:last\-of\-type$|^\:only\-child$|^\:only\-of\-type$|^\:empty$|^\:link|^\:visited$|^\:active$|^\:hover$|^\:focus$|^\:target$|^\:lang$|^\:enabled^\:disabled$|^\:checked$|^\:first\-line$|^\:first\-letter$|^\:before$|^\:after$|^\:not$|^\:required$|^\:invalid$)/;
-
-  function tokenBase(stream, state) {
-    var ch = stream.next();
-
-    if (ch == "@") {stream.eatWhile(/[\w\-]/); return ret("meta", stream.current());}
-    else if (ch == "/" && stream.eat("*")) {
-      state.tokenize = tokenCComment;
-      return tokenCComment(stream, state);
-    } else if (ch == "<" && stream.eat("!")) {
-      state.tokenize = tokenSGMLComment;
-      return tokenSGMLComment(stream, state);
-    } else if (ch == "=") ret(null, "compare");
-    else if (ch == "|" && stream.eat("=")) return ret(null, "compare");
-    else if (ch == "\"" || ch == "'") {
-      state.tokenize = tokenString(ch);
-      return state.tokenize(stream, state);
-    } else if (ch == "/") { // e.g.: .png will not be parsed as a class
-      if(stream.eat("/")){
-        state.tokenize = tokenSComment;
-        return tokenSComment(stream, state);
-      } else {
-        if(type == "string" || type == "(") return ret("string", "string");
-        if(state.stack[state.stack.length-1] !== undefined) return ret(null, ch);
-        stream.eatWhile(/[\a-zA-Z0-9\-_.\s]/);
-        if( /\/|\)|#/.test(stream.peek() || (stream.eatSpace() && stream.peek() === ")"))  || stream.eol() )return ret("string", "string"); // let url(/images/logo.png) without quotes return as string
-      }
-    } else if (ch == "!") {
-      stream.match(/^\s*\w*/);
-      return ret("keyword", "important");
-    } else if (/\d/.test(ch)) {
-      stream.eatWhile(/[\w.%]/);
-      return ret("number", "unit");
-    } else if (/[,+<>*\/]/.test(ch)) {
-      if(stream.peek() == "=" || type == "a")return ret("string", "string");
-      if(ch === ",")return ret(null, ch);
-      return ret(null, "select-op");
-    } else if (/[;{}:\[\]()~\|]/.test(ch)) {
-      if(ch == ":"){
-        stream.eatWhile(/[a-z\\\-]/);
-        if( selectors.test(stream.current()) ){
-          return ret("tag", "tag");
-        } else if(stream.peek() == ":"){//::-webkit-search-decoration
-          stream.next();
-          stream.eatWhile(/[a-z\\\-]/);
-          if(stream.current().match(/\:\:\-(o|ms|moz|webkit)\-/))return ret("string", "string");
-          if( selectors.test(stream.current().substring(1)) )return ret("tag", "tag");
-          return ret(null, ch);
-        } else {
-          return ret(null, ch);
-        }
-      } else if(ch == "~"){
-        if(type == "r")return ret("string", "string");
-      } else {
-        return ret(null, ch);
-      }
-    } else if (ch == ".") {
-      if(type == "(")return ret("string", "string"); // allow url(../image.png)
-      stream.eatWhile(/[\a-zA-Z0-9\-_]/);
-      if(stream.peek() === " ")stream.eatSpace();
-      if(stream.peek() === ")" || type === ":")return ret("number", "unit");//rgba(0,0,0,.25);
-      else if(stream.current().length >1){
-        if(state.stack[state.stack.length-1] === "rule" && stream.peek().match(/{|,|\+|\(/) === null)return ret("number", "unit");
-      }
-      return ret("tag", "tag");
-    } else if (ch == "#") {
-      //we don't eat white-space, we want the hex color and or id only
-      stream.eatWhile(/[A-Za-z0-9]/);
-      //check if there is a proper hex color length e.g. #eee || #eeeEEE
-      if(stream.current().length == 4 || stream.current().length == 7){
-        if(stream.current().match(/[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/,false) != null){//is there a valid hex color value present in the current stream
-          //when not a valid hex value, parse as id
-          if(stream.current().substring(1) != stream.current().match(/[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/,false))return ret("atom", "tag");
-          //eat white-space
-          stream.eatSpace();
-          //when hex value declaration doesn't end with [;,] but is does with a slash/cc comment treat it as an id, just like the other hex values that don't end with[;,]
-          if( /[\/<>.(){!$%^&*_\-\\?=+\|#'~`]/.test(stream.peek()) ){
-            if(type === "select-op")return ret("number", "unit"); else return ret("atom", "tag");
-          }
-          //#time { color: #aaa }
-          else if(stream.peek() == "}" )return ret("number", "unit");
-          //we have a valid hex color value, parse as id whenever an element/class is defined after the hex(id) value e.g. #eee aaa || #eee .aaa
-          else if( /[a-zA-Z\\]/.test(stream.peek()) )return ret("atom", "tag");
-          //when a hex value is on the end of a line, parse as id
-          else if(stream.eol())return ret("atom", "tag");
-          //default
-          else return ret("number", "unit");
-        } else {//when not a valid hexvalue in the current stream e.g. #footer
-          stream.eatWhile(/[\w\\\-]/);
-          return ret("atom", stream.current());
-        }
-      } else {//when not a valid hexvalue length
-        stream.eatWhile(/[\w\\\-]/);
-        if(state.stack[state.stack.length-1] === "rule")return ret("atom", stream.current());return ret("atom", stream.current());
-        return ret("atom", "tag");
-      }
-    } else if (ch == "&") {
-      stream.eatWhile(/[\w\-]/);
-      return ret(null, ch);
-    } else {
-      stream.eatWhile(/[\w\\\-_%.{]/);
-      if(stream.current().match(/\\/) !== null){
-        if(stream.current().charAt(stream.current().length-1) === "\\"){
-          stream.eat(/\'|\"|\)|\(/);
-          while(stream.eatWhile(/[\w\\\-_%.{]/)){
-            stream.eat(/\'|\"|\)|\(/);
-          }
-          return ret("string", stream.current());
-        }
-      } //else if(type === "tag")return ret("tag", "tag");
-        else if(type == "string"){
-        if(state.stack[state.stack.length-1] === "{" && stream.peek() === ":")return ret("variable", "variable");
-        if(stream.peek() === "/")stream.eatWhile(/[\w\\\-_%.{:\/]/);
-        return ret(type, stream.current());
-      } else if(stream.current().match(/(^http$|^https$)/) != null){
-        stream.eatWhile(/[\w\\\-_%.{:\/]/);
-        if(stream.peek() === "/")stream.eatWhile(/[\w\\\-_%.{:\/]/);
-        return ret("string", "string");
-      } else if(stream.peek() == "<" || stream.peek() == ">" || stream.peek() == "+"){
-        if(type === "(" && (stream.current() === "n" || stream.current() === "-n"))return ret("string", stream.current());
-        return ret("tag", "tag");
-      } else if( /\(/.test(stream.peek()) ){
-        if(stream.current() === "when")return ret("variable","variable");
-        else if(state.stack[state.stack.length-1] === "@media" && stream.current() === "and")return ret("variable",stream.current());
-        return ret(null, ch);
-      } else if (stream.peek() == "/" && state.stack[state.stack.length-1] !== undefined){ // url(dir/center/image.png)
-        if(stream.peek() === "/")stream.eatWhile(/[\w\\\-_%.{:\/]/);
-        return ret("string", stream.current());
-      } else if( stream.current().match(/\-\d|\-.\d/) ){ // match e.g.: -5px -0.4 etc... only colorize the minus sign
-        //commment out these 2 comment if you want the minus sign to be parsed as null -500px
-        //stream.backUp(stream.current().length-1);
-        //return ret(null, ch);
-        return ret("number", "unit");
-      } else if( /\/|[\s\)]/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == "/")) && stream.current().indexOf(".") !== -1){
-        if(stream.current().substring(stream.current().length-1,stream.current().length) == "{"){
-          stream.backUp(1);
-          return ret("tag", "tag");
-        }//end if
-        stream.eatSpace();
-        if( /[{<>.a-zA-Z\/]/.test(stream.peek())  || stream.eol() )return ret("tag", "tag"); // e.g. button.icon-plus
-        return ret("string", "string"); // let url(/images/logo.png) without quotes return as string
-      } else if( stream.eol() || stream.peek() == "[" || stream.peek() == "#" || type == "tag" ){
-
-        if(stream.current().substring(stream.current().length-1,stream.current().length) == "{")stream.backUp(1);
-        else if(state.stack[state.stack.length-1] === "border-color" || state.stack[state.stack.length-1] === "background-position" || state.stack[state.stack.length-1] === "font-family")return ret(null, stream.current());
-        else if(type === "tag")return ret("tag", "tag");
-        else if((type === ":" || type === "unit") && state.stack[state.stack.length-1] === "rule")return ret(null, stream.current());
-        else if(state.stack[state.stack.length-1] === "rule" && type === "tag")return ret("string", stream.current());
-        else if(state.stack[state.stack.length-1] === ";" && type === ":")return ret(null, stream.current());
-        //else if(state.stack[state.stack.length-1] === ";" || type === "")return ret("variable", stream.current());
-        else if(stream.peek() === "#" && type !== undefined && type.match(/\+|,|tag|select\-op|}|{|;/g) === null)return ret("string", stream.current());
-        else if(type === "variable")return ret(null, stream.current());
-        else if(state.stack[state.stack.length-1] === "{" && type === "comment")return ret("variable", stream.current());
-        else if(state.stack.length === 0 && (type === ";" || type === "comment"))return ret("tag", stream.current());
-        else if((state.stack[state.stack.length-1] === "{" || type === ";") && state.stack[state.stack.length-1] !== "@media{")return ret("variable", stream.current());
-        else if(state.stack[state.stack.length-2] === "{" && state.stack[state.stack.length-1] === ";")return ret("variable", stream.current());
-
-        return ret("tag", "tag");
-      } else if(type == "compare" || type == "a" || type == "("){
-        return ret("string", "string");
-      } else if(type == "|" || stream.current() == "-" || type == "["){
-        if(type == "|" && stream.peek().match(/\]|=|\~/) !== null)return ret("number", stream.current());
-        else if(type == "|" )return ret("tag", "tag");
-        else if(type == "["){
-          stream.eatWhile(/\w\-/);
-          return ret("number", stream.current());
-        }
-        return ret(null, ch);
-      } else if((stream.peek() == ":") || ( stream.eatSpace() && stream.peek() == ":")) {
-        stream.next();
-        var t_v = stream.peek() == ":" ? true : false;
-        if(!t_v){
-          var old_pos = stream.pos;
-          var sc = stream.current().length;
-          stream.eatWhile(/[a-z\\\-]/);
-          var new_pos = stream.pos;
-          if(stream.current().substring(sc-1).match(selectors) != null){
-            stream.backUp(new_pos-(old_pos-1));
-            return ret("tag", "tag");
-          } else stream.backUp(new_pos-(old_pos-1));
-        } else {
-          stream.backUp(1);
-        }
-        if(t_v)return ret("tag", "tag"); else return ret("variable", "variable");
-      } else if(state.stack[state.stack.length-1]  === "font-family" || state.stack[state.stack.length-1]  === "background-position" || state.stack[state.stack.length-1]  === "border-color"){
-        return ret(null, null);
-      } else {
-
-        if(state.stack[state.stack.length-1] === null && type === ":")return ret(null, stream.current());
-
-        //else if((type === ")" && state.stack[state.stack.length-1] === "rule") || (state.stack[state.stack.length-2] === "{" && state.stack[state.stack.length-1] === "rule" && type === "variable"))return ret(null, stream.current());
-
-        else if(/\^|\$/.test(stream.current()) && stream.peek().match(/\~|=/) !== null)return ret("string", "string");//att^=val
-
-        else if(type === "unit" && state.stack[state.stack.length-1] === "rule")return ret(null, "unit");
-        else if(type === "unit" && state.stack[state.stack.length-1] === ";")return ret(null, "unit");
-        else if(type === ")" && state.stack[state.stack.length-1] === "rule")return ret(null, "unit");
-        else if(type && type.match("@") !== null  && state.stack[state.stack.length-1] === "rule")return ret(null, "unit");
-        //else if(type === "unit" && state.stack[state.stack.length-1] === "rule")return ret(null, stream.current());
-
-        else if((type === ";" || type === "}" || type === ",") && state.stack[state.stack.length-1] === ";")return ret("tag", stream.current());
-        else if((type === ";" && stream.peek() !== undefined && stream.peek().match(/{|./) === null) || (type === ";" && stream.eatSpace() && stream.peek().match(/{|./) === null))return ret("variable", stream.current());
-        else if((type === "@media" && state.stack[state.stack.length-1] === "@media") || type === "@namespace")return ret("tag", stream.current());
-
-        else if(type === "{"  && state.stack[state.stack.length-1] === ";" && stream.peek() === "{")return ret("tag", "tag");
-        else if((type === "{" || type === ":") && state.stack[state.stack.length-1] === ";")return ret(null, stream.current());
-        else if((state.stack[state.stack.length-1] === "{" && stream.eatSpace() && stream.peek().match(/.|#/) === null) || type === "select-op"  || (state.stack[state.stack.length-1] === "rule" && type === ",") )return ret("tag", "tag");
-        else if(type === "variable" && state.stack[state.stack.length-1] === "rule")return ret("tag", "tag");
-        else if((stream.eatSpace() && stream.peek() === "{") || stream.eol() || stream.peek() === "{")return ret("tag", "tag");
-        //this one messes up indentation
-        //else if((type === "}" && stream.peek() !== ":") || (type === "}" && stream.eatSpace() && stream.peek() !== ":"))return(type, "tag");
-
-        else if(type === ")" && (stream.current() == "and" || stream.current() == "and "))return ret("variable", "variable");
-        else if(type === ")" && (stream.current() == "when" || stream.current() == "when "))return ret("variable", "variable");
-        else if(type === ")" || type === "comment" || type === "{")return ret("tag", "tag");
-        else if(stream.sol())return ret("tag", "tag");
-        else if((stream.eatSpace() && stream.peek() === "#") || stream.peek() === "#")return ret("tag", "tag");
-        else if(state.stack.length === 0)return ret("tag", "tag");
-        else if(type === ";" && stream.peek() !== undefined && stream.peek().match(/^[.|\#]/g) !== null)return ret("tag", "tag");
-
-        else if(type === ":"){stream.eatSpace();return ret(null, stream.current());}
-
-        else if(stream.current() === "and " || stream.current() === "and")return ret("variable", stream.current());
-        else if(type === ";" && state.stack[state.stack.length-1] === "{")return ret("variable", stream.current());
-
-        else if(state.stack[state.stack.length-1] === "rule")return ret(null, stream.current());
-
-        return ret("tag", stream.current());
-      }
-    }
-  }
-
-  function tokenSComment(stream, state) { // SComment = Slash comment
-    stream.skipToEnd();
-    state.tokenize = tokenBase;
-    return ret("comment", "comment");
-  }
-
-  function tokenCComment(stream, state) {
-    var maybeEnd = false, ch;
-    while ((ch = stream.next()) != null) {
-      if (maybeEnd && ch == "/") {
-        state.tokenize = tokenBase;
-        break;
-      }
-      maybeEnd = (ch == "*");
-    }
-    return ret("comment", "comment");
-  }
-
-  function tokenSGMLComment(stream, state) {
-    var dashes = 0, ch;
-    while ((ch = stream.next()) != null) {
-      if (dashes >= 2 && ch == ">") {
-        state.tokenize = tokenBase;
-        break;
-      }
-      dashes = (ch == "-") ? dashes + 1 : 0;
-    }
-    return ret("comment", "comment");
-  }
-
-  function tokenString(quote) {
-    return function(stream, state) {
-      var escaped = false, ch;
-      while ((ch = stream.next()) != null) {
-        if (ch == quote && !escaped)
-          break;
-        escaped = !escaped && ch == "\\";
-      }
-      if (!escaped) state.tokenize = tokenBase;
-      return ret("string", "string");
-    };
-  }
-
-  return {
-    startState: function(base) {
-      return {tokenize: tokenBase,
-              baseIndent: base || 0,
-              stack: []};
-    },
-
-    token: function(stream, state) {
-      if (stream.eatSpace()) return null;
-      var style = state.tokenize(stream, state);
-
-      var context = state.stack[state.stack.length-1];
-      if (type == "hash" && context == "rule") style = "atom";
-      else if (style == "variable") {
-        if (context == "rule") style = null; //"tag"
-        else if (!context || context == "@media{") {
-          style = stream.current() == "when"  ? "variable" :
-          /[\s,|\s\)|\s]/.test(stream.peek()) ? "tag"      : type;
-        }
-      }
-
-      if (context == "rule" && /^[\{\};]$/.test(type))
-        state.stack.pop();
-      if (type == "{") {
-        if (context == "@media") state.stack[state.stack.length-1] = "@media{";
-        else state.stack.push("{");
-      }
-      else if (type == "}") state.stack.pop();
-      else if (type == "@media") state.stack.push("@media");
-      else if (stream.current() === "font-family") state.stack[state.stack.length-1] = "font-family";
-      else if (stream.current() === "background-position") state.stack[state.stack.length-1] = "background-position";
-      else if (stream.current() === "border-color") state.stack[state.stack.length-1] = "border-color";
-      else if (context == "{" && type != "comment" && type !== "tag") state.stack.push("rule");
-      else if (stream.peek() === ":" && stream.current().match(/@|#/) === null) style = type;
-      if(type === ";" && (state.stack[state.stack.length-1] == "font-family" || state.stack[state.stack.length-1] == "background-position" || state.stack[state.stack.length-1] == "border-color"))state.stack[state.stack.length-1] = stream.current();
-      else if(type === "tag" && stream.peek() === ")" && stream.current().match(/\:/) === null){type = null; style = null;}
-      // ????
-      else if((type === "variable" && stream.peek() === ")") || (type === "variable" && stream.eatSpace() && stream.peek() === ")"))return ret(null,stream.current());
-      return style;
-    },
-
-    indent: function(state, textAfter) {
-      var n = state.stack.length;
-      if (/^\}/.test(textAfter))
-        n -= state.stack[state.stack.length-1] === "rule" ? 2 : 1;
-      else if (state.stack[state.stack.length-2] === "{")
-        n -= state.stack[state.stack.length-1] === "rule" ? 1 : 0;
-      return state.baseIndent + n * indentUnit;
-    },
-
-    electricChars: "}",
-    blockCommentStart: "/*",
-    blockCommentEnd: "*/",
-    lineComment: "//"
-  };
-});
-
-CodeMirror.defineMIME("text/x-less", "less");
-if (!CodeMirror.mimeModes.hasOwnProperty("text/css"))
-  CodeMirror.defineMIME("text/css", "less");
index 75f0938..0ad8828 100644 (file)
         // So call it to get the original start state that we will modify.
         var state = this._startState(base);
 
-        // Start the stack off like it has already parsed a rule. This causes everything
+        // Start off the state stack like it has already parsed a rule. This causes everything
         // after to be parsed as properties in a rule.
-        state.stack = ["rule"];
+        state.state = "block";
+        state.context.type = "block";
 
         return state;
     }
index 3d99cb6..840c0b3 100644 (file)
@@ -337,7 +337,7 @@ CodeMirror.extendMode("css", {
             if (content === ";")
                 return 1;
             if (content === ",") { // "a,b,c,...,z{}" rule list at top level or in @media top level and only if the line length will be large.
-                if ((!state.stack.length || state.stack.lastValue === "@media{") && state._cssPrettyPrint.lineLength > 60) {
+                if ((!state.stack || !state.stack.length || state.stack.lastValue === "@media{") && state._cssPrettyPrint.lineLength > 60) {
                     state._cssPrettyPrint.lineLength = 0;
                     return 1;
                 }
@@ -395,7 +395,7 @@ CodeMirror.extendMode("css", {
         // In order insert newlines in selector lists we need keep track of the length of the current line.
         // This isn't exact line length, only the builder knows that, but it is good enough to get an idea.
         // If we are at a top level, keep track of the current line length, otherwise we reset to 0.
-        if (!state.stack.length || state.stack.lastValue === "@media{")
+        if (!state.stack || !state.stack.length || state.stack.lastValue === "@media{")
             state._cssPrettyPrint.lineLength += content.length;
         else
             state._cssPrettyPrint.lineLength = 0;
index 1993b48..0420abb 100644 (file)
 .cm-s-default .cm-tag.cm-bracket,
 .cm-s-default .cm-atom,
 .cm-s-default .cm-keyword,
-.cm-s-default .cm-m-css.cm-tag,
+.cm-s-default .cm-m-css.cm-atom,
 .cm-s-default .cm-m-css.cm-meta,
 .cm-s-default .cm-m-css.cm-variable-3,
+.cm-s-default .cm-m-css.cm-property,
 .cm-s-default .cm-m-javascript.cm-builtin,
 .syntax-highlighted .css-keyword,
 .syntax-highlighted .css-tag,
@@ -59,7 +60,6 @@
 }
 
 .cm-s-default .cm-number,
-.cm-s-default .cm-m-css.cm-atom,
 .syntax-highlighted .css-number,
 .syntax-highlighted .javascript-number {
     color: rgb(28, 0, 207);
 .cm-s-default .cm-def,
 .cm-s-default .cm-bracket,
 .cm-s-default .cm-operator,
-.cm-s-default .cm-qualifier,
 .cm-s-default .cm-variable,
 .cm-s-default .cm-variable-2,
+.cm-s-default .cm-m-css.cm-tag,
 .cm-s-default .cm-m-css.cm-string-2,
 .cm-s-default .cm-m-css.cm-builtin,
-.cm-s-default .cm-m-css.cm-property,
+.cm-s-default .cm-m-css.cm-qualifier,
 .syntax-highlighted .css-property,
 .syntax-highlighted .css-selector,
 .syntax-highlighted .javascript-ident {