diff --git a/mode/css/css.js b/mode/css/css.js index 7fcf335d30c83a14125858aab84e08848a0569e9..512bb29de616ac77187a6fac4658a8147f0b344c 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -28,7 +28,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) { counterDescriptors = parserConfig.counterDescriptors || {}, colorKeywords = parserConfig.colorKeywords || {}, valueKeywords = parserConfig.valueKeywords || {}, - allowNested = parserConfig.allowNested; + allowNested = parserConfig.allowNested, + supportsAtComponent = (typeof parserConfig.supportsAtComponent != "undefined" ? + parserConfig.supportsAtComponent : false); var type, override; function ret(style, tp) { type = tp; return style; } @@ -127,6 +129,11 @@ CodeMirror.defineMode("css", function(config, parserConfig) { return type; } + function pushContextNoIndent(state, stream, type) { + state.context = new Context(type, stream.indentation(), state.context); + return type; + } + function popContext(state) { state.context = state.context.prev; return state.context.type; @@ -160,6 +167,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) { return pushContext(state, stream, "block"); } else if (type == "}" && state.context.prev) { return popContext(state); + } else if (supportsAtComponent && /@component/.test(type)) { + return pushContext(state, stream, "atComponentBlock"); } else if (/@(media|supports|(-moz-)?document)/.test(type)) { return pushContext(state, stream, "atBlock"); } else if (/@(font-face|counter-style)/.test(type)) { @@ -286,6 +295,18 @@ CodeMirror.defineMode("css", function(config, parserConfig) { return state.context.type; }; + states.atComponentBlock = function(type, stream, state) { + if (type == "}") return popAndPass(type, stream, state); + if (type == "{") { + return popContext(state) && pushContextNoIndent(state, stream, allowNested ? "block" : "top"); + } + + if (type == "word") { + override = "error"; + } + return state.context.type; + }; + states.atBlock_parens = function(type, stream, state) { if (type == ")") return popContext(state); if (type == "{" || type == "}") return popAndPass(type, stream, state, 2); @@ -769,4 +790,26 @@ CodeMirror.defineMode("css", function(config, parserConfig) { helperType: "less" }); + CodeMirror.defineMIME("text/x-gss", { + documentTypes: documentTypes, + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + fontProperties: fontProperties, + counterDescriptors: counterDescriptors, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + supportsAtComponent: true, + tokenHooks: { + "/": function(stream, state) { + if (!stream.eat("*")) return false; + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } + }, + name: "css", + helperType: "gss" + }); + }); diff --git a/mode/css/gss.html b/mode/css/gss.html new file mode 100644 index 0000000000000000000000000000000000000000..232fe8c12b4f250f1e672feb5b4f6ee48041c732 --- /dev/null +++ b/mode/css/gss.html @@ -0,0 +1,103 @@ +<!doctype html> + +<title>CodeMirror: Closure Stylesheets (GSS) mode</title> +<meta charset="utf-8"/> +<link rel=stylesheet href="../../doc/docs.css"> + +<link rel="stylesheet" href="../../lib/codemirror.css"> +<link rel="stylesheet" href="../../addon/hint/show-hint.css"> +<script src="../../lib/codemirror.js"></script> +<script src="css.js"></script> +<script src="../../addon/hint/show-hint.js"></script> +<script src="../../addon/hint/css-hint.js"></script> +<style>.CodeMirror {background: #f8f8f8;}</style> +<div id=nav> + <a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a> + + <ul> + <li><a href="../../index.html">Home</a> + <li><a href="../../doc/manual.html">Manual</a> + <li><a href="https://github.com/codemirror/codemirror">Code</a> + </ul> + <ul> + <li><a href="../index.html">Language modes</a> + <li><a class=active href="#">Closure Stylesheets (GSS)</a> + </ul> +</div> + +<article> +<h2>Closure Stylesheets (GSS) mode</h2> +<form><textarea id="code" name="code"> +/* Some example Closure Stylesheets */ + +@provide 'some.styles'; + +@require 'other.styles'; + +@component { + +@def FONT_FAMILY "Times New Roman", Georgia, Serif; +@def FONT_SIZE_NORMAL 15px; +@def FONT_NORMAL normal FONT_SIZE_NORMAL FONT_FAMILY; + +@def BG_COLOR rgb(235, 239, 249); + +@def DIALOG_BORDER_COLOR rgb(107, 144, 218); +@def DIALOG_BG_COLOR BG_COLOR; + +@def LEFT_HAND_NAV_WIDTH 180px; +@def LEFT_HAND_NAV_PADDING 3px; + +@defmixin size(WIDTH, HEIGHT) { + width: WIDTH; + height: HEIGHT; +} + +body { + background-color: BG_COLOR; + margin: 0; + padding: 3em 6em; + font: FONT_NORMAL; + color: #000; +} + +#navigation a { + font-weight: bold; + text-decoration: none !important; +} + +.dialog { + background-color: DIALOG_BG_COLOR; + border: 1px solid DIALOG_BORDER_COLOR; +} + +.content { + position: absolute; + margin-left: add(LEFT_HAND_NAV_PADDING, /* padding left */ + LEFT_HAND_NAV_WIDTH, + LEFT_HAND_NAV_PADDING); /* padding right */ + +} + +.logo { + @mixin size(150px, 55px); + background-image: url('http://www.google.com/images/logo_sm.gif'); +} + +} +</textarea></form> + <script> + var editor = CodeMirror.fromTextArea(document.getElementById("code"), { + extraKeys: {"Ctrl-Space": "autocomplete"}, + lineNumbers: true, + matchBrackets: "text/x-less", + mode: "text/x-gss" + }); + </script> + + <p>A mode for <a href="https://github.com/google/closure-stylesheets">Closure Stylesheets</a> (GSS).</p> + <p><strong>MIME type defined:</strong> <code>text/x-gss</code>.</p> + + <p><strong>Parsing/Highlighting Tests:</strong> <a href="../../test/index.html#gss_*">normal</a>, <a href="../../test/index.html#verbose,gss_*">verbose</a>.</p> + + </article> diff --git a/mode/css/gss_test.js b/mode/css/gss_test.js new file mode 100644 index 0000000000000000000000000000000000000000..e1a330652e5b657e5b4d1f188ca5dd7a645444cd --- /dev/null +++ b/mode/css/gss_test.js @@ -0,0 +1,17 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + "use strict"; + + var mode = CodeMirror.getMode({indentUnit: 2}, "gss"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "gss"); } + + MT("atComponent", + "[def @component] {", + "[tag foo] {", + " [property color]: [keyword black];", + "}", + "}"); + +})(); diff --git a/mode/css/test.js b/mode/css/test.js index cda07748b25ee758dde5eab73c3b9314f2b52826..7d78135de494acd814e4c675f01dad3e80b8f6bd 100644 --- a/mode/css/test.js +++ b/mode/css/test.js @@ -6,7 +6,7 @@ function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } // Error, because "foobarhello" is neither a known type or property, but - // property was expected (after "and"), and it should be in parenthese. + // property was expected (after "and"), and it should be in parentheses. MT("atMediaUnknownType", "[def @media] [attribute screen] [keyword and] [error foobarhello] { }"); diff --git a/mode/index.html b/mode/index.html index ca1703aff9cff927ec898d6162e00d59056b75eb..9bb8beff92d3a24549b42d362d89307172d91ce1 100644 --- a/mode/index.html +++ b/mode/index.html @@ -36,6 +36,7 @@ option.</p> <li><a href="brainfuck/index.html">Brainfuck</a></li> <li><a href="clike/index.html">C, C++, C#</a></li> <li><a href="clojure/index.html">Clojure</a></li> + <li><a href="css/gss.html">Closure Stylesheets (GSS)</a></li> <li><a href="cmake/index.html">CMake</a></li> <li><a href="cobol/index.html">COBOL</a></li> <li><a href="coffeescript/index.html">CoffeeScript</a></li> diff --git a/mode/meta.js b/mode/meta.js index 376e1ecdc25e09a95e89a8c4ec83b419f2162fcb..aff0cc7c62167a84b2326e3de5325a3fd82271c7 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -22,6 +22,7 @@ {name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]}, {name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp"]}, {name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj"]}, + {name: "Closure Stylesheets (GSS)", mime: "text/x-gss", mode: "css", ext: ["gss"]}, {name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists.txt$/}, {name: "CoffeeScript", mime: "text/x-coffeescript", mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]}, {name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp", ext: ["cl", "lisp", "el"], alias: ["lisp"]}, diff --git a/test/index.html b/test/index.html index 310e88519d167b03c4045c4dae30d189226883c6..e0593e90f36fa5cd6aa791a0081907cfb7398980 100644 --- a/test/index.html +++ b/test/index.html @@ -20,6 +20,7 @@ <script src="../mode/clike/clike.js"></script> <!-- clike must be after css or vim and sublime tests will fail --> <script src="../mode/gfm/gfm.js"></script> +<script src="../mode/gss/gss.js"></script> <script src="../mode/haml/haml.js"></script> <script src="../mode/htmlmixed/htmlmixed.js"></script> <script src="../mode/javascript/javascript.js"></script> @@ -100,6 +101,7 @@ <script src="../mode/clike/test.js"></script> <script src="../mode/css/test.js"></script> + <script src="../mode/css/gss_test.js"></script> <script src="../mode/css/scss_test.js"></script> <script src="../mode/css/less_test.js"></script> <script src="../mode/gfm/test.js"></script>