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