diff options
author | murphy <murphy@rubychan.de> | 2008-09-18 01:12:44 +0000 |
---|---|---|
committer | murphy <murphy@rubychan.de> | 2008-09-18 01:12:44 +0000 |
commit | 41acfacb91970c8fa4e8b34f35c718eb329a3733 (patch) | |
tree | f11afbc209873285165934749e47b74e6936f25f /lib/coderay | |
parent | e46b6cbe74db250d743e7f194bfc7514529a82cc (diff) | |
download | coderay-41acfacb91970c8fa4e8b34f35c718eb329a3733.tar.gz |
New: *CSS Scanner* (closes #29).
* Based on Stefan Walk's implementation, with fixes, enhancements and speedups.
* It seems to be fairly fast and highlights nicely.
* I added the styles for Ignis Draconis, S5, and YUI as example code for testing.
More changes:
* Added three new token classes, :important, :pseudo_class, and :value, along with CSS styles.
Diffstat (limited to 'lib/coderay')
-rw-r--r-- | lib/coderay/scanners/css.rb | 181 | ||||
-rw-r--r-- | lib/coderay/styles/cycnus.rb | 5 | ||||
-rwxr-xr-x | lib/coderay/token_classes.rb | 3 |
3 files changed, 188 insertions, 1 deletions
diff --git a/lib/coderay/scanners/css.rb b/lib/coderay/scanners/css.rb new file mode 100644 index 0000000..897e27a --- /dev/null +++ b/lib/coderay/scanners/css.rb @@ -0,0 +1,181 @@ +module CodeRay +module Scanners + + class CSS < Scanner + + register_for :css + + module RE + NonASCII = /[\x80-\xFF]/ + Hex = /[0-9a-fA-F]/ + Unicode = /\\#{Hex}{1,6}(?:\r\n|\s)?/ # differs from standard because it allows uppercase hex too + Escape = /#{Unicode}|\\[^\r\n\f0-9a-fA-F]/ + NMChar = /[-_a-zA-Z0-9]|#{NonASCII}|#{Escape}/ + NMStart = /[_a-zA-Z]|#{NonASCII}|#{Escape}/ + NL = /\r\n|\r|\n|\f/ + String1 = /"(?:[^\n\r\f\\"]|\\#{NL}|#{Escape})*"?/ # FIXME: buggy regexp + String2 = /'(?:[^\n\r\f\\']|\\#{NL}|#{Escape})*'?/ # FIXME: buggy regexp + String = /#{String1}|#{String2}/ + + HexColor = /#(?:#{Hex}{6}|#{Hex}{3})/ + Color = /#{HexColor}/ + + Num = /-?(?:[0-9]+|[0-9]*\.[0-9]+)/ + Name = /#{NMChar}+/ + Ident = /-?#{NMStart}#{NMChar}*/ + AtKeyword = /@#{Ident}/ + Percentage = /#{Num}%/ + + reldimensions = %w[em ex px] + absdimensions = %w[in cm mm pt pc] + Unit = Regexp.union(*(reldimensions + absdimensions)) + + Dimension = /#{Num}#{Unit}/ + + Comment = %r! /\* (?: .*? \*/ | .* ) !mx + Function = /(?:url|alpha)\((?:[^)\n\r\f]|\\\))*\)?/ + + Id = /##{Name}/ + Class = /\.#{Name}/ + PseudoClass = /:#{Name}/ + + end + + def scan_tokens tokens, options + + value_expected = nil + states = [:initial] + + until eos? + + kind = nil + match = nil + + if scan(/\s+/) + kind = :space + + elsif case states.last + when :initial + if scan(/#{RE::Ident}|\*/ox) + kind = :keyword + elsif scan RE::Class + kind = :class + elsif scan RE::Id + kind = :constant + elsif scan RE::PseudoClass + kind = :pseudo_class + elsif scan RE::Name + kind = :identifier + end + + when :block + if scan(/(?>#{RE::Ident})(?!\()/ox) + if value_expected + kind = :value + else + kind = :key + end + end + + when :comment + if scan(/(?:[^*\s]|\*(?!\/))+/) + kind = :comment + elsif scan(/\*\//) + kind = :comment + states.pop + elsif scan(/\s+/) + kind = :space + end + + else + raise_inspect 'Unknown state', tokens + + end + + elsif scan(/\/\*/) + kind = :comment + states.push :comment + + elsif scan(/\{/) + value_expected = false + kind = :operator + states.push :block + + elsif scan(/\}/) + value_expected = false + if states.last == :block + kind = :operator + states.pop + else + kind = :error + end + + elsif match = scan(/#{RE::String}/o) + tokens << [:open, :string] + tokens << [match[0, 1], :delimiter] + tokens << [match[1..-2], :content] if match.size > 2 + tokens << [match[-1, 1], :delimiter] if match.size >= 2 + tokens << [:close, :string] + next + + elsif match = scan(/#{RE::Function}/o) + tokens << [:open, :string] + start = match[/^\w+\(/] + tokens << [start, :delimiter] + if match[-1] == ?) + tokens << [match[start.size..-2], :content] + tokens << [')', :delimiter] + else + tokens << [match[start.size..-1], :content] + end + tokens << [:close, :string] + next + + elsif scan(/(?: #{RE::Dimension} | #{RE::Percentage} | #{RE::Num} )/ox) + kind = :float + + elsif scan(/#{RE::Color}/o) + kind = :color + + elsif scan(/! *important/) + kind = :important + + elsif scan(/rgb\([^()\n]*\)?/) + kind = :color + + elsif scan(/#{RE::AtKeyword}/o) + kind = :directive + + elsif match = scan(/ [+>:;,.=()\/] /x) + if match == ':' + value_expected = true + elsif match == ';' + value_expected = false + end + kind = :operator + + else + getch + kind = :error + + end + + match ||= matched + if $DEBUG and not kind + raise_inspect 'Error token %p in line %d' % + [[match, kind], line], tokens + end + raise_inspect 'Empty token', tokens unless match + + tokens << [match, kind] + # tokens << [states.inspect, :error] + + end + + tokens + end + + end + +end +end diff --git a/lib/coderay/styles/cycnus.rb b/lib/coderay/styles/cycnus.rb index 7b68a66..d552d50 100644 --- a/lib/coderay/styles/cycnus.rb +++ b/lib/coderay/styles/cycnus.rb @@ -80,6 +80,7 @@ ol.CodeRay li { white-space: pre } .il .il .il { background: #ccc } .il .idl { font-weight: bold; color: #888 } +.im { color:#f00; } .in { color:#B2B; font-weight:bold } .iv { color:#33B } .la { color:#970; font-weight:bold } @@ -89,11 +90,13 @@ ol.CodeRay li { white-space: pre } .op { } .pc { color:#038; font-weight:bold } .pd { color:#369; font-weight:bold } -.pp { color:#579 } +.pp { color:#579; } +.ps { color:#00C; font-weight: bold; } .pt { color:#339; font-weight:bold } .r, .kw { color:#080; font-weight:bold } .ke { color: #808; } +.vl { color: #088; } .rx { background-color:#fff0ff } .rx .k { color:#808 } diff --git a/lib/coderay/token_classes.rb b/lib/coderay/token_classes.rb index c352e48..9b5e83c 100755 --- a/lib/coderay/token_classes.rb +++ b/lib/coderay/token_classes.rb @@ -29,6 +29,7 @@ module CodeRay :function => 'fu', :global_variable => 'gv', :hex => 'hx', + :important => 'im', :include => 'ic', :inline => 'il', :inline_delimiter => 'idl', @@ -46,6 +47,7 @@ module CodeRay :pre_type => 'pt', :predefined => 'pd', :preprocessor => 'pp', + :pseudo_class => 'ps', :regexp => 'rx', :reserved => 'r', :shell => 'sh', @@ -56,6 +58,7 @@ module CodeRay :tag_special => 'ts', :type => 'ty', :variable => 'v', + :value => 'vl', :xml_text => 'xt', :ident => :NO_HIGHLIGHT, # 'id' |