comparison vendor/gems/coderay-0.9.7/lib/coderay/scanners/.svn/text-base/css.rb.svn-base @ 210:0579821a129a

Update to Redmine trunk rev 4802
author Chris Cannam
date Tue, 08 Feb 2011 13:51:46 +0000
parents
children
comparison
equal deleted inserted replaced
128:07fa8a8b56a8 210:0579821a129a
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,
13 :error, :important,
14 ]
15
16 module RE
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})*"?/ # FIXME: buggy regexp
24 String2 = /'(?:[^\n\r\f\\']|\\#{NL}|#{Escape})*'?/ # FIXME: 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)\((?:[^)\n\r\f]|\\\))*\)?/
44
45 Id = /##{Name}/
46 Class = /\.#{Name}/
47 PseudoClass = /:#{Name}/
48 AttributeSelector = /\[[^\]]*\]?/
49
50 end
51
52 def scan_tokens tokens, options
53
54 value_expected = nil
55 states = [:initial]
56
57 until eos?
58
59 kind = nil
60 match = nil
61
62 if scan(/\s+/)
63 kind = :space
64
65 elsif case states.last
66 when :initial, :media
67 if scan(/(?>#{RE::Ident})(?!\()|\*/ox)
68 kind = :type
69 elsif scan RE::Class
70 kind = :class
71 elsif scan RE::Id
72 kind = :constant
73 elsif scan RE::PseudoClass
74 kind = :pseudo_class
75 elsif match = scan(RE::AttributeSelector)
76 # TODO: Improve highlighting inside of attribute selectors.
77 tokens << [:open, :string]
78 tokens << [match[0,1], :delimiter]
79 tokens << [match[1..-2], :content] if match.size > 2
80 tokens << [match[-1,1], :delimiter] if match[-1] == ?]
81 tokens << [:close, :string]
82 next
83 elsif match = scan(/@media/)
84 kind = :directive
85 states.push :media_before_name
86 end
87
88 when :block
89 if scan(/(?>#{RE::Ident})(?!\()/ox)
90 if value_expected
91 kind = :value
92 else
93 kind = :key
94 end
95 end
96
97 when :media_before_name
98 if scan RE::Ident
99 kind = :type
100 states[-1] = :media_after_name
101 end
102
103 when :media_after_name
104 if scan(/\{/)
105 kind = :operator
106 states[-1] = :media
107 end
108
109 when :comment
110 if scan(/(?:[^*\s]|\*(?!\/))+/)
111 kind = :comment
112 elsif scan(/\*\//)
113 kind = :comment
114 states.pop
115 elsif scan(/\s+/)
116 kind = :space
117 end
118
119 else
120 raise_inspect 'Unknown state', tokens
121
122 end
123
124 elsif scan(/\/\*/)
125 kind = :comment
126 states.push :comment
127
128 elsif scan(/\{/)
129 value_expected = false
130 kind = :operator
131 states.push :block
132
133 elsif scan(/\}/)
134 value_expected = false
135 if states.last == :block || states.last == :media
136 kind = :operator
137 states.pop
138 else
139 kind = :error
140 end
141
142 elsif match = scan(/#{RE::String}/o)
143 tokens << [:open, :string]
144 tokens << [match[0, 1], :delimiter]
145 tokens << [match[1..-2], :content] if match.size > 2
146 tokens << [match[-1, 1], :delimiter] if match.size >= 2
147 tokens << [:close, :string]
148 next
149
150 elsif match = scan(/#{RE::Function}/o)
151 tokens << [:open, :string]
152 start = match[/^\w+\(/]
153 tokens << [start, :delimiter]
154 if match[-1] == ?)
155 tokens << [match[start.size..-2], :content]
156 tokens << [')', :delimiter]
157 else
158 tokens << [match[start.size..-1], :content]
159 end
160 tokens << [:close, :string]
161 next
162
163 elsif scan(/(?: #{RE::Dimension} | #{RE::Percentage} | #{RE::Num} )/ox)
164 kind = :float
165
166 elsif scan(/#{RE::Color}/o)
167 kind = :color
168
169 elsif scan(/! *important/)
170 kind = :important
171
172 elsif scan(/rgb\([^()\n]*\)?/)
173 kind = :color
174
175 elsif scan(/#{RE::AtKeyword}/o)
176 kind = :directive
177
178 elsif match = scan(/ [+>:;,.=()\/] /x)
179 if match == ':'
180 value_expected = true
181 elsif match == ';'
182 value_expected = false
183 end
184 kind = :operator
185
186 else
187 getch
188 kind = :error
189
190 end
191
192 match ||= matched
193 if $CODERAY_DEBUG and not kind
194 raise_inspect 'Error token %p in line %d' %
195 [[match, kind], line], tokens
196 end
197 raise_inspect 'Empty token', tokens unless match
198
199 tokens << [match, kind]
200
201 end
202
203 tokens
204 end
205
206 end
207
208 end
209 end