diff .svn/pristine/56/56493cc79ece7ebee244c20a035044b3abd7b20d.svn-base @ 927:9ee5fd0b9bd3

Merge from cannam_integration
author luisf <luis.figueira@eecs.qmul.ac.uk>
date Fri, 11 May 2012 16:13:59 +0100
parents cbb26bc654de
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.svn/pristine/56/56493cc79ece7ebee244c20a035044b3abd7b20d.svn-base	Fri May 11 16:13:59 2012 +0100
@@ -0,0 +1,192 @@
+module CodeRay
+module Scanners
+
+  class CSS < Scanner
+    
+    register_for :css
+    
+    KINDS_NOT_LOC = [
+      :comment,
+      :class, :pseudo_class, :type,
+      :constant, :directive,
+      :key, :value, :operator, :color, :float, :string,
+      :error, :important,
+    ]  # :nodoc:
+    
+    module RE  # :nodoc:
+      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]|#{Escape}/
+      NMStart = /[_a-zA-Z]|#{Escape}/
+      NL = /\r\n|\r|\n|\f/
+      String1 = /"(?:[^\n\r\f\\"]|\\#{NL}|#{Escape})*"?/  # TODO: buggy regexp
+      String2 = /'(?:[^\n\r\f\\']|\\#{NL}|#{Escape})*'?/  # TODO: 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|attr|counters?)\((?:[^)\n\r\f]|\\\))*\)?/
+      
+      Id = /##{Name}/
+      Class = /\.#{Name}/
+      PseudoClass = /:#{Name}/
+      AttributeSelector = /\[[^\]]*\]?/
+    end
+    
+  protected
+    
+    def scan_tokens encoder, options
+      
+      value_expected = nil
+      states = [:initial]
+      
+      until eos?
+        
+        if match = scan(/\s+/)
+          encoder.text_token match, :space
+          
+        elsif case states.last
+          when :initial, :media
+            if match = scan(/(?>#{RE::Ident})(?!\()|\*/ox)
+              encoder.text_token match, :type
+              next
+            elsif match = scan(RE::Class)
+              encoder.text_token match, :class
+              next
+            elsif match = scan(RE::Id)
+              encoder.text_token match, :constant
+              next
+            elsif match = scan(RE::PseudoClass)
+              encoder.text_token match, :pseudo_class
+              next
+            elsif match = scan(RE::AttributeSelector)
+              # TODO: Improve highlighting inside of attribute selectors.
+              encoder.text_token match[0,1], :operator
+              encoder.text_token match[1..-2], :attribute_name if match.size > 2
+              encoder.text_token match[-1,1], :operator if match[-1] == ?]
+              next
+            elsif match = scan(/@media/)
+              encoder.text_token match, :directive
+              states.push :media_before_name
+              next
+            end
+          
+          when :block
+            if match = scan(/(?>#{RE::Ident})(?!\()/ox)
+              if value_expected
+                encoder.text_token match, :value
+              else
+                encoder.text_token match, :key
+              end
+              next
+            end
+            
+          when :media_before_name
+            if match = scan(RE::Ident)
+              encoder.text_token match, :type
+              states[-1] = :media_after_name
+              next
+            end
+          
+          when :media_after_name
+            if match = scan(/\{/)
+              encoder.text_token match, :operator
+              states[-1] = :media
+              next
+            end
+          
+          else
+            #:nocov:
+            raise_inspect 'Unknown state', encoder
+            #:nocov:
+            
+          end
+          
+        elsif match = scan(/\/\*(?:.*?\*\/|\z)/m)
+          encoder.text_token match, :comment
+          
+        elsif match = scan(/\{/)
+          value_expected = false
+          encoder.text_token match, :operator
+          states.push :block
+          
+        elsif match = scan(/\}/)
+          value_expected = false
+          if states.last == :block || states.last == :media
+            encoder.text_token match, :operator
+            states.pop
+          else
+            encoder.text_token match, :error
+          end
+          
+        elsif match = scan(/#{RE::String}/o)
+          encoder.begin_group :string
+          encoder.text_token match[0, 1], :delimiter
+          encoder.text_token match[1..-2], :content if match.size > 2
+          encoder.text_token match[-1, 1], :delimiter if match.size >= 2
+          encoder.end_group :string
+          
+        elsif match = scan(/#{RE::Function}/o)
+          encoder.begin_group :string
+          start = match[/^\w+\(/]
+          encoder.text_token start, :delimiter
+          if match[-1] == ?)
+            encoder.text_token match[start.size..-2], :content
+            encoder.text_token ')', :delimiter
+          else
+            encoder.text_token match[start.size..-1], :content
+          end
+          encoder.end_group :string
+          
+        elsif match = scan(/(?: #{RE::Dimension} | #{RE::Percentage} | #{RE::Num} )/ox)
+          encoder.text_token match, :float
+          
+        elsif match = scan(/#{RE::Color}/o)
+          encoder.text_token match, :color
+          
+        elsif match = scan(/! *important/)
+          encoder.text_token match, :important
+          
+        elsif match = scan(/(?:rgb|hsl)a?\([^()\n]*\)?/)
+          encoder.text_token match, :color
+          
+        elsif match = scan(RE::AtKeyword)
+          encoder.text_token match, :directive
+          
+        elsif match = scan(/ [+>:;,.=()\/] /x)
+          if match == ':'
+            value_expected = true
+          elsif match == ';'
+            value_expected = false
+          end
+          encoder.text_token match, :operator
+          
+        else
+          encoder.text_token getch, :error
+          
+        end
+        
+      end
+      
+      encoder
+    end
+    
+  end
+  
+end
+end