| Class | CodeRay::Scanners::CSS |
| In: |
lib/coderay/scanners/css.rb
|
| Parent: | Scanner |
| KINDS_NOT_LOC | = | [ :comment, :class, :pseudo_class, :type, :constant, :directive, :key, :value, :operator, :color, :float, :content, :delimiter, :error, :important, ] |
# File lib/coderay/scanners/css.rb, line 52
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