summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKornelius Kalnbach <murphy@rubychan.de>2011-09-09 01:00:35 +0200
committerKornelius Kalnbach <murphy@rubychan.de>2011-09-09 01:00:35 +0200
commitd42887ef56c724d9f7b3b21ed8e1758f9d96e706 (patch)
tree5ba4b6dbc8774dbb09743121d3d469b7299d840a
parent03583bbfa756de93a3e75fb3f61d5d9729e250f7 (diff)
downloadcoderay-d42887ef56c724d9f7b3b21ed8e1758f9d96e706.tar.gz
#353 New scanner: HAML!
-rw-r--r--Changes-1.0.textile8
-rw-r--r--lib/coderay/helpers/file_type.rb1
-rw-r--r--lib/coderay/scanners/haml.rb168
3 files changed, 177 insertions, 0 deletions
diff --git a/Changes-1.0.textile b/Changes-1.0.textile
index 76d1060..9f8126c 100644
--- a/Changes-1.0.textile
+++ b/Changes-1.0.textile
@@ -15,6 +15,7 @@ h3. General changes
* *NEW*: The new Diff scanner colorizes code inside of the diff, and highlights inline changes.
* *NEW*: Extended support and usage of HTML5 and CSS 3 features.
* *NEW*: Direct Streaming
+* *NEW* scanners: Clojure and HAML
* *CHANGED*: Token classes (used as CSS classes) are readable names; breaks you stylesheet!
* *IMPROVED* documentation
* *IMPROVED* speed: faster startup (using @autoload@), scanning, and encoding
@@ -212,6 +213,13 @@ h3. @Scanners::Diff@
h3. *RENAMED*: @Scanners::ERB@ (was @Scanners::RHTML@)
+h3. *NEW*: @Scanners::HAML@
+
+It uses the new :state options of the HTML and Ruby scanners.
+
+Some rare cases are not considered (like @#{...}@ snippets inside of :javascript blocks),
+but it highlights pretty well.
+
h3. @Scanners::HTML@
* *FIXED*: Closes open string groups.
diff --git a/lib/coderay/helpers/file_type.rb b/lib/coderay/helpers/file_type.rb
index c752a03..7b9939c 100644
--- a/lib/coderay/helpers/file_type.rb
+++ b/lib/coderay/helpers/file_type.rb
@@ -88,6 +88,7 @@ module CodeRay
'groovy' => :groovy,
'gvy' => :groovy,
'h' => :c,
+ 'haml' => :haml,
'htm' => :page,
'html' => :page,
'html.erb' => :erb,
diff --git a/lib/coderay/scanners/haml.rb b/lib/coderay/scanners/haml.rb
new file mode 100644
index 0000000..52988b2
--- /dev/null
+++ b/lib/coderay/scanners/haml.rb
@@ -0,0 +1,168 @@
+module CodeRay
+module Scanners
+
+ load :ruby
+ load :html
+ load :java_script
+
+ class HAML < Scanner
+
+ register_for :haml
+ title 'HAML Template'
+
+ KINDS_NOT_LOC = HTML::KINDS_NOT_LOC
+
+ protected
+
+ def setup
+ super
+ @ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true
+ @embedded_ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true, :state => @ruby_scanner.interpreted_string_state
+ @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true
+ end
+
+ def scan_tokens encoder, options
+
+ match = nil
+ code = ''
+
+ until eos?
+
+ if bol?
+ if match = scan(/!!!.*/)
+ encoder.text_token match, :doctype
+ next
+ end
+
+ if match = scan(/(?>( *)(\/(?!\[if)|-\#|:javascript|:ruby|:\w+) *)(?=\n)/)
+ encoder.text_token match, :comment
+
+ code = self[2]
+ if match = scan(/(?:\n+#{self[1]} .*)+/)
+ case code
+ when '/', '-#'
+ encoder.text_token match, :comment
+ when ':javascript'
+ # TODO: recognize #{...} snippets inside JavaScript
+ @java_script_scanner ||= CodeRay.scanner :java_script, :tokens => @tokens, :keep_tokens => true
+ @java_script_scanner.tokenize match, :tokens => encoder
+ when ':ruby'
+ @ruby_scanner.tokenize match, :tokens => encoder
+ when /:\w+/
+ encoder.text_token match, :comment
+ else
+ raise 'else-case reached: %p' % [code]
+ end
+ end
+ end
+
+ if match = scan(/ +/)
+ encoder.text_token match, :space
+ end
+
+ if match = scan(/\/.*/)
+ encoder.text_token match, :comment
+ next
+ end
+
+ if match = scan(/\\/)
+ encoder.text_token match, :plain
+ if match = scan(/.+/)
+ @html_scanner.tokenize match, :tokens => encoder
+ end
+ next
+ end
+
+ tag = false
+
+ if match = scan(/%[\w:]+\/?/)
+ encoder.text_token match, :tag
+ # if match = scan(/( +)(.+)/)
+ # encoder.text_token self[1], :space
+ # @embedded_ruby_scanner.tokenize self[2], :tokens => encoder
+ # end
+ tag = true
+ end
+
+ while match = scan(/([.#])[-\w]*\w/)
+ encoder.text_token match, self[1] == '#' ? :constant : :class
+ tag = true
+ end
+
+ if tag && match = scan(/(\()([^)]+)?(\))?/)
+ # TODO: recognize title=@title, class="widget_#{@widget.number}"
+ encoder.text_token self[1], :plain
+ @html_scanner.tokenize self[2], :tokens => encoder, :state => :attribute if self[2]
+ encoder.text_token self[3], :plain if self[3]
+ end
+
+ if tag && match = scan(/\{/)
+ encoder.text_token match, :plain
+
+ code = ''
+ level = 1
+ while true
+ code << scan(/([^\{\},\n]|, *\n?)*/)
+ case match = getch
+ when '{'
+ level += 1
+ code << match
+ when '}'
+ level -= 1
+ if level > 0
+ code << match
+ else
+ break
+ end
+ when "\n", ",", nil
+ break
+ end
+ end
+ @ruby_scanner.tokenize code, :tokens => encoder unless code.empty?
+
+ encoder.text_token match, :plain if match
+ end
+
+ if tag && match = scan(/(\[)([^\]\n]+)?(\])?/)
+ encoder.text_token self[1], :plain
+ @ruby_scanner.tokenize self[2], :tokens => encoder if self[2]
+ encoder.text_token self[3], :plain if self[3]
+ end
+
+ if tag && match = scan(/\//)
+ encoder.text_token match, :tag
+ end
+
+ if scan(/(>?<?[-=]|[&!]=|(& |!)|~)( *)([^,\n\|]+(?:(, *|\|(?=.|\n.*\|$))\n?[^,\n\|]*)*)?/)
+ encoder.text_token self[1] + self[3], :plain
+ if self[4]
+ if self[2]
+ @embedded_ruby_scanner.tokenize self[4], :tokens => encoder
+ else
+ @ruby_scanner.tokenize self[4], :tokens => encoder
+ end
+ end
+ elsif match = scan(/((?:<|><?)(?![!?\/\w]))?(.+)?/)
+ encoder.text_token self[1], :plain if self[1]
+ # TODO: recognize #{...} snippets
+ @html_scanner.tokenize self[2], :tokens => encoder if self[2]
+ end
+
+ elsif match = scan(/.+/)
+ @html_scanner.tokenize match, :tokens => encoder
+
+ end
+
+ if match = scan(/\n/)
+ encoder.text_token match, :space
+ end
+ end
+
+ encoder
+
+ end
+
+ end
+
+end
+end