Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add support for coffeescript. Fixes #40

  • Loading branch information...
commit e1fdba9683fba0cd5c436225e9eafd87da083452 1 parent ca6164a
@ccampbell authored
View
75 demos/coffeescript.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Syntax Highlighting</title>
+<link href="../themes/blackboard.css" rel="stylesheet" type="text/css" media="screen">
+<body>
+
+ <pre><code data-language="coffeescript"># Assignment:
+number = 42
+opposite = true
+
+# Conditions:
+number = -42 if opposite
+
+# Functions:
+square = (x) -> x * x
+
+# Arrays:
+list = [1, 2, 3, 4, 5]
+
+# Objects:
+math =
+ root: Math.sqrt
+ square: square
+ cube: (x) -> x * square x
+
+# Splats:
+race = (winner, runners...) ->
+ print winner, runners
+
+# Existence:
+alert "I knew it!" if elvis?
+
+# Array comprehensions:
+cubes = (math.cube num for num in list)</code></pre>
+
+<pre><code data-language="coffeescript">class Animal
+ constructor: (@name) ->
+
+ move: (meters) ->
+ alert @name + " moved #{meters}m."
+
+class Snake extends Animal
+ move: ->
+ alert "Slithering..."
+ super 5
+
+class Horse extends Animal
+ move: ->
+ alert "Galloping..."
+ super 45
+
+sam = new Snake "Sammy the Python"
+tom = new Horse "Tommy the Palomino"
+
+sam.move()
+tom.move()</code></pre>
+<pre><code data-language="coffeescript">weatherReport = (location) ->
+ # Make an Ajax request to fetch the weather...
+ [location, 72, "Mostly Sunny"]
+
+[city, temp, forecast] = weatherReport "Berkeley, CA"</code></pre>
+
+<pre><code data-language="coffeescript">fs = require 'fs'
+
+option '-o', '--output [DIR]', 'directory for compiled code'
+
+task 'build:parser', 'rebuild the Jison parser', (options) ->
+ require 'jison'
+ code = require('./lib/grammar').parser.generate()
+ dir = options.output or 'lib'
+ fs.writeFile "#{dir}/parser.js", code</code></pre>
+ <script src="../js/rainbow.js"></script>
+ <script src="../js/language/generic.js"></script>
+ <script src="../js/language/coffeescript.js"></script>
+</body>
View
125 js/language/coffeescript.js
@@ -0,0 +1,125 @@
+/**
+ * Coffeescript patterns
+ *
+ * @author Craig Campbell
+ * @version 1.0
+ */
+Rainbow.extend('coffeescript', [
+ {
+ 'name': 'comment.block',
+ 'pattern': /(\#{3})[\s\S]*\1/gm
+ },
+ {
+ 'name': 'string.block',
+ 'pattern': /('{3}|"{3})[\s\S]*\1/gm
+ },
+
+ /**
+ * multiline regex with comments
+ */
+ {
+ 'name': 'string.regex',
+ 'matches': {
+ 2: {
+ 'name': 'comment',
+ 'pattern': /\#(.*?)\n/g
+ }
+ },
+ 'pattern': /(\/{3})([\s\S]*)\1/gm
+ },
+ {
+ 'matches': {
+ 1: 'keyword'
+ },
+ 'pattern': /\b(in|when|is|isnt|of|not|unless|until|super)(?=\b)/gi
+ },
+ {
+ 'name': 'keyword.operator',
+ 'pattern': /\?/g
+ },
+ {
+ 'name': 'constant.language',
+ 'pattern': /\b(undefined|yes|on|no|off)\b/g
+ },
+ {
+ 'name': 'keyword.variable.coffee',
+ 'pattern': /@(\w+)/gi
+ },
+
+ /**
+ * reset global keywards from generic
+ */
+ {
+ 'name': 'reset',
+ 'pattern': /object|class|print/gi
+ },
+
+ /**
+ * named function
+ */
+ {
+ 'matches' : {
+ 1: 'entity.name.function',
+ 2: 'keyword.operator',
+ 3: {
+ 'name': 'function.argument.coffee',
+ 'pattern': /([\@\w]+)/g
+ },
+ 4: 'keyword.function'
+ },
+ 'pattern': /(\w+)\s{0,}(=|:)\s{0,}\((.*?)((-|=)&gt;)/gi
+ },
+
+ /**
+ * anonymous function
+ */
+ {
+ 'matches': {
+ 1: {
+ 'name': 'function.argument.coffee',
+ 'pattern': /([\@\w]+)/g
+ },
+ 2: 'keyword.function'
+ },
+ 'pattern': /\s\((.*?)\)\s{0,}((-|=)&gt;)/gi
+ },
+
+ /**
+ * direct function no arguments
+ */
+ {
+ 'matches' : {
+ 1: 'entity.name.function',
+ 2: 'keyword.operator',
+ 3: 'keyword.function'
+ },
+ 'pattern': /(\w+)\s{0,}(=|:)\s{0,}((-|=)&gt;)/gi
+ },
+
+ /**
+ * class definitions
+ */
+ {
+ 'matches': {
+ 1: 'storage.class',
+ 2: 'entity.name.class',
+ 3: 'storage.modifier.extends',
+ 4: 'entity.other.inherited-class'
+ },
+ 'pattern': /\b(class)\s(\w+)(\sextends\s)?([\w\\]*)?\b/g
+ },
+
+ /**
+ * object instantiation
+ */
+ {
+ 'matches': {
+ 1: 'keyword.new',
+ 2: {
+ 'name': 'support.class',
+ 'pattern': /\w+/g
+ }
+ },
+ 'pattern': /\b(new)\s(.*?)(?=\s)/g
+ }
+]);
View
1  tests/index.html
@@ -11,6 +11,7 @@
<select multiple name="languages">
<option selected value="csharp">csharp</option>
<option selected value="css">css</option>
+ <option selected value="coffeescript">coffeescript</option>
<option selected value="generic">generic</option>
<option selected value="html">html</option>
<option selected value="java">java</option>
View
230 tests/language/coffeescript-test.js
@@ -0,0 +1,230 @@
+/**
+ * css tests
+ *
+ * @author Craig Campbell
+ */
+RainbowTester.startTest('coffeescript');
+
+RainbowTester.run(
+ 'comment',
+
+ '# this is a comment',
+
+ '<span class="comment"># this is a comment</span>'
+);
+
+RainbowTester.run(
+ 'block comment',
+
+ '###\n' +
+ 'CoffeeScript Compiler v1.3.3\n' +
+ 'Released under the MIT License\n' +
+ '###',
+
+ '<span class="comment block">###\n' +
+ 'CoffeeScript Compiler v1.3.3\n' +
+ 'Released under the MIT License\n' +
+ '###</span>'
+);
+
+RainbowTester.run(
+ 'string',
+
+ 'test = "this is a string"',
+
+ 'test <span class="keyword operator">=</span> <span class="string">"this is a string"</span>'
+);
+
+RainbowTester.run(
+ 'block string',
+
+ 'html = """\n' +
+ ' <strong>\n' +
+ ' cup of coffeescript\n' +
+ ' </strong>\n' +
+ ' """',
+
+ 'html <span class="keyword operator">=</span> <span class="string block">"""\n' +
+ ' &lt;strong&gt;\n' +
+ ' cup of coffeescript\n' +
+ ' &lt;/strong&gt;\n' +
+ ' """</span>'
+);
+
+RainbowTester.run(
+ 'function call',
+
+ 'square = (x) -> x * x',
+
+ '<span class="entity name function">square</span> <span class="keyword operator">=</span> (<span class="function argument coffee">x</span>) <span class="keyword function">-&gt;</span> x <span class="keyword operator">*</span> x'
+);
+
+RainbowTester.run(
+ 'function call inside object',
+
+ 'math =\n' +
+ ' root: Math.sqrt\n' +
+ ' square: square\n' +
+ ' cube: (x) -> x * square x',
+
+ 'math <span class="keyword operator">=</span>\n' +
+ ' root: Math.sqrt\n' +
+ ' square: square\n' +
+ ' <span class="entity name function">cube</span><span class="keyword operator">:</span> (<span class="function argument coffee">x</span>) <span class="keyword function">-&gt;</span> x <span class="keyword operator">*</span> square x'
+);
+
+RainbowTester.run(
+ 'function call multiple arguments',
+
+ 'race = (winner, runners...) ->\n' +
+ ' print winner, runners',
+
+ '<span class="entity name function">race</span> <span class="keyword operator">=</span> (<span class="function argument coffee">winner</span>, <span class="function argument coffee">runners</span>...) <span class="keyword function">-&gt;</span>\n' +
+ ' <span class="reset">print</span> winner, runners'
+);
+
+RainbowTester.run(
+ 'switch statement',
+
+ 'switch day\n' +
+ ' when "Mon" then go work\n' +
+ ' when "Tue" then go relax\n' +
+ ' when "Thu" then go iceFishing\n' +
+ ' when "Fri", "Sat"\n' +
+ ' if day is bingoDay\n' +
+ ' go bingo\n' +
+ ' go dancing\n' +
+ ' when "Sun" then go church\n' +
+ 'else go work',
+
+ '<span class="keyword">switch</span> day\n' +
+ ' <span class="keyword">when</span> <span class="string">"Mon"</span> <span class="keyword">then</span> go work\n' +
+ ' <span class="keyword">when</span> <span class="string">"Tue"</span> <span class="keyword">then</span> go relax\n' +
+ ' <span class="keyword">when</span> <span class="string">"Thu"</span> <span class="keyword">then</span> go iceFishing\n' +
+ ' <span class="keyword">when</span> <span class="string">"Fri"</span>, <span class="string">"Sat"</span>\n' +
+ ' <span class="keyword">if</span> day <span class="keyword">is</span> bingoDay\n' +
+ ' go bingo\n' +
+ ' go dancing\n' +
+ ' <span class="keyword">when</span> <span class="string">"Sun"</span> <span class="keyword">then</span> go church\n' +
+ '<span class="keyword">else</span> go work'
+);
+
+RainbowTester.run(
+ 'multiline regex',
+
+ 'OPERATOR = /// ^ (\n' +
+ ' ?: [-=]> # function\n' +
+ ' | [-+*/%<>&|^!?=]= # compound assign / compare\n' +
+ ' | >>>=? # zero-fill right shift\n' +
+ ' | ([-+:])\\1 # doubles\n' +
+ ' | ([&|<>])\\2=? # logic / shift\n' +
+ ' | \\?\\. # soak access\n' +
+ ' | \\.{2,3} # range or splat\n' +
+ ') ///',
+
+ 'OPERATOR <span class="keyword operator">=</span> <span class="string regex">/// ^ (\n' +
+ ' ?: [-=]&gt; <span class="comment"># function\n' +
+ '</span> | [-+*/%&lt;&gt;&amp;|^!?=]= <span class="comment"># compound assign / compare\n' +
+ '</span> | &gt;&gt;&gt;=? <span class="comment"># zero-fill right shift\n' +
+ '</span> | ([-+:])\\1 <span class="comment"># doubles\n' +
+ '</span> | ([&amp;|&lt;&gt;])\\2=? <span class="comment"># logic / shift\n' +
+ '</span> | \\?\\. <span class="comment"># soak access\n' +
+ '</span> | \\.{2,3} <span class="comment"># range or splat\n' +
+ '</span>) ///</span>'
+);
+
+RainbowTester.run(
+ 'function inside function call',
+
+ "task 'build:parser', 'rebuild the Jison parser', (options) ->\n" +
+ " require 'jison'\n" +
+ " code = require('./lib/grammar').parser.generate()\n" +
+ " dir = options.output or 'lib'\n" +
+ " fs.writeFile \"#{dir}/parser.js\", code",
+
+ 'task <span class="string">\'build:parser\'</span>, <span class="string">\'rebuild the Jison parser\'</span>, (<span class="function argument coffee">options</span>) <span class="keyword function">-&gt;</span>\n' +
+ ' require <span class="string">\'jison\'</span>\n' +
+ ' code <span class="keyword operator">=</span> <span class="function call">require</span>(<span class="string">\'./lib/grammar\'</span>).parser.<span class="function call">generate</span>()\n' +
+ ' dir <span class="keyword operator">=</span> options.output <span class="keyword">or</span> <span class="string">\'lib\'</span>\n' +
+ ' fs.writeFile <span class="string">"#{dir}/parser.js"</span>, code'
+);
+
+RainbowTester.run(
+ 'multiline function',
+
+ 'weatherReport = (location) ->\n' +
+ ' # Make an Ajax request to fetch the weather...\n' +
+ ' [location, 72, "Mostly Sunny"]\n' +
+ '\n' +
+ ' [city, temp, forecast] = weatherReport "Berkeley, CA"',
+
+ '<span class="entity name function">weatherReport</span> <span class="keyword operator">=</span> (<span class="function argument coffee">location</span>) <span class="keyword function">-&gt;</span>\n' +
+ ' <span class="comment"># Make an Ajax request to fetch the weather...</span>\n' +
+ ' [location, <span class="constant numeric">72</span>, <span class="string">"Mostly Sunny"</span>]\n' +
+ '\n' +
+ ' [city, temp, forecast] <span class="keyword operator">=</span> weatherReport <span class="string">"Berkeley, CA"</span>'
+);
+
+RainbowTester.run(
+ 'function binding',
+
+ 'Account = (customer, cart) ->\n' +
+ ' @customer = customer\n' +
+ ' @cart = cart\n' +
+ '\n' +
+ ' $(\'.shopping_cart\').bind \'click\', (event) =>\n' +
+ ' @customer.purchase @cart',
+
+ '<span class="entity name function">Account</span> <span class="keyword operator">=</span> (<span class="function argument coffee">customer</span>, <span class="function argument coffee">cart</span>) <span class="keyword function">-&gt;</span>\n' +
+ ' <span class="keyword variable coffee">@customer</span> <span class="keyword operator">=</span> customer\n' +
+ ' <span class="keyword variable coffee">@cart</span> <span class="keyword operator">=</span> cart\n' +
+ '\n' +
+ ' $(<span class="string">\'.shopping_cart\'</span>).bind <span class="string">\'click\'</span>, (<span class="function argument coffee">event</span>) <span class="keyword function">=&gt;</span>\n' +
+ ' <span class="keyword variable coffee">@customer</span>.purchase <span class="keyword variable coffee">@cart</span>'
+);
+
+RainbowTester.run(
+ 'direct function call',
+
+ 'move: ->\n' +
+ ' alert "Galloping..."\n' +
+ ' super 45',
+
+ '<span class="entity name function">move</span><span class="keyword operator">:</span> <span class="keyword function">-&gt;</span>\n' +
+ ' alert <span class="string">"Galloping..."</span>\n' +
+ ' <span class="keyword">super</span> <span class="constant numeric">45</span>'
+);
+
+RainbowTester.run(
+ '@ keyword',
+
+ 'alert @name + " moved #{meters}m."',
+
+ 'alert <span class="keyword variable coffee">@name</span> <span class="keyword operator">+</span> <span class="string">" moved #{meters}m."</span>'
+);
+
+RainbowTester.run(
+ 'class definition',
+
+ 'class Animal',
+
+ '<span class="storage class">class</span> <span class="entity name class">Animal</span>'
+);
+
+RainbowTester.run(
+ 'child class definition',
+
+ 'class Snake extends Animal',
+
+ '<span class="storage class">class</span> <span class="entity name class">Snake</span><span class="storage modifier extends"> extends </span><span class="entity other inherited-class">Animal</span>'
+);
+
+RainbowTester.run(
+ 'class instantiation',
+
+ 'sam = new Snake "Sammy the Python"',
+
+ 'sam <span class="keyword operator">=</span> <span class="keyword new">new</span> <span class="support class">Snake</span> <span class="string">"Sammy the Python"</span>'
+);
+
+RainbowTester.endTest('css');
View
1  util/builder.py
@@ -15,6 +15,7 @@ def __init__(self, js_path, closure_path, theme_path=None):
self.versions = {
'c': '1.0.6',
'csharp': '1.0.1',
+ 'coffeescript': '1.0',
'css': '1.0.7',
'generic': '1.0.9',
'html': '1.0.6',
Please sign in to comment.
Something went wrong with that request. Please try again.