coderay 1.0.9 → 1.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +2 -0
  3. data/bin/coderay +4 -4
  4. data/lib/coderay.rb +2 -3
  5. data/lib/coderay/encoders/debug.rb +5 -17
  6. data/lib/coderay/encoders/debug_lint.rb +62 -0
  7. data/lib/coderay/encoders/html.rb +84 -84
  8. data/lib/coderay/encoders/html/css.rb +7 -7
  9. data/lib/coderay/encoders/html/numbering.rb +24 -19
  10. data/lib/coderay/encoders/html/output.rb +1 -1
  11. data/lib/coderay/encoders/lint.rb +57 -0
  12. data/lib/coderay/encoders/statistic.rb +0 -1
  13. data/lib/coderay/encoders/terminal.rb +121 -105
  14. data/lib/coderay/helpers/file_type.rb +54 -47
  15. data/lib/coderay/helpers/plugin.rb +4 -13
  16. data/lib/coderay/scanner.rb +58 -26
  17. data/lib/coderay/scanners/c.rb +1 -1
  18. data/lib/coderay/scanners/cpp.rb +1 -1
  19. data/lib/coderay/scanners/css.rb +22 -25
  20. data/lib/coderay/scanners/diff.rb +53 -31
  21. data/lib/coderay/scanners/groovy.rb +17 -4
  22. data/lib/coderay/scanners/html.rb +38 -16
  23. data/lib/coderay/scanners/java.rb +1 -1
  24. data/lib/coderay/scanners/java_script.rb +30 -6
  25. data/lib/coderay/scanners/json.rb +15 -12
  26. data/lib/coderay/scanners/lua.rb +280 -0
  27. data/lib/coderay/scanners/php.rb +22 -4
  28. data/lib/coderay/scanners/python.rb +3 -3
  29. data/lib/coderay/scanners/raydebug.rb +8 -8
  30. data/lib/coderay/scanners/ruby.rb +2 -2
  31. data/lib/coderay/scanners/sass.rb +232 -0
  32. data/lib/coderay/scanners/sql.rb +7 -4
  33. data/lib/coderay/scanners/taskpaper.rb +36 -0
  34. data/lib/coderay/scanners/yaml.rb +2 -2
  35. data/lib/coderay/styles/alpha.rb +31 -21
  36. data/lib/coderay/token_kinds.rb +68 -71
  37. data/lib/coderay/tokens.rb +23 -77
  38. data/lib/coderay/version.rb +1 -1
  39. data/test/functional/examples.rb +3 -3
  40. data/test/functional/for_redcloth.rb +4 -10
  41. metadata +13 -14
  42. data/lib/coderay/helpers/gzip.rb +0 -41
@@ -131,7 +131,7 @@ module CodeRay
131
131
 
132
132
  # A Hash of plugion_id => Plugin pairs.
133
133
  def plugin_hash
134
- @plugin_hash ||= make_plugin_hash
134
+ @plugin_hash ||= (@plugin_hash = make_plugin_hash).tap { load_plugin_map }
135
135
  end
136
136
 
137
137
  # Returns an array of all .rb files in the plugin path.
@@ -158,7 +158,6 @@ module CodeRay
158
158
  # This is done automatically when plugin_path is called.
159
159
  def load_plugin_map
160
160
  mapfile = path_to '_map'
161
- @plugin_map_loaded = true
162
161
  if File.exist? mapfile
163
162
  require mapfile
164
163
  true
@@ -171,23 +170,16 @@ module CodeRay
171
170
 
172
171
  # Return a plugin hash that automatically loads plugins.
173
172
  def make_plugin_hash
174
- @plugin_map_loaded ||= false
175
173
  Hash.new do |h, plugin_id|
176
174
  id = validate_id(plugin_id)
177
175
  path = path_to id
178
176
  begin
179
177
  require path
180
178
  rescue LoadError => boom
181
- if @plugin_map_loaded
182
- if h.has_key?(:default)
183
- warn '%p could not load plugin %p; falling back to %p' % [self, id, h[:default]]
184
- h[:default]
185
- else
186
- raise PluginNotFound, '%p could not load plugin %p: %s' % [self, id, boom]
187
- end
179
+ if h.has_key?(:default)
180
+ h[:default]
188
181
  else
189
- load_plugin_map
190
- h[plugin_id]
182
+ raise PluginNotFound, '%p could not load plugin %p: %s' % [self, id, boom]
191
183
  end
192
184
  else
193
185
  # Plugin should have registered by now
@@ -271,7 +263,6 @@ module CodeRay
271
263
  end
272
264
 
273
265
  def aliases
274
- plugin_host.load_plugin_map
275
266
  plugin_host.plugin_hash.inject [] do |aliases, (key, _)|
276
267
  aliases << key if plugin_host[key] == self
277
268
  aliases
@@ -182,16 +182,9 @@ module CodeRay
182
182
  # Scan the code and returns all tokens in a Tokens object.
183
183
  def tokenize source = nil, options = {}
184
184
  options = @options.merge(options)
185
- @tokens = options[:tokens] || @tokens || Tokens.new
186
- @tokens.scanner = self if @tokens.respond_to? :scanner=
187
- case source
188
- when Array
189
- self.string = self.class.normalize(source.join)
190
- when nil
191
- reset
192
- else
193
- self.string = self.class.normalize(source)
194
- end
185
+
186
+ set_tokens_from_options options
187
+ set_string_from_source source
195
188
 
196
189
  begin
197
190
  scan_tokens @tokens, options
@@ -261,6 +254,22 @@ module CodeRay
261
254
  def setup # :doc:
262
255
  end
263
256
 
257
+ def set_string_from_source source
258
+ case source
259
+ when Array
260
+ self.string = self.class.normalize(source.join)
261
+ when nil
262
+ reset
263
+ else
264
+ self.string = self.class.normalize(source)
265
+ end
266
+ end
267
+
268
+ def set_tokens_from_options options
269
+ @tokens = options[:tokens] || @tokens || Tokens.new
270
+ @tokens.scanner = self if @tokens.respond_to? :scanner=
271
+ end
272
+
264
273
  # This is the central method, and commonly the only one a
265
274
  # subclass implements.
266
275
  #
@@ -277,19 +286,15 @@ module CodeRay
277
286
  @binary_string = nil if defined? @binary_string
278
287
  end
279
288
 
280
- # Scanner error with additional status information
281
- def raise_inspect msg, tokens, state = self.state || 'No state given!', ambit = 30, backtrace = caller
282
- raise ScanError, <<-EOE % [
289
+ SCAN_ERROR_MESSAGE = <<-MESSAGE
283
290
 
284
291
 
285
- ***ERROR in %s: %s (after %d tokens)
292
+ ***ERROR in %s: %s (after %s tokens)
286
293
 
287
294
  tokens:
288
295
  %s
289
296
 
290
- current line: %d column: %d pos: %d
291
- matched: %p state: %p
292
- bol? = %p, eos? = %p
297
+ %s
293
298
 
294
299
  surrounding code:
295
300
  %p ~~ %p
@@ -297,16 +302,43 @@ surrounding code:
297
302
 
298
303
  ***ERROR***
299
304
 
300
- EOE
301
- File.basename(caller[0]),
302
- msg,
303
- tokens.respond_to?(:size) ? tokens.size : 0,
304
- tokens.respond_to?(:last) ? tokens.last(10).map { |t| t.inspect }.join("\n") : '',
305
- line, column, pos,
306
- matched, state, bol?, eos?,
305
+ MESSAGE
306
+
307
+ def raise_inspect_arguments message, tokens, state, ambit
308
+ return File.basename(caller[0]),
309
+ message,
310
+ tokens_size(tokens),
311
+ tokens_last(tokens, 10).map(&:inspect).join("\n"),
312
+ scanner_state_info(state),
307
313
  binary_string[pos - ambit, ambit],
308
- binary_string[pos, ambit],
309
- ], backtrace
314
+ binary_string[pos, ambit]
315
+ end
316
+
317
+ SCANNER_STATE_INFO = <<-INFO
318
+ current line: %d column: %d pos: %d
319
+ matched: %p state: %p
320
+ bol?: %p, eos?: %p
321
+ INFO
322
+
323
+ def scanner_state_info state
324
+ SCANNER_STATE_INFO % [
325
+ line, column, pos,
326
+ matched, state || 'No state given!',
327
+ bol?, eos?,
328
+ ]
329
+ end
330
+
331
+ # Scanner error with additional status information
332
+ def raise_inspect message, tokens, state = self.state, ambit = 30, backtrace = caller
333
+ raise ScanError, SCAN_ERROR_MESSAGE % raise_inspect_arguments(message, tokens, state, ambit), backtrace
334
+ end
335
+
336
+ def tokens_size tokens
337
+ tokens.size if tokens.respond_to?(:size)
338
+ end
339
+
340
+ def tokens_last tokens, n
341
+ tokens.respond_to?(:last) ? tokens.last(n) : []
310
342
  end
311
343
 
312
344
  # Shorthand for scan_until(/\z/).
@@ -148,7 +148,7 @@ module Scanners
148
148
  encoder.text_token match, :char
149
149
  elsif match = scan(/ \\ | $ /x)
150
150
  encoder.end_group :string
151
- encoder.text_token match, :error
151
+ encoder.text_token match, :error unless match.empty?
152
152
  state = :initial
153
153
  label_expected = false
154
154
  else
@@ -160,7 +160,7 @@ module Scanners
160
160
  encoder.text_token match, :char
161
161
  elsif match = scan(/ \\ | $ /x)
162
162
  encoder.end_group :string
163
- encoder.text_token match, :error
163
+ encoder.text_token match, :error unless match.empty?
164
164
  state = :initial
165
165
  label_expected = false
166
166
  else
@@ -7,27 +7,25 @@ module Scanners
7
7
 
8
8
  KINDS_NOT_LOC = [
9
9
  :comment,
10
- :class, :pseudo_class, :type,
11
- :constant, :directive,
10
+ :class, :pseudo_class, :tag,
11
+ :id, :directive,
12
12
  :key, :value, :operator, :color, :float, :string,
13
- :error, :important,
13
+ :error, :important, :type,
14
14
  ] # :nodoc:
15
15
 
16
16
  module RE # :nodoc:
17
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
18
+ Unicode = /\\#{Hex}{1,6}\b/ # differs from standard because it allows uppercase hex too
19
+ Escape = /#{Unicode}|\\[^\n0-9a-fA-F]/
20
+ NMChar = /[-_a-zA-Z0-9]/
21
+ NMStart = /[_a-zA-Z]/
22
+ String1 = /"(?:[^\n\\"]+|\\\n|#{Escape})*"?/ # TODO: buggy regexp
23
+ String2 = /'(?:[^\n\\']+|\\\n|#{Escape})*'?/ # TODO: buggy regexp
25
24
  String = /#{String1}|#{String2}/
26
25
 
27
26
  HexColor = /#(?:#{Hex}{6}|#{Hex}{3})/
28
- Color = /#{HexColor}/
29
27
 
30
- Num = /-?(?:[0-9]+|[0-9]*\.[0-9]+)/
28
+ Num = /-?(?:[0-9]*\.[0-9]+|[0-9]+)n?/
31
29
  Name = /#{NMChar}+/
32
30
  Ident = /-?#{NMStart}#{NMChar}*/
33
31
  AtKeyword = /@#{Ident}/
@@ -35,16 +33,15 @@ module Scanners
35
33
 
36
34
  reldimensions = %w[em ex px]
37
35
  absdimensions = %w[in cm mm pt pc]
38
- Unit = Regexp.union(*(reldimensions + absdimensions + %w[s]))
36
+ Unit = Regexp.union(*(reldimensions + absdimensions + %w[s dpi dppx deg]))
39
37
 
40
38
  Dimension = /#{Num}#{Unit}/
41
39
 
42
- Comment = %r! /\* (?: .*? \*/ | .* ) !mx
43
- Function = /(?:url|alpha|attr|counters?)\((?:[^)\n\r\f]|\\\))*\)?/
40
+ Function = /(?:url|alpha|attr|counters?)\((?:[^)\n]|\\\))*\)?/
44
41
 
45
- Id = /##{Name}/
42
+ Id = /(?!#{HexColor}\b(?!-))##{Name}/
46
43
  Class = /\.#{Name}/
47
- PseudoClass = /:#{Name}/
44
+ PseudoClass = /::?#{Ident}/
48
45
  AttributeSelector = /\[[^\]]*\]?/
49
46
  end
50
47
 
@@ -52,11 +49,11 @@ module Scanners
52
49
 
53
50
  def setup
54
51
  @state = :initial
55
- @value_expected = nil
52
+ @value_expected = false
56
53
  end
57
54
 
58
55
  def scan_tokens encoder, options
59
- states = Array(options[:state] || @state)
56
+ states = Array(options[:state] || @state).dup
60
57
  value_expected = @value_expected
61
58
 
62
59
  until eos?
@@ -67,13 +64,13 @@ module Scanners
67
64
  elsif case states.last
68
65
  when :initial, :media
69
66
  if match = scan(/(?>#{RE::Ident})(?!\()|\*/ox)
70
- encoder.text_token match, :type
67
+ encoder.text_token match, :tag
71
68
  next
72
69
  elsif match = scan(RE::Class)
73
70
  encoder.text_token match, :class
74
71
  next
75
72
  elsif match = scan(RE::Id)
76
- encoder.text_token match, :constant
73
+ encoder.text_token match, :id
77
74
  next
78
75
  elsif match = scan(RE::PseudoClass)
79
76
  encoder.text_token match, :pseudo_class
@@ -148,17 +145,17 @@ module Scanners
148
145
  start = match[/^\w+\(/]
149
146
  encoder.text_token start, :delimiter
150
147
  if match[-1] == ?)
151
- encoder.text_token match[start.size..-2], :content
148
+ encoder.text_token match[start.size..-2], :content if match.size > start.size + 1
152
149
  encoder.text_token ')', :delimiter
153
150
  else
154
- encoder.text_token match[start.size..-1], :content
151
+ encoder.text_token match[start.size..-1], :content if match.size > start.size
155
152
  end
156
153
  encoder.end_group :function
157
154
 
158
155
  elsif match = scan(/(?: #{RE::Dimension} | #{RE::Percentage} | #{RE::Num} )/ox)
159
156
  encoder.text_token match, :float
160
157
 
161
- elsif match = scan(/#{RE::Color}/o)
158
+ elsif match = scan(/#{RE::HexColor}/o)
162
159
  encoder.text_token match, :color
163
160
 
164
161
  elsif match = scan(/! *important/)
@@ -170,7 +167,7 @@ module Scanners
170
167
  elsif match = scan(RE::AtKeyword)
171
168
  encoder.text_token match, :directive
172
169
 
173
- elsif match = scan(/ [+>:;,.=()\/] /x)
170
+ elsif match = scan(/ [+>~:;,.=()\/] /x)
174
171
  if match == ':'
175
172
  value_expected = true
176
173
  elsif match == ';'
@@ -20,7 +20,7 @@ module Scanners
20
20
 
21
21
  line_kind = nil
22
22
  state = :initial
23
- deleted_lines = 0
23
+ deleted_lines_count = 0
24
24
  scanners = Hash.new do |h, lang|
25
25
  h[lang] = Scanners[lang].new '', :keep_tokens => true, :keep_state => true
26
26
  end
@@ -30,7 +30,7 @@ module Scanners
30
30
  until eos?
31
31
 
32
32
  if match = scan(/\n/)
33
- deleted_lines = 0 unless line_kind == :delete
33
+ deleted_lines_count = 0 unless line_kind == :delete
34
34
  if line_kind
35
35
  encoder.end_line line_kind
36
36
  line_kind = nil
@@ -45,7 +45,7 @@ module Scanners
45
45
  if match = scan(/--- |\+\+\+ |=+|_+/)
46
46
  encoder.begin_line line_kind = :head
47
47
  encoder.text_token match, :head
48
- if match = scan(/.*?(?=$|[\t\n\x00]| \(revision)/)
48
+ if match = scan(/[^\x00\n]+?(?=$|[\t\n]| \(revision)/)
49
49
  encoder.text_token match, :filename
50
50
  if options[:highlight_code] && match != '/dev/null'
51
51
  file_type = CodeRay::FileType.fetch(match, :text)
@@ -69,7 +69,7 @@ module Scanners
69
69
  state = :added
70
70
  elsif match = scan(/\\ .*/)
71
71
  encoder.text_token match, :comment
72
- elsif match = scan(/@@(?>[^@\n]*)@@/)
72
+ elsif match = scan(/@@(?>[^@\n]+)@@/)
73
73
  content_scanner.state = :initial unless match?(/\n\+/)
74
74
  content_scanner_entry_state = nil
75
75
  if check(/\n|$/)
@@ -99,37 +99,59 @@ module Scanners
99
99
  end
100
100
  next
101
101
  elsif match = scan(/-/)
102
- deleted_lines += 1
103
- encoder.begin_line line_kind = :delete
104
- encoder.text_token match, :delete
105
- if options[:inline_diff] && deleted_lines == 1 && check(/(?>.*)\n\+(?>.*)$(?!\n\+)/)
106
- content_scanner_entry_state = content_scanner.state
107
- skip(/(.*)\n\+(.*)$/)
108
- head, deletion, insertion, tail = diff self[1], self[2]
109
- pre, deleted, post = content_scanner.tokenize [head, deletion, tail], :tokens => Tokens.new
110
- encoder.tokens pre
111
- unless deleted.empty?
112
- encoder.begin_group :eyecatcher
113
- encoder.tokens deleted
114
- encoder.end_group :eyecatcher
102
+ deleted_lines_count += 1
103
+ if options[:inline_diff] && deleted_lines_count == 1 && (changed_lines_count = 1 + check(/.*(?:\n\-.*)*/).count("\n")) && match?(/(?>.*(?:\n\-.*){#{changed_lines_count - 1}}(?:\n\+.*){#{changed_lines_count}})$(?!\n\+)/)
104
+ deleted_lines = Array.new(changed_lines_count) { |i| skip(/\n\-/) if i > 0; scan(/.*/) }
105
+ inserted_lines = Array.new(changed_lines_count) { |i| skip(/\n\+/) ; scan(/.*/) }
106
+
107
+ deleted_lines_tokenized = []
108
+ inserted_lines_tokenized = []
109
+ for deleted_line, inserted_line in deleted_lines.zip(inserted_lines)
110
+ pre, deleted_part, inserted_part, post = diff deleted_line, inserted_line
111
+ content_scanner_entry_state = content_scanner.state
112
+ deleted_lines_tokenized << content_scanner.tokenize([pre, deleted_part, post], :tokens => Tokens.new)
113
+ content_scanner.state = content_scanner_entry_state || :initial
114
+ inserted_lines_tokenized << content_scanner.tokenize([pre, inserted_part, post], :tokens => Tokens.new)
115
115
  end
116
- encoder.tokens post
117
- encoder.end_line line_kind
118
- encoder.text_token "\n", :space
119
- encoder.begin_line line_kind = :insert
120
- encoder.text_token '+', :insert
121
- content_scanner.state = content_scanner_entry_state || :initial
122
- pre, inserted, post = content_scanner.tokenize [head, insertion, tail], :tokens => Tokens.new
123
- encoder.tokens pre
124
- unless inserted.empty?
125
- encoder.begin_group :eyecatcher
126
- encoder.tokens inserted
127
- encoder.end_group :eyecatcher
116
+
117
+ for pre, deleted_part, post in deleted_lines_tokenized
118
+ encoder.begin_line :delete
119
+ encoder.text_token '-', :delete
120
+ encoder.tokens pre
121
+ unless deleted_part.empty?
122
+ encoder.begin_group :eyecatcher
123
+ encoder.tokens deleted_part
124
+ encoder.end_group :eyecatcher
125
+ end
126
+ encoder.tokens post
127
+ encoder.end_line :delete
128
+ encoder.text_token "\n", :space
129
+ end
130
+
131
+ for pre, inserted_part, post in inserted_lines_tokenized
132
+ encoder.begin_line :insert
133
+ encoder.text_token '+', :insert
134
+ encoder.tokens pre
135
+ unless inserted_part.empty?
136
+ encoder.begin_group :eyecatcher
137
+ encoder.tokens inserted_part
138
+ encoder.end_group :eyecatcher
139
+ end
140
+ encoder.tokens post
141
+ changed_lines_count -= 1
142
+ if changed_lines_count > 0
143
+ encoder.end_line :insert
144
+ encoder.text_token "\n", :space
145
+ end
128
146
  end
129
- encoder.tokens post
147
+
148
+ line_kind = :insert
149
+
130
150
  elsif match = scan(/.*/)
151
+ encoder.begin_line line_kind = :delete
152
+ encoder.text_token '-', :delete
131
153
  if options[:highlight_code]
132
- if deleted_lines == 1
154
+ if deleted_lines_count == 1
133
155
  content_scanner_entry_state = content_scanner.state
134
156
  end
135
157
  content_scanner.tokenize match, :tokens => encoder unless match.empty?
@@ -36,9 +36,12 @@ module Scanners
36
36
 
37
37
  protected
38
38
 
39
+ def setup
40
+ @state = :initial
41
+ end
42
+
39
43
  def scan_tokens encoder, options
40
-
41
- state = :initial
44
+ state = options[:state] || @state
42
45
  inline_block_stack = []
43
46
  inline_block_paren_depth = nil
44
47
  string_delimiter = nil
@@ -223,7 +226,7 @@ module Scanners
223
226
  encoder.text_token match, :content # TODO: Shouldn't this be :error?
224
227
 
225
228
  elsif match = scan(/ \\ | \n /x)
226
- encoder.end_group state
229
+ encoder.end_group state == :regexp ? :regexp : :string
227
230
  encoder.text_token match, :error
228
231
  after_def = value_expected = false
229
232
  state = :initial
@@ -243,7 +246,17 @@ module Scanners
243
246
  end
244
247
 
245
248
  if [:multiline_string, :string, :regexp].include? state
246
- encoder.end_group state
249
+ encoder.end_group state == :regexp ? :regexp : :string
250
+ end
251
+
252
+ if options[:keep_state]
253
+ @state = state
254
+ end
255
+
256
+ until inline_block_stack.empty?
257
+ state, = *inline_block_stack.pop
258
+ encoder.end_group :inline
259
+ encoder.end_group state == :regexp ? :regexp : :string
247
260
  end
248
261
 
249
262
  encoder