# Syntax: Diff

## jQuery.Syntax Diff

    diff --git a/ex.ruby.html b/ex.ruby.html
    index a02a04e..7d42db0 100644
    --- a/ex.ruby.html
    +++ b/ex.ruby.html
    @@ -21,6 +21,8 @@
     	<body>
     		<h1>Syntax: Ruby</h1>

    +		<h2>Ruby Script #1</h2>
    +
     		<pre class="ruby">#!/usr/bin/env ruby

     # Copyright (c) 2009 Samuel Williams. Released under the GNU GPLv3.
    @@ -104,5 +106,257 @@ end
     # RExec daemon runner
     Server.daemonize</pre>

    +	<h2>Ruby Script #2</h2>
    +
    +	<pre class="ruby">#!/usr/bin/env ruby
    +# Simple Operator Expression Parser
    +
    +require &#x27;set&#x27;
    +
    +DEBUG = false
    +
    +class Array
    +  def map_to(with)
    +    r = {}
    +
    +    each_with_index { |v,i| r[v] = with[i] }
    +
    +    return r
    +  end
    +end
    +
    +module Expression
    +  class Context
    +    def initialize(operators, values)
    +      @values = values
    +      @operators = operators
    +    end
    +
    +    def value_of (key)
    +      @values[key]
    +    end
    +
    +    def call (op, args)
    +      @operators.call(op, args)
    +    end
    +  end
    +
    +  class Constant
    +    def initialize(value)
    +      @value = value
    +    end
    +
    +    def evaluate (ctx)
    +      return @value
    +    end
    +  end
    +
    +  class Identifier
    +    def initialize(name)
    +      @name = name
    +    end
    +
    +    def evaluate (ctx)
    +      ctx.value_of(@name)
    +    end
    +  end
    +
    +  class Operator
    +    def initialize(name, args = [])
    +      @name = name
    +      @args = args
    +    end
    +
    +    def name
    +      @name
    +    end
    +
    +    def evaluate (ctx)
    +      ctx.call(@name, @args.collect { |a| a.evaluate(ctx) })
    +    end
    +
    +    def args
    +      @args
    +    end
    +  end
    +
    +  class Brackets
    +    def initialize(node)
    +      @node = node
    +    end
    +
    +    def evaluate (ctx)
    +      @node.evaluate(ctx)
    +    end
    +  end
    +
    +  class Parser
    +    def initialize(ops, expr)
    +      @identifiers = []
    +      @operators = ops
    +
    +      # Tokens and expressions line up
    +      @expressions = []
    +      @tokens = []
    +
    +      @top = nil
    +
    +      parse(expr)
    +    end
    +
    +    def evaluate (ctx)
    +      @expressions.collect do |expr|
    +        expr != nil ? expr.evaluate(ctx) : nil
    +      end
    +    end
    +
    +    def identifiers
    +      @identifiers
    +    end
    +
    +    def tokens
    +      @tokens
    +    end
    +  private
    +    def parse(expr)
    +      symbols = @operators.keys + [&quot;(&quot;, &quot;)&quot;]
    +      tokenizer = Regexp.union(Regexp.union(*symbols), /[A-Z]+/)
    +
    +      @tokens = expr.scan(tokenizer)
    +      @expressions = [nil] * @tokens.size
    +
    +      @identifiers = Set.new(expr.scan(/[A-Z]+/))
    +
    +      @top, i = process_expression
    +
    +      if DEBUG
    +        puts &quot;Processed #{i} tokens...&quot;
    +        puts &quot;Tokens: &quot; + @tokens.join(&quot; &quot;)
    +        puts @top.inspect
    +        puts @expressions.inspect
    +      end
    +    end
    +
    +    def process_expression(i = 0)
    +      ast = []
    +      ops = {}
    +      while i &lt; @tokens.size
    +        t = @tokens[i]
    +
    +        if t == &quot;(&quot;
    +          result, i = process_expression(i+1)
    +          ast += result
    +        elsif t == &quot;)&quot;
    +          break
    +        else
    +          result = process_token(i)
    +          ast &lt;&lt; result
    +        end
    +
    +        if result.class == Operator
    +          ops[result.name] ||= []
    +          # Store the index
    +          ops[result.name] &lt;&lt; (ast.size - 1)
    +        end
    +
    +        i += 1
    +      end
    +
    +      #puts ast.inspect
    +
    +      # We need to sort the list of operators now
    +      # [c, infix, prefix, c]
    +
    +      @operators.order.each do |name|
    +        op_kind = @operators.kind(name)
    +        next unless ops[name]
    +
    +        ops[name].each do |loc|
    +          op = ast[loc]
    +
    +          if op_kind == :prefix
    +            rhs = find_subexpression(ast, loc, RHS_SEARCH)
    +            op.args &lt;&lt; ast[rhs]
    +            ast[rhs] = nil
    +          elsif op_kind == :infix
    +            lhs = find_subexpression(ast, loc, LHS_SEARCH)
    +            rhs = find_subexpression(ast, loc, RHS_SEARCH)
    +            op.args &lt;&lt; ast[lhs]
    +            op.args &lt;&lt; ast[rhs]
    +            ast[lhs] = ast[rhs] = nil
    +          elsif op_kind == :postfix
    +            lhs = find_subexpression(ast, loc, LHS_SEARCH)
    +            op.args &lt;&lt; ast[lhs]
    +            ast[rhs] = nil
    +          end
    +        end
    +      end
    +
    +      return [ast.uniq, i]
    +    end
    +
    +    RHS_SEARCH = 1
    +    LHS_SEARCH = -1
    +
    +    def find_subexpression(ast, loc, dir)
    +      while loc &gt;= 0 &amp;&amp; loc &lt; ast.size
    +        loc += dir
    +        return loc if ast[loc] != nil
    +      end
    +
    +      return nil
    +    end
    +
    +    def process_token(i)
    +      t = @tokens[i]
    +
    +      if @operators.key? t
    +        tok = Operator.new(t)
    +      elsif t.match /[A-Z]+/
    +        tok = Identifier.new(t)
    +      else
    +        tok = Constant.new(t)
    +      end
    +
    +      @expressions[i] = tok
    +      return tok
    +    end
    +  end
    +
    +  TYPE = 0
    +  FUNC = 1
    +  class Operators
    +    def initialize
    +      @operators = {}
    +      @order = []
    +    end
    +
    +    def add(sym, kind, &amp;block)
    +      @operators[sym] = [kind, block]
    +      @order &lt;&lt; sym
    +    end
    +
    +    def order
    +      @order
    +    end
    +
    +    def keys
    +      @operators.keys
    +    end
    +
    +    def key? k
    +      @operators.key? k
    +    end
    +
    +    def kind k
    +      @operators[k][0]
    +    end
    +
    +    def call(k, args)
    +      @operators[k][1].call(*args)
    +    end
    +  end
    +end</pre>
    +
     	</body>
     </html>
    \ No newline at end of file
    diff --git a/example.css b/example.css
    index e69de29..4ece63a 100644
    --- a/example.css
    +++ b/example.css
    @@ -0,0 +1,3 @@
    +body {
    +	font-size: 70%;
    +}
    \ No newline at end of file
    diff --git a/example.html b/example.html
    deleted file mode 100644
    index 7ac7cd5..0000000
    --- a/example.html
    +++ /dev/null
    @@ -1,46 +0,0 @@
    -<!DOCTYPE html>
    -<html>
    -	<head>
    -
    -		<link rel="stylesheet" href="jquery.syntax.css" type="text/css" media="screen" />
    -		<link rel="stylesheet" href="example.css" type="text/css" media="screen" />
    -
    -		<script src="jquery-1.4.1.js" type="text/javascript" charset="utf-8"></script>
    -
    -		<script src="jquery.syntax.js" type="text/javascript" charset="utf-8"></script>
    -		<script src="jquery.syntax.cache.js" type="text/javascript" charset='utf-8'></script>
    -
    -		<script type="text/javascript" language="JavaScript">
    -		//<!--
    -			$(function() {
    -				$('#highlight').click(function() {
    -					$('pre.clang').syntax({brush: 'clang', layout: 'table', replace: true}, function(options, html, container) {
    -						//$('.function', html).replaceWith(function(){
    -						//	return $('<a>').addClass('function').attr('href', '#' + $(this).text()).html($(this).html());
    -						//})
    -					});
    -				});
    -			});
    -		//-->
    -		</script>
    -
    -	</head>
    -	<body>
    -		<h1>Syntax Highlighting Example</h1>
    -
    -		<button id="highlight">Highlight</button>
    -
    -		<pre class="clang">#include &lt;iostream&gt;
    -/* Multi line c comment
    -
    -	Hello World
    -*/
    -
    -	const char * s = "My name is computer!\n\n"
    -int main (int argv, char ** argv) {
    -	return EXIT_SUCCESS;
    -}
    -</pre>
    -
    -	</body>
    -</html>
    \ No newline at end of file
    diff --git a/example2.html b/example2.html
    deleted file mode 100644
    index f5f1d8c..0000000
    --- a/example2.html
    +++ /dev/null
    @@ -1,81 +0,0 @@
    -<!DOCTYPE html>
    -<html>
    -	<head>
    -
    -		<link rel="stylesheet" href="jquery.syntax.css" type="text/css" media="screen" />
    -		<link rel="stylesheet" href="example.css" type="text/css" media="screen" />
    -
    -		<script src="jquery-1.4.1.js" type="text/javascript"></script>
    -
    -		<script src="jquery.syntax.js" type="text/javascript"></script>
    -		<script src="jquery.syntax.cache.js" type="text/javascript" charset='utf-8'></script>
    -
    -		<script src="jquery.syntax.brush.clang.js" type="text/javascript"></script>
    -		<script src="jquery.syntax.layout.table.js" type="text/javascript"></script>
    -
    -		<link rel="stylesheet" href="jquery.syntax.layout.table.css" type="text/css" media="screen">
    -
    -		<script type="text/javascript" language="JavaScript">
    -		//<!--
    -			$(function() {
    -				$('#highlight').click(function() {
    -					window.console.profile("Syntax Highlighting");
    -					start = new Date();
    -
    -					$('pre.clang').syntax({brush: 'clang', layout: 'table', replace: true}, function(options, html, container) {
    -						//$('.function', html).replaceWith(function(){
    -						//	return $('<a>').addClass('function').attr('href', '#' + $(this).text()).html($(this).html());
    -						//})
    -
    -						finish = new Date();
    -						window.console.profileEnd();
    -						window.console.log(finish - start);
    -					});
    -				});
    -			});
    -		//-->
    -		</script>
    -
    -	</head>
    -	<body>
    -		<h1>Syntax Highlighting Example</h1>
    -
    -		<button id="highlight">Highlight</button>
    -
    -		<pre class="clang">#include &lt;iostream&gt;
    -
    -// If we increase row by 1, the offset will increase by sz (number of elements per row i.e. number of columns)
    -// If we increase col by 1, the offset will increase by 1
    -unsigned rowMajorOffset(unsigned row, unsigned col, unsigned sz)
    -{
    -  return col + row * sz;
    -}
    -
    -// If we increase col by 1, the offset will increase by sz (number of elements per column i.e. number of rows)
    -// If we increase row by 1, the offset will increase by 1
    -unsigned columnMajorOffset(unsigned row, unsigned col, unsigned sz)
    -{
    -  return row + col * sz;
    -}
    -
    -int main (int argc, char * const argv[]) {
    -	Matrix&lt;float, 4, 2, false&gt; rowMajorMatrix;
    -	Matrix&lt;float, 4, 2, true&gt; columnMajorMatrix;
    -
    -	rowMajorMatrix.loadTestPattern();
    -	rowMajorMatrix.debug();
    -
    -	columnMajorMatrix.loadTestPattern();
    -	columnMajorMatrix.debug();
    -
    -	rowMajorMatrix = columnMajorMatrix.transposeStorage();
    -	rowMajorMatrix.debug();
    -
    -	Matrix&lt;float, 2, 4, false&gt; transposedMatrix = columnMajorMatrix.transposeMatrix();
    -	transposedMatrix.debug();
    -
    -	return 0;
    -}</pre>
    -
    -	</body>
    -</html>
    \ No newline at end of file
    diff --git a/example3.html b/example3.html
    deleted file mode 100644
    index d559b68..0000000
    --- a/example3.html
    +++ /dev/null
    @@ -1,171 +0,0 @@
    -<!DOCTYPE html>
    -<html>
    -	<head>
    -
    -		<link rel="stylesheet" href="jquery.syntax.css" type="text/css" media="screen" />
    -		<link rel="stylesheet" href="example.css" type="text/css" media="screen" />
    -
    -		<script src="jquery-1.4.1.js" type="text/javascript"></script>
    -
    -		<script src="jquery.syntax.js" type="text/javascript"></script>
    -		<script src="jquery.syntax.cache.js" type="text/javascript" charset='utf-8'></script>
    -
    -		<script src="jquery.syntax.brush.clang.js" type="text/javascript"></script>
    -		<script src="jquery.syntax.layout.table.js" type="text/javascript"></script>
    -
    -		<link rel="stylesheet" href="jquery.syntax.layout.table.css" type="text/css" media="screen">
    -
    -		<script type="text/javascript" language="JavaScript">
    -		//<!--
    -			$(function() {
    -				$('#highlight').click(function() {
    -					window.console.profile("Syntax Highlighting");
    -					start = new Date();
    -
    -					$('pre.clang').syntax({brush: 'clang', layout: 'table', replace: true}, function(options, html, container) {
    -						//$('.function', html).replaceWith(function(){
    -						//	return $('<a>').addClass('function').attr('href', '#' + $(this).text()).html($(this).html());
    -						//})
    -
    -						finish = new Date();
    -						window.console.profileEnd();
    -						window.console.log(finish - start);
    -					});
    -				});
    -			});
    -		//-->
    -		</script>
    -
    -	</head>
    -	<body>
    -		<h1>Syntax Highlighting Example</h1>
    -
    -		<button id="highlight">Highlight</button>
    -
    -		<pre class="clang">#include &lt;iostream&gt;
    -
    -// If we increase row by 1, the offset will increase by sz (number of elements per row i.e. number of columns)
    -// If we increase col by 1, the offset will increase by 1
    -unsigned rowMajorOffset(unsigned row, unsigned col, unsigned sz)
    -{
    -    return col + row * sz;
    -}
    -
    -// If we increase col by 1, the offset will increase by sz (number of elements per column i.e. number of rows)
    -// If we increase row by 1, the offset will increase by 1
    -unsigned columnMajorOffset(unsigned row, unsigned col, unsigned sz)
    -{
    -    return row + col * sz;
    -}
    -
    -template &lt;typename _ValueT, unsigned _R, unsigned _C, bool _ColumnMajor&gt;
    -class Matrix {
    -protected:
    -	enum { ColumnMajor = _ColumnMajor };
    -	enum { R = _R };
    -	enum { C = _C };
    -
    -	typedef _ValueT ValueT;
    -
    -	ValueT m_values[C*R];
    -
    -public:
    -	const ValueT &amp; at (unsigned r, unsigned c) const
    -	{
    -		if (ColumnMajor)
    -			return m_values[columnMajorOffset(r, c, R)];
    -		else
    -			return m_values[rowMajorOffset(r, c, C)];
    -	}
    -
    -	ValueT &amp; at (unsigned r, unsigned c)
    -	{
    -		if (ColumnMajor)
    -			return m_values[columnMajorOffset(r, c, R)];
    -		else
    -			return m_values[rowMajorOffset(r, c, C)];
    -	}
    -
    -	void loadTestPattern ()
    -	{
    -		for (unsigned r = 0; r &lt; R; r += 1)
    -			for (unsigned c = 0; c &lt; C; c += 1)
    -				at(r, c) = (r+1) * 1000 + (c+1);
    -	}
    -
    -	void debug ()
    -	{
    -		using namespace std;
    -
    -		if (ColumnMajor)
    -			cout &lt;&lt; &quot;Column-Major Matrix &quot; &lt;&lt; &quot;(&quot; &lt;&lt; R &lt;&lt; &quot;,&quot; &lt;&lt; C &lt;&lt; &quot;)&quot; &lt;&lt; &quot; @ &quot; &lt;&lt; this &lt;&lt; endl;
    -		else
    -			cout &lt;&lt; &quot;Row-Major Matrix &quot; &lt;&lt; &quot;(&quot; &lt;&lt; R &lt;&lt; &quot;,&quot; &lt;&lt; C &lt;&lt; &quot;)&quot; &lt;&lt; &quot; @ &quot; &lt;&lt; this &lt;&lt; endl;
    -
    -		cout &lt;&lt; &quot;Memory Offset: &quot;;
    -		for (unsigned i = 0; i &lt; (R*C); i += 1)
    -			cout &lt;&lt; i &lt;&lt; &quot;    &quot;;
    -		cout &lt;&lt; endl;
    -
    -		cout &lt;&lt; &quot;       Values: &quot;;
    -		for (unsigned i = 0; i &lt; (R*C); i += 1)
    -			cout &lt;&lt; m_values[i] &lt;&lt; &quot; &quot;;
    -		cout &lt;&lt; endl;
    -
    -		cout &lt;&lt; &quot;Standard Mathematical Notation:&quot; &lt;&lt; endl;
    -		cout &lt;&lt; &quot;      &quot;;
    -		for (unsigned c = 0; c &lt; C; c += 1)
    -			cout &lt;&lt; &quot;Col &quot; &lt;&lt; c &lt;&lt; &quot; &quot;;
    -		cout &lt;&lt; endl;
    -
    -		for (unsigned r = 0; r &lt; R; r += 1) {
    -			cout &lt;&lt; &quot;Row &quot; &lt;&lt; r &lt;&lt; &quot; &quot;;
    -			for (unsigned c = 0; c &lt; C; c += 1)
    -				cout &lt;&lt; at(r, c) &lt;&lt; &quot;  &quot;;
    -			cout &lt;&lt; endl;
    -		}
    -		cout &lt;&lt; endl;
    -	}
    -
    -	Matrix&lt;ValueT, R, C, !ColumnMajor&gt; transposeStorage () const
    -	{
    -		Matrix&lt;ValueT, R, C, !ColumnMajor&gt; result;
    -
    -		for (unsigned r = 0; r &lt; R; r += 1)
    -			for (unsigned c = 0; c &lt; C; c += 1)
    -				result.at(r, c) = at(r, c);
    -
    -		return result;
    -	}
    -
    -	Matrix&lt;ValueT, C, R, !ColumnMajor&gt; transposeMatrix () const
    -	{
    -		Matrix&lt;ValueT, C, R, !ColumnMajor&gt; result;
    -
    -		memcpy(&amp;result.at(0,0), m_values, sizeof(m_values));
    -
    -		return result;
    -	}
    -};
    -
    -int main (int argc, char * const argv[]) {
    -	Matrix&lt;float, 4, 2, false&gt; rowMajorMatrix;
    -	Matrix&lt;float, 4, 2, true&gt; columnMajorMatrix;
    -
    -	rowMajorMatrix.loadTestPattern();
    -	rowMajorMatrix.debug();
    -
    -	columnMajorMatrix.loadTestPattern();
    -	columnMajorMatrix.debug();
    -
    -	rowMajorMatrix = columnMajorMatrix.transposeStorage();
    -	rowMajorMatrix.debug();
    -
    -	Matrix&lt;float, 2, 4, false&gt; transposedMatrix = columnMajorMatrix.transposeMatrix();
    -	transposedMatrix.debug();
    -
    -	return 0;
    -}</pre>
    -
    -	</body>
    -</html>
    \ No newline at end of file
    diff --git a/jquery.syntax.brush.clang.js b/jquery.syntax.brush.clang.js
    index dcbebbc..3c10a29 100644
    --- a/jquery.syntax.brush.clang.js
    +++ b/jquery.syntax.brush.clang.js
    @@ -1,16 +1,19 @@
     // brush: "clang" aliases: ["cpp", "c", "objective-c"]

     Syntax.register('clang', function(brush) {
    -	var keywords = ["@interface", "@implementation", "@protocol", "@end", "@private", "@protected", "@public", "@try", "@throw", "@catch", "@finally", "@class", "@selector", "@encode", "@synchronized", "struct", "break", "continue", "else", "for", "switch", "case", "default", "enum", "goto", "register", "sizeof", "typedef", "volatile", "do", "extern", "if", "return", "static", "union", "while", "asm", "dynamic_cast", "namespace", "reinterpret_cast", "try", "explicit", "static_cast", "typeid", "catch", "operator", "template", "class", "friend", "private", "using", "const_cast", "inline", "public", "throw", "virtual", "mutable", "protected", "wchar_t"];
    +	var keywords = ["@interface", "@implementation", "@protocol", "@end", "@private", "@protected", "@public", "@try", "@throw", "@catch", "@finally", "@class", "@selector", "@encode", "@synchronized", "@property", "struct", "break", "continue", "else", "for", "switch", "case", "default", "enum", "goto", "register", "sizeof", "typedef", "volatile", "do", "extern", "if", "return", "static", "union", "while", "asm", "dynamic_cast", "namespace", "reinterpret_cast", "try", "explicit", "static_cast", "typeid", "catch", "operator", "template", "class", "friend", "private", "using", "const_cast", "inline", "public", "throw", "virtual", "mutable", "protected", "wchar_t"];

    -	var types = ["auto", "const", "double", "float", "int", "short", "char", "long", "signed", "unsigned", "bool", "void", "typename"];
    -	var operators = ["+", "*", "/", "-", "&", "|", "~", "!", "%", "<", "=", ">", "new", "delete"];
    +	var types = ["auto", "const", "double", "float", "int", "short", "char", "long", "signed", "unsigned", "bool", "void", "typename", "id"];
    +	var operators = ["+", "*", "/", "-", "&", "|", "~", "!", "%", "<", "=", ">", "[", "]", "new", "delete"];
     	var values = ["this", "true", "false", /[0-9]+(\.[0-9]+)?/g];

    -	brush.push(values, {klass: 'constant', children: null});
    -	brush.push(types, {klass: 'type', children: null})
    -	brush.push(keywords, {klass: 'keyword', children: null})
    -	brush.push(operators, {klass: 'operator', children: null})
    +	brush.push(values, {klass: 'constant', children: []});
    +	brush.push(types, {klass: 'type', children: []})
    +	brush.push(keywords, {klass: 'keyword', children: []})
    +	brush.push(operators, {klass: 'operator', children: []})
    +
    +	// Objective-C classes
    +	brush.push({pattern: /\b[A-Z][\w]*\b/g, klass: 'type', children: []})

     	brush.push({
     		pattern: /#.*$/gmi,
    @@ -21,6 +24,15 @@ Syntax.register('clang', function(brush) {
     	brush.push(Syntax.lib.cStyleComment);
     	brush.push(Syntax.lib.cppStyleComment);

    +	// Objective-C style functions
    +	brush.push({pattern: /\w+:/g, klass: 'function', children: []});
    +	brush.push({
    +		pattern: /[^:\[]\s+(\w+)(?=])/g,
    +		klass: 'function',
    +		matches: Syntax.singleMatchFunction(1, {klass: 'function', children: []})
    +	})
    +
    +	// Strings
     	brush.push({pattern: /".+?"/g, klass: 'string', children: 'escape'});
     	brush.push({pattern: /\\./g, klass: 'escape'});

    diff --git a/jquery.syntax.brush.ruby.js b/jquery.syntax.brush.ruby.js
    index 71fdeaf..64a4626 100644
    --- a/jquery.syntax.brush.ruby.js
    +++ b/jquery.syntax.brush.ruby.js
    @@ -1,34 +1,30 @@
     // brush: "ruby" aliases: []

    -/*
    -	# This ruby code will generate a list of classes.
    -	classes = []
    -
    -	ObjectSpace.each_object(Class) do |c|
    -		classes << c
    -	end
    -
    -	puts classes.collect{|cls| cls.name}.inspect
    -*/
    +Syntax.lib.rubyStyleFunction = {pattern: /(?:def\s+|\.)([a-z_][a-z0-9_]+)/gi, matches: Syntax.singleMatchFunction(1, {klass: 'function', children: null})}
    +Syntax.lib.rubyStyleSymbol = {pattern: /:[\w]+/, klass: 'constant', children: null}

     Syntax.register('ruby', function(brush) {
     	var keywords = ["alias", "and", "begin", "break", "case", "class", "def", "define_method", "defined", "do", "each", "else", "elsif", "end", "ensure", "false", "for", "if", "in", "module", "new", "next", "nil", "not", "or", "raise", "redo", "rescue", "retry", "return", "self", "super", "then", "throw", "true", "undef", "unless", "until", "when", "while", "yield"];

    -	var types = ["Socket", "UNIXServer", "UNIXSocket", "UDPSocket", "TCPServer", "TCPSocket", "IPSocket", "BasicSocket", "SocketError", "Pathname", "StopIteration", "Enumerable::Enumerator", "Binding", "UnboundMethod", "Method", "Proc", "SystemStackError", "LocalJumpError", "Struct::Tms", "Process::Status", "Time", "Dir", "File::Stat", "File", "IO", "EOFError", "IOError", "Range", "MatchData", "Regexp", "RegexpError", "Struct", "Hash", "Array", "Errno::EDQUOT", "Errno::ESTALE", "Errno::EINPROGRESS", "Errno::EALREADY", "Errno::EHOSTUNREACH", "Errno::EHOSTDOWN", "Errno::ECONNREFUSED", "Errno::ETIMEDOUT", "Errno::ETOOMANYREFS", "Errno::ESHUTDOWN", "Errno::ENOTCONN", "Errno::EISCONN", "Errno::ENOBUFS", "Errno::ECONNRESET", "Errno::ECONNABORTED", "Errno::ENETRESET", "Errno::ENETUNREACH", "Errno::ENETDOWN", "Errno::EADDRNOTAVAIL", "Errno::EADDRINUSE", "Errno::EAFNOSUPPORT", "Errno::EPFNOSUPPORT", "Errno::EOPNOTSUPP", "Errno::ESOCKTNOSUPPORT", "Errno::EPROTONOSUPPORT", "Errno::ENOPROTOOPT", "Errno::EPROTOTYPE", "Errno::EMSGSIZE", "Errno::EDESTADDRREQ", "Errno::ENOTSOCK", "Errno::EUSERS", "Errno::EILSEQ", "Errno::EOVERFLOW", "Errno::EBADMSG", "Errno::EMULTIHOP", "Errno::EPROTO", "Errno::ENOLINK", "Errno::EREMOTE", "Errno::ENOSR", "Errno::ETIME", "Errno::ENODATA", "Errno::ENOSTR", "Errno::EIDRM", "Errno::ENOMSG", "Errno::ELOOP", "Errno::ENOTEMPTY", "Errno::ENOSYS", "Errno::ENOLCK", "Errno::ENAMETOOLONG", "Errno::EDEADLK", "Errno::ERANGE", "Errno::EDOM", "Errno::EPIPE", "Errno::EMLINK", "Errno::EROFS", "Errno::ESPIPE", "Errno::ENOSPC", "Errno::EFBIG", "Errno::ETXTBSY", "Errno::ENOTTY", "Errno::EMFILE", "Errno::ENFILE", "Errno::EINVAL", "Errno::EISDIR", "Errno::ENOTDIR", "Errno::ENODEV", "Errno::EXDEV", "Errno::EEXIST", "Errno::EBUSY", "Errno::ENOTBLK", "Errno::EFAULT", "Errno::EACCES", "Errno::ENOMEM", "Errno::EAGAIN", "Errno::ECHILD", "Errno::EBADF", "Errno::ENOEXEC", "Errno::E2BIG", "Errno::ENXIO", "Errno::EIO", "Errno::EINTR", "Errno::ESRCH", "Errno::ENOENT", "Errno::EPERM", "Bignum", "Float", "Fixnum", "Integer", "Numeric", "FloatDomainError", "ZeroDivisionError", "ThreadGroup", "Continuation", "Thread", "ThreadError", "SystemCallError", "NoMemoryError", "SecurityError", "RuntimeError", "NotImplementedError", "LoadError", "SyntaxError", "ScriptError", "NoMethodError", "NameError::message", "NameError", "RangeError", "IndexError", "ArgumentError", "TypeError", "StandardError", "Interrupt", "SignalException", "fatal", "SystemExit", "Exception", "String", "FalseClass", "TrueClass", "Data", "Symbol", "NilClass", "Class", "Module", "Object"];
    -
     	var operators = ["+", "*", "/", "-", "&", "|", "~", "!", "%", "<", "=", ">"];
     	var values = ["this", "true", "false", "nil", /[0-9]+(\.[0-9]+)?/g];

     	brush.push(values, {klass: 'constant', children: null});
    -	brush.push(types, {klass: 'type', children: null})
    +
    +	brush.push({pattern: /(@+|\$)[\w]+/g, klass: 'variable', children: null})
    +
    +	brush.push({pattern: /[A-Z_][\w:]+/g, klass: 'type', children: null})
     	brush.push(keywords, {klass: 'keyword', children: null})
     	brush.push(operators, {klass: 'operator', children: null})

     	brush.push(Syntax.lib.perlStyleComment)
    +	brush.push(Syntax.lib.webLink)

     	brush.push({pattern: /".+?"/g, klass: 'string', children: ['escape']});
    +	brush.push({pattern: /'.+?'/g, klass: 'string', children: ['escape']});
     	brush.push({pattern: /\\./g, klass: 'escape'});

     	brush.push(Syntax.lib.rubyStyleFunction);
    +	brush.push(Syntax.lib.cStyleFunction);
     });

    diff --git a/jquery.syntax.css b/jquery.syntax.css
    index 0c4d657..2423173 100644
    --- a/jquery.syntax.css
    +++ b/jquery.syntax.css
    @@ -14,12 +14,12 @@

     .syntax .keyword {
     	color: #3c3;
    -	font-weight: bold;
     }

     .syntax .type,
     .syntax .template {
    -	color: #3c3;
    +	color: #191;
    +	font-weight: bold;
     }

     .syntax .typename {
    @@ -44,7 +44,12 @@
     	color: #c00;
     }

    -.syntax .template {
    +.syntax .href {
    +	color: #00f;
    +	text-decoration: underline;
    +}
    +
    +.syntax .variable {
     	font-style: italic;
     }

    diff --git a/jquery.syntax.js b/jquery.syntax.js
    index 7dfc642..07fc8a1 100644
    --- a/jquery.syntax.js
    +++ b/jquery.syntax.js
    @@ -73,9 +73,8 @@ ResourceLoader.prototype._finish = function (name) {
     	if (!resource)
     		window.console.log("Could not load resource named ", name)
     	else {
    -		for (var i in loading) {
    +		for (var i = 0; i < loading.length; i += 1)
     			loading[i](resource)
    -		}
     	}
     }

    @@ -100,11 +99,9 @@ Syntax = {

     		Syntax.getResource('jquery.syntax.brush', name, callback)
     	}),
    -
     	layouts: new ResourceLoader(function(name, callback) {
     		Syntax.getResource('jquery.syntax.layout', name, callback)
    -	}),
    -
    +	}),
     	getStyles: function (path) {
     		var link = $('<link>')
     		$("head").append(link)
    @@ -115,7 +112,6 @@ Syntax = {
     			href: path
     		})
     	},
    -
     	getScript: function (path, callback) {
     		$.ajax({
     			async: 'true',
    @@ -128,7 +124,6 @@ Syntax = {
     			cache: true
     		})
     	},
    -
     	getResource: function (prefix, name, callback) {
     		var basename = prefix + "." + name

    @@ -137,25 +132,22 @@ Syntax = {

     		Syntax.getScript(this.root + basename + '.js', callback)
     	},
    -
     	register: function (name, callback) {
    -		brush = Syntax.brushes[name] = new Syntax.Brush()
    +		var brush = Syntax.brushes[name] = new Syntax.Brush()
     		window.console.log("Registering brush", name, Syntax.brushes)

     		brush.klass = name

     		callback(brush)
     	},
    -
     	alias: function (name, aliases) {
    -		for (var i in aliases)
    +		for (var i = 0; i < aliases.length; i += 1)
     			Syntax.aliases[aliases[i]] = name
     	},
    -
     	getMatches: function (text, expr) {
     		//window.console.log("getMatches: ", text, expr)

    -		var matches = []
    +		var matches = [], match = null

     		while((match = expr.pattern.exec(text)) != null) {
     			if (expr.matches)
    @@ -168,23 +160,23 @@ Syntax = {
     	}
     }

    -// Default layout
     Syntax.layouts.plain = function (options, html, container) {
     	return html
     }

     Syntax.singleMatchFunction = function(index, rule) {
    -	return function(token) {
    +	return function(match) {
     		return new Syntax.Match(RegExp.indexOf(match, index), match[index].length, rule, match[index])
     	}
     }

    -Syntax.lib.cStyleComment = {pattern: /\/\*[\s\S]*?\*\//gm, klass: 'comment', children: null}
    -Syntax.lib.cppStyleComment = {pattern: /\/\/.*$/gm, klass: 'comment', children: null}
    -Syntax.lib.perlStyleComment = {pattern: /#.*$/gm, klass: 'comment', children: null}
    -Syntax.lib.cStyleFunction = {pattern: /([a-z_][a-z0-9_]+)\s*\(/gi, matches: Syntax.singleMatchFunction(1, {klass: 'function', children: null})}
    -Syntax.lib.rubyStyleFunction = {pattern: /\.([a-z_][a-z0-9_]+)/gi, matches: Syntax.singleMatchFunction(1, {klass: 'function', children: null})}
    -Syntax.lib.rubyStyleSymbol = {pattern: /:[\w]+/, klass: 'constant', children: null}
    +Syntax.lib.cStyleComment = {pattern: /\/\*[\s\S]*?\*\//gm, klass: 'comment', children: ['href']}
    +Syntax.lib.cppStyleComment = {pattern: /\/\/.*$/gm, klass: 'comment', children: ['href']}
    +Syntax.lib.perlStyleComment = {pattern: /#.*$/gm, klass: 'comment', children: ['href']}
    +
    +Syntax.lib.cStyleFunction = {pattern: /([a-z_][a-z0-9_]+)\s*\(/gi, matches: Syntax.singleMatchFunction(1, {klass: 'function', children: []})}
    +
    +Syntax.lib.webLink = {pattern: /https?:\/\/([-\w~!$?&#\/+|.,=]|%[a-f\d]{2})+/g, klass: 'href'}

     Syntax.Match = function (offset, length, expr, value) {
     	this.offset = offset
    @@ -199,16 +191,11 @@ Syntax.Match = function (offset, length, expr, value) {
     }

     Syntax.Match.sort = function (a,b) {
    -	var diff = a.offset - b.offset
    -
    -	if (diff != 0)
    -		return diff
    -	else
    -		return b.length - a.length
    +	return (a.offset - b.offset) || (b.length - a.length)
     }

     Syntax.Match.prototype.contains = function (match) {
    -	return (this.offset <= match.offset) && (match.endOffset <= this.endOffset)
    +	return (match.offset >= this.offset) && (match.endOffset <= this.endOffset)
     }

     Syntax.Match.defaultReduceCallback = function (node, container) {
    @@ -237,9 +224,8 @@ Syntax.Match.prototype.reduce = function (append) {
     	if (this.expression && this.expression.klass)
     		container.addClass(this.expression.klass)

    -	for (var i in this.children) {
    +	for (var i = 0; i < this.children.length; i += 1) {
     		//window.console.log(i, this.children[i], text)
    -
     		var child = this.children[i]
     		var end = child.offset

    @@ -256,56 +242,59 @@ Syntax.Match.prototype.reduce = function (append) {
     	else if (start < this.endOffset)
     		append(this.value.substr(start - this.offset, this.endOffset - start), container)
     	else if (start > this.endOffset)
    -		window.console.log("Start position", start, "exceeds length of value", this)
    +		window.console.log("Start position", start, "exceeds length of value", this.offset, this.length)

     	return container
     }

    -// This function is by far the biggest overal cost in terms of run-time. This is not because
    -// it is slow, but mostly because it is called many times. It already has as much of the logic
    -// folded into it (few function calls). I considered making it non-recursive, but after testing,
    -// I found that less than 64 out of 500 function calls recursed at all, so it wouldn't be worth
    -// it - it might even get slower.
    -Syntax.Match.prototype.insert = function (match) {
    +// This is not a general tree insertion function. It is optimised to run in almost constant
    +// time, but data must be inserted in sorted order, otherwise you will have problems.
    +Syntax.Match.prototype.insertAtEnd = function (match) {
    +	if (!this.contains(match)) {
    +		window.console.log(this, "does not contain", match)
    +		return null;
    +	}
    +
     	// We have explicitly said: no children
     	if (this.expression.children === null)
     		return null
    -
    -	if (this.expression.children) {
    -		// window.console.log(this.expression.children, match.expression.klass, $.inArray(match.expression.klass, this.expression.children))
    +	else if (this.expression.children) {
     		if ($.inArray(match.expression.klass, this.expression.children) == -1)
     			return null
     	}

    -	if (!this.contains(match))
    -		return null
    -
     	if (this.children.length > 0) {
    -		for (var i in this.children) {
    -			var child = this.children[i]
    -
    -			if (match.offset < child.offset) {
    -				if (match.endOffset <= child.offset) {
    -					this.children.splice(i, 0, match)
    -					return this
    -				} else {
    -					window.console.log("Match " + match.toString() + " " + displacement + "  existing child: " + this.children[i].toString())
    -					return null
    -				}
    -			} else if (match.offset < child.endOffset) {
    -				if (match.endOffset <= child.endOffset) {
    -					// Recursive step
    -					return child.insert(match)
    -				} else {
    -					var parts = match.halfBisect(child.endOffset)
    -					child.insert(parts[0])
    -					match = parts[1]
    -				}
    +		var i = this.children.length-1
    +		var child = this.children[i]
    +
    +		if (match.offset < child.offset) {
    +			if (match.endOffset <= child.offset) {
    +				// displacement = 'before'
    +				this.children.splice(i, 0, match)
    +				return this
    +			} else {
    +				// displacement = 'left-overlap'
    +				return null
    +			}
    +		} else if (match.offset < child.endOffset) {
    +			if (match.endOffset <= child.endOffset) {
    +				// displacement = 'contains'
    +				var result = child.insertAtEnd(match)
    +				return result
     			} else {
    -				if (i == this.children.length-1) {
    -					this.children.splice(i+1, 0, match)
    -					return this
    -				}
    +				// displacement = 'right-overlap'
    +				// This code should work, but right now I don't think its useful.
    +				window.console.error("Cannot add match", match, "into", this, "it right-overlaps!")
    +				//var parts = match.halfBisect(child.endOffset)
    +				// child.insertAtEnd(parts[0])
    +				// this.insertAtEnd(parts[1])
    +				return null;
    +			}
    +		} else {
    +			// displacement = 'after'
    +			if (i == this.children.length-1) {
    +				this.children.splice(i+1, 0, match)
    +				return this
     			}
     		}

    @@ -328,7 +317,14 @@ Syntax.Match.prototype.halfBisect = function(offset) {
     Syntax.Match.prototype.bisectAtOffsets = function(splits) {
     	var parts = [], start = this.offset, prev = null, children = $.merge([], this.children)

    -	for (var i in splits) {
    +	// Copy the array so we can modify it.
    +	splits = splits.slice(0)
    +
    +	// We need to split including the last part.
    +	splits.push(this.endOffset)
    +	splits.sort(function(a,b){return a-b})
    +
    +	for (var i = 0; i < splits.length; i += 1) {
     		var offset = splits[i]

     		if (offset < this.offset || offset > this.endOffset) {
    @@ -336,7 +332,7 @@ Syntax.Match.prototype.bisectAtOffsets = function(splits) {
     		}

     		var match = new Syntax.Match(start, offset - start, this.expression)
    -		match.value = this.value.substr(start, match.length)
    +		match.value = this.value.substr(start - this.offset, match.length)

     		if (prev)
     			prev.next = match
    @@ -351,7 +347,7 @@ Syntax.Match.prototype.bisectAtOffsets = function(splits) {
     	splits.length = parts.length

     	for (var i = 0; i < parts.length; i += 1) {
    -		var offset = splits.shift()
    +		var offset = splits[0]

     		while (children.length > 0) {
     			if (children[0].endOffset <= parts[i].endOffset)
    @@ -362,15 +358,18 @@ Syntax.Match.prototype.bisectAtOffsets = function(splits) {

     		if (children.length) {
     			// We may have an intersection
    -			if (children[0].offset < parts[i].offset) {
    -				children_parts = children.shift().bisectAtOffsets(splits)
    +			if (children[0].offset < parts[i].endOffset) {
    +				var children_parts = children.shift().bisectAtOffsets(splits), j = 0

    -				for (var j in children_parts)
    +				for (; j < children_parts.length; j += 1)
     					parts[i+j].children.push(children_parts[j])

    -				// i += (j-1)
    +				// Skip any parts which have been populated already
    +				// i += (children_parts.length-1)
     			}
     		}
    +
    +		splits.shift();
     	}

     	if (children.length)
    @@ -380,14 +379,11 @@ Syntax.Match.prototype.bisectAtOffsets = function(splits) {
     }

     Syntax.Match.prototype.split = function(pattern) {
    -	var splits = []
    +	var splits = [], match

     	while ((match = pattern.exec(this.value)) != null)
     		splits.push(pattern.lastIndex)

    -	// We need to have a fake split at the end.
    -	splits.push(this.endOffset)
    -
     	return this.bisectAtOffsets(splits)
     }

    @@ -400,14 +396,24 @@ Syntax.Brush.prototype.push = function () {
     	if ($.isArray(arguments[0])) {
     		var patterns = arguments[0], rule = arguments[1]

    -		for (var i in patterns)
    +		for (var i = 0; i < patterns.length; i += 1)
     			this.push($.extend({pattern: patterns[i]}, rule))
     	} else {
     		var rule = arguments[0]

     		if (typeof(rule.pattern) == 'string') {
     			rule.string = rule.pattern
    -			rule.pattern = new RegExp(RegExp.escape(rule.pattern), rule.options || 'g')
    +			var prefix = "\\b", postfix = "\\b"
    +
    +			if (!rule.pattern.match(/^\w/)) {
    +				if (!rule.pattern.match(/\w$/))
    +					prefix = postfix = ""
    +				else
    +					prefix = "\\B"
    +			}
    +
    +
    +			rule.pattern = rule.pattern = new RegExp(prefix + RegExp.escape(rule.pattern) + postfix, rule.options || 'g')
     		}

     		if (rule.pattern.global)
    @@ -420,9 +426,8 @@ Syntax.Brush.prototype.push = function () {
     Syntax.Brush.prototype.getMatches = function(text) {
     	var matches = []

    -	for (var i in this.rules) {
    +	for (var i = 0; i < this.rules.length; i += 1)
     		matches = matches.concat(Syntax.getMatches(text, this.rules[i]))
    -	}

     	return matches
     }
    @@ -434,15 +439,14 @@ Syntax.Brush.prototype.process = function(text) {
     	// This sort is absolutely key to the functioning of the tree insertion algorithm.
     	matches.sort(Syntax.Match.sort)

    -	for (var i in matches) {
    -		top.insert(matches[i])
    -	}
    +	for (var i = 0; i < matches.length; i += 1)
    +		top.insertAtEnd(matches[i])

     	var lines = top.split(/\n/g)

     	var html = $('<pre>').addClass('syntax')

    -	for (var i in lines) {
    +	for (var i = 0; i < lines.length; i += 1) {
     		var line = lines[i].reduce()
     		html.append(line)
     	}
    diff --git a/jquery.syntax.layout.table.css b/jquery.syntax.layout.table.css
    index 6e12646..043f721 100644
    --- a/jquery.syntax.layout.table.css
    +++ b/jquery.syntax.layout.table.css
    @@ -11,6 +11,10 @@ table.syntax {
     	-webkit-box-shadow: 5px 5px 5px #eee;
     }

    +table.syntax tr.alt td.source {
    +	background-color: #f6f6f6;
    +}
    +
     table.syntax td {
     	padding-left: 0.4em;
     	padding-right: 0.4em;
    @@ -22,5 +26,5 @@ table.syntax td.number {

     	width: 2.5em;
     	color: #555;
    -	background-color: #dadada;
    +	background-color: #e0e0e0;
     }
    \ No newline at end of file
    diff --git a/jquery.syntax.layout.table.js b/jquery.syntax.layout.table.js
    index 9cd68c3..14967c4 100644
    --- a/jquery.syntax.layout.table.js
    +++ b/jquery.syntax.layout.table.js
    @@ -1,16 +1,14 @@
    -Syntax.layouts.table = function(options, code, container) {
    -	var table = $('<table>'), tr = null, td = null;
    +Syntax.layouts.tableJQ = function(options, code, container) {
    +	var table = $('<table class="syntax">'), tr = null, td = null;
     	var line = 1;

    -	table.addClass('syntax');
    -
     	code.children().each(function() {
    -		tr = $('<tr>').addClass('line', 'line-' + line);
    +		tr = $('<tr class="line ln' + line + '">')

    -		td = $('<td>').addClass('number').text(line);
    +		td = $('<td class="number">' + line + '</td>')
     		tr.append(td);

    -		td = $('<td>').addClass('source');
    +		td = $('<td class="source">')
     		td.append(this);
     		tr.append(td);

    @@ -19,4 +17,57 @@ Syntax.layouts.table = function(options, code, container) {
     	});

     	return table;
    -}
    \ No newline at end of file
    +}
    +
    +Syntax.layouts.tableDOM = function(options, code, container) {
    +	var table = $('<table>'), tr = null, td = null;
    +	var line = 1;
    +
    +	table.addClass('syntax');
    +
    +	code.children().each(function() {
    +		tr = document.createElement('tr')
    +		tr.className = "line ln" + line
    +
    +		if (line % 2)
    +			tr.className += " alt"
    +
    +		td = document.createElement('td')
    +		td.className = "number"
    +		td.innerHTML = line
    +		tr.appendChild(td)
    +
    +		td = document.createElement('td')
    +		td.className = "source"
    +		td.innerHTML = this.innerHTML
    +		tr.appendChild(td)
    +
    +		table[0].appendChild(tr)
    +		line = line + 1;
    +	});
    +
    +	$('span.href', table).each(function(){
    +		$(this).replaceWith($('<a>').attr('href', this.innerHTML).text(this.innerHTML))
    +	})
    +
    +	return table;
    +}
    +
    +Syntax.layouts.tableSTR = function(options, code, container) {
    +	var table = "<table class='syntax'>", tr = null, td = null;
    +	var line = 1;
    +
    +	code.children().each(function() {
    +		table += "<tr class='line ln" + line + "'><td class='number'></td><td class='source'>" + this.innerHTML + "</td></tr>"
    +
    +		line = line + 1;
    +	});
    +
    +	table += "</table>"
    +
    +	window.console.log(table.length)
    +
    +	return $(table);
    +}
    +
    +Syntax.layouts.table = Syntax.layouts.tableDOM
    \ No newline at end of file