annotate vendor/gems/coderay-1.0.0/lib/coderay/scanners/css.rb @ 1472:f0b798dad2d6 feature_526

Close obsolete branch feature_526
author Chris Cannam
date Tue, 20 Nov 2012 19:45:51 +0000
parents cbb26bc654de
children
rev   line source
Chris@909 1 module CodeRay
Chris@909 2 module Scanners
Chris@909 3
Chris@909 4 class CSS < Scanner
Chris@909 5
Chris@909 6 register_for :css
Chris@909 7
Chris@909 8 KINDS_NOT_LOC = [
Chris@909 9 :comment,
Chris@909 10 :class, :pseudo_class, :type,
Chris@909 11 :constant, :directive,
Chris@909 12 :key, :value, :operator, :color, :float, :string,
Chris@909 13 :error, :important,
Chris@909 14 ] # :nodoc:
Chris@909 15
Chris@909 16 module RE # :nodoc:
Chris@909 17 Hex = /[0-9a-fA-F]/
Chris@909 18 Unicode = /\\#{Hex}{1,6}(?:\r\n|\s)?/ # differs from standard because it allows uppercase hex too
Chris@909 19 Escape = /#{Unicode}|\\[^\r\n\f0-9a-fA-F]/
Chris@909 20 NMChar = /[-_a-zA-Z0-9]|#{Escape}/
Chris@909 21 NMStart = /[_a-zA-Z]|#{Escape}/
Chris@909 22 NL = /\r\n|\r|\n|\f/
Chris@909 23 String1 = /"(?:[^\n\r\f\\"]|\\#{NL}|#{Escape})*"?/ # TODO: buggy regexp
Chris@909 24 String2 = /'(?:[^\n\r\f\\']|\\#{NL}|#{Escape})*'?/ # TODO: buggy regexp
Chris@909 25 String = /#{String1}|#{String2}/
Chris@909 26
Chris@909 27 HexColor = /#(?:#{Hex}{6}|#{Hex}{3})/
Chris@909 28 Color = /#{HexColor}/
Chris@909 29
Chris@909 30 Num = /-?(?:[0-9]+|[0-9]*\.[0-9]+)/
Chris@909 31 Name = /#{NMChar}+/
Chris@909 32 Ident = /-?#{NMStart}#{NMChar}*/
Chris@909 33 AtKeyword = /@#{Ident}/
Chris@909 34 Percentage = /#{Num}%/
Chris@909 35
Chris@909 36 reldimensions = %w[em ex px]
Chris@909 37 absdimensions = %w[in cm mm pt pc]
Chris@909 38 Unit = Regexp.union(*(reldimensions + absdimensions))
Chris@909 39
Chris@909 40 Dimension = /#{Num}#{Unit}/
Chris@909 41
Chris@909 42 Comment = %r! /\* (?: .*? \*/ | .* ) !mx
Chris@909 43 Function = /(?:url|alpha|attr|counters?)\((?:[^)\n\r\f]|\\\))*\)?/
Chris@909 44
Chris@909 45 Id = /##{Name}/
Chris@909 46 Class = /\.#{Name}/
Chris@909 47 PseudoClass = /:#{Name}/
Chris@909 48 AttributeSelector = /\[[^\]]*\]?/
Chris@909 49 end
Chris@909 50
Chris@909 51 protected
Chris@909 52
Chris@909 53 def scan_tokens encoder, options
Chris@909 54
Chris@909 55 value_expected = nil
Chris@909 56 states = [:initial]
Chris@909 57
Chris@909 58 until eos?
Chris@909 59
Chris@909 60 if match = scan(/\s+/)
Chris@909 61 encoder.text_token match, :space
Chris@909 62
Chris@909 63 elsif case states.last
Chris@909 64 when :initial, :media
Chris@909 65 if match = scan(/(?>#{RE::Ident})(?!\()|\*/ox)
Chris@909 66 encoder.text_token match, :type
Chris@909 67 next
Chris@909 68 elsif match = scan(RE::Class)
Chris@909 69 encoder.text_token match, :class
Chris@909 70 next
Chris@909 71 elsif match = scan(RE::Id)
Chris@909 72 encoder.text_token match, :constant
Chris@909 73 next
Chris@909 74 elsif match = scan(RE::PseudoClass)
Chris@909 75 encoder.text_token match, :pseudo_class
Chris@909 76 next
Chris@909 77 elsif match = scan(RE::AttributeSelector)
Chris@909 78 # TODO: Improve highlighting inside of attribute selectors.
Chris@909 79 encoder.text_token match[0,1], :operator
Chris@909 80 encoder.text_token match[1..-2], :attribute_name if match.size > 2
Chris@909 81 encoder.text_token match[-1,1], :operator if match[-1] == ?]
Chris@909 82 next
Chris@909 83 elsif match = scan(/@media/)
Chris@909 84 encoder.text_token match, :directive
Chris@909 85 states.push :media_before_name
Chris@909 86 next
Chris@909 87 end
Chris@909 88
Chris@909 89 when :block
Chris@909 90 if match = scan(/(?>#{RE::Ident})(?!\()/ox)
Chris@909 91 if value_expected
Chris@909 92 encoder.text_token match, :value
Chris@909 93 else
Chris@909 94 encoder.text_token match, :key
Chris@909 95 end
Chris@909 96 next
Chris@909 97 end
Chris@909 98
Chris@909 99 when :media_before_name
Chris@909 100 if match = scan(RE::Ident)
Chris@909 101 encoder.text_token match, :type
Chris@909 102 states[-1] = :media_after_name
Chris@909 103 next
Chris@909 104 end
Chris@909 105
Chris@909 106 when :media_after_name
Chris@909 107 if match = scan(/\{/)
Chris@909 108 encoder.text_token match, :operator
Chris@909 109 states[-1] = :media
Chris@909 110 next
Chris@909 111 end
Chris@909 112
Chris@909 113 else
Chris@909 114 #:nocov:
Chris@909 115 raise_inspect 'Unknown state', encoder
Chris@909 116 #:nocov:
Chris@909 117
Chris@909 118 end
Chris@909 119
Chris@909 120 elsif match = scan(/\/\*(?:.*?\*\/|\z)/m)
Chris@909 121 encoder.text_token match, :comment
Chris@909 122
Chris@909 123 elsif match = scan(/\{/)
Chris@909 124 value_expected = false
Chris@909 125 encoder.text_token match, :operator
Chris@909 126 states.push :block
Chris@909 127
Chris@909 128 elsif match = scan(/\}/)
Chris@909 129 value_expected = false
Chris@909 130 if states.last == :block || states.last == :media
Chris@909 131 encoder.text_token match, :operator
Chris@909 132 states.pop
Chris@909 133 else
Chris@909 134 encoder.text_token match, :error
Chris@909 135 end
Chris@909 136
Chris@909 137 elsif match = scan(/#{RE::String}/o)
Chris@909 138 encoder.begin_group :string
Chris@909 139 encoder.text_token match[0, 1], :delimiter
Chris@909 140 encoder.text_token match[1..-2], :content if match.size > 2
Chris@909 141 encoder.text_token match[-1, 1], :delimiter if match.size >= 2
Chris@909 142 encoder.end_group :string
Chris@909 143
Chris@909 144 elsif match = scan(/#{RE::Function}/o)
Chris@909 145 encoder.begin_group :string
Chris@909 146 start = match[/^\w+\(/]
Chris@909 147 encoder.text_token start, :delimiter
Chris@909 148 if match[-1] == ?)
Chris@909 149 encoder.text_token match[start.size..-2], :content
Chris@909 150 encoder.text_token ')', :delimiter
Chris@909 151 else
Chris@909 152 encoder.text_token match[start.size..-1], :content
Chris@909 153 end
Chris@909 154 encoder.end_group :string
Chris@909 155
Chris@909 156 elsif match = scan(/(?: #{RE::Dimension} | #{RE::Percentage} | #{RE::Num} )/ox)
Chris@909 157 encoder.text_token match, :float
Chris@909 158
Chris@909 159 elsif match = scan(/#{RE::Color}/o)
Chris@909 160 encoder.text_token match, :color
Chris@909 161
Chris@909 162 elsif match = scan(/! *important/)
Chris@909 163 encoder.text_token match, :important
Chris@909 164
Chris@909 165 elsif match = scan(/(?:rgb|hsl)a?\([^()\n]*\)?/)
Chris@909 166 encoder.text_token match, :color
Chris@909 167
Chris@909 168 elsif match = scan(RE::AtKeyword)
Chris@909 169 encoder.text_token match, :directive
Chris@909 170
Chris@909 171 elsif match = scan(/ [+>:;,.=()\/] /x)
Chris@909 172 if match == ':'
Chris@909 173 value_expected = true
Chris@909 174 elsif match == ';'
Chris@909 175 value_expected = false
Chris@909 176 end
Chris@909 177 encoder.text_token match, :operator
Chris@909 178
Chris@909 179 else
Chris@909 180 encoder.text_token getch, :error
Chris@909 181
Chris@909 182 end
Chris@909 183
Chris@909 184 end
Chris@909 185
Chris@909 186 encoder
Chris@909 187 end
Chris@909 188
Chris@909 189 end
Chris@909 190
Chris@909 191 end
Chris@909 192 end