rouge 0.0.13 → 0.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,19 +18,26 @@ load load_dir.join('rouge/version.rb')
18
18
  load load_dir.join('rouge/text_analyzer.rb')
19
19
  load load_dir.join('rouge/token.rb')
20
20
  load load_dir.join('rouge/lexer.rb')
21
+
21
22
  load load_dir.join('rouge/lexers/text.rb')
22
23
  load load_dir.join('rouge/lexers/diff.rb')
24
+ load load_dir.join('rouge/lexers/tex.rb')
23
25
 
26
+ load load_dir.join('rouge/lexers/make.rb')
24
27
  load load_dir.join('rouge/lexers/shell.rb')
25
28
 
26
29
  load load_dir.join('rouge/lexers/javascript.rb')
27
30
  load load_dir.join('rouge/lexers/css.rb')
28
31
  load load_dir.join('rouge/lexers/html.rb')
29
32
  load load_dir.join('rouge/lexers/xml.rb')
33
+ load load_dir.join('rouge/lexers/php.rb')
34
+
35
+ load load_dir.join('rouge/lexers/erb.rb')
30
36
 
31
37
  load load_dir.join('rouge/lexers/tcl.rb')
32
38
  load load_dir.join('rouge/lexers/python.rb')
33
39
  load load_dir.join('rouge/lexers/ruby.rb')
40
+ load load_dir.join('rouge/lexers/perl.rb')
34
41
 
35
42
  load load_dir.join('rouge/lexers/haskell.rb')
36
43
  load load_dir.join('rouge/lexers/scheme.rb')
@@ -42,6 +49,7 @@ load load_dir.join('rouge/lexers/java.rb')
42
49
 
43
50
  load load_dir.join('rouge/formatter.rb')
44
51
  load load_dir.join('rouge/formatters/html.rb')
52
+ load load_dir.join('rouge/formatters/terminal256.rb')
45
53
 
46
54
  load load_dir.join('rouge/theme.rb')
47
55
  load load_dir.join('rouge/themes/thankful_eyes.rb')
@@ -25,11 +25,13 @@ module Rouge
25
25
  end
26
26
 
27
27
  desc 'highlight [FILE]', 'highlight some code'
28
- option :file, :aliases => '-f', :desc => 'the file to operate on'
28
+ option :input_file, :aliases => '-i', :desc => 'the file to operate on'
29
29
  option :lexer, :aliases => '-l',
30
30
  :desc => ('Which lexer to use. If not provided, rougify will try to ' +
31
31
  'guess based on --mimetype, the filename, and the file ' +
32
32
  'contents.')
33
+ option :formatter, :aliases => '-f', :default => 'html',
34
+ :desc => ('Which formatter to use.')
33
35
  option :mimetype, :aliases => '-m',
34
36
  :desc => ('a mimetype that Rouge will use to guess the correct lexer. ' +
35
37
  'This is ignored if --lexer is specified.')
@@ -52,8 +54,10 @@ module Rouge
52
54
  raise "unknown lexer: #{options[:lexer]}" unless lexer_class
53
55
  end
54
56
 
57
+ formatter_class = Formatter.find(options[:formatter])
58
+
55
59
  # only HTML is supported for now
56
- formatter = Formatters::HTML.new(normalize_hash_keys(options[:formatter_opts]))
60
+ formatter = formatter_class.new(normalize_hash_keys(options[:formatter_opts]))
57
61
  lexer = lexer_class.new(normalize_hash_keys(options[:lexer_opts]))
58
62
 
59
63
  puts Rouge.highlight(source, lexer, formatter)
@@ -1,5 +1,18 @@
1
1
  module Rouge
2
2
  class Formatter
3
+ REGISTRY = {}
4
+
5
+ def self.tag(tag=nil)
6
+ return @tag unless tag
7
+ REGISTRY[tag] = self
8
+
9
+ @tag = tag
10
+ end
11
+
12
+ def self.find(tag)
13
+ REGISTRY[tag]
14
+ end
15
+
3
16
  def render(tokens)
4
17
  enum_for(:stream, tokens).to_a.join
5
18
  end
@@ -4,6 +4,8 @@ require 'cgi'
4
4
  module Rouge
5
5
  module Formatters
6
6
  class HTML < Formatter
7
+ tag 'html'
8
+
7
9
  def initialize(opts={})
8
10
  @css_class = opts[:css_class] || 'highlight'
9
11
  end
@@ -0,0 +1,152 @@
1
+ module Rouge
2
+ module Formatters
3
+ class Terminal256 < Formatter
4
+ tag 'terminal256'
5
+
6
+ attr_reader :theme
7
+ def initialize(opts={})
8
+ @theme = opts[:theme] || Themes::ThankfulEyes
9
+ @theme = Theme.find(@theme) if @theme.is_a? String
10
+ end
11
+
12
+ def stream(tokens, &b)
13
+ tokens.each do |tok, val|
14
+ escape = escape_sequence(tok)
15
+ yield escape.style_string
16
+ yield val
17
+ yield escape.reset_string
18
+ end
19
+ end
20
+
21
+ class EscapeSequence
22
+ attr_reader :style
23
+ def initialize(style)
24
+ @style = style
25
+ end
26
+
27
+ def self.xterm_colors
28
+ @xterm_colors ||= [].tap do |out|
29
+ # colors 0..15: 16 basic colors
30
+ out << [0x00, 0x00, 0x00] # 0
31
+ out << [0xcd, 0x00, 0x00] # 1
32
+ out << [0x00, 0xcd, 0x00] # 2
33
+ out << [0xcd, 0xcd, 0x00] # 3
34
+ out << [0x00, 0x00, 0xee] # 4
35
+ out << [0xcd, 0x00, 0xcd] # 5
36
+ out << [0x00, 0xcd, 0xcd] # 6
37
+ out << [0xe5, 0xe5, 0xe5] # 7
38
+ out << [0x7f, 0x7f, 0x7f] # 8
39
+ out << [0xff, 0x00, 0x00] # 9
40
+ out << [0x00, 0xff, 0x00] # 10
41
+ out << [0xff, 0xff, 0x00] # 11
42
+ out << [0x5c, 0x5c, 0xff] # 12
43
+ out << [0xff, 0x00, 0xff] # 13
44
+ out << [0x00, 0xff, 0xff] # 14
45
+ out << [0xff, 0xff, 0xff] # 15
46
+
47
+ # colors 16..232: the 6x6x6 color cube
48
+ valuerange = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff]
49
+
50
+ 217.times do |i|
51
+ r = valuerange[(i / 36) % 6]
52
+ g = valuerange[(i / 6) % 6]
53
+ b = valuerange[i % 6]
54
+ out << [r, g, b]
55
+ end
56
+
57
+ # colors 233..253: grayscale
58
+ 1.upto 22 do |i|
59
+ v = 8 + i * 10
60
+ out << [v, v, v]
61
+ end
62
+ end
63
+ end
64
+
65
+ def fg
66
+ return @fg if instance_variable_defined? :@fg
67
+ @fg = style.fg && self.class.color_index(style.fg)
68
+ end
69
+
70
+ def bg
71
+ return @bg if instance_variable_defined? :@bg
72
+ @bg = style.bg && self.class.color_index(style.bg)
73
+ end
74
+
75
+ def style_string
76
+ @style_string ||= begin
77
+ attrs = []
78
+
79
+ attrs << ['38', '5', fg.to_s] if fg
80
+ attrs << ['45', '5', bg.to_s] if bg
81
+ attrs << '01' if style[:bold]
82
+ attrs << '04' if style[:italic] # underline, but hey, whatevs
83
+ escape(attrs)
84
+ end
85
+ end
86
+
87
+ def reset_string
88
+ @reset_string ||= begin
89
+ attrs = []
90
+ attrs << '39' if fg # fg reset
91
+ attrs << '49' if bg # bg reset
92
+ attrs << '00' if style[:bold] || style[:italic]
93
+
94
+ escape(attrs)
95
+ end
96
+ end
97
+
98
+ # private
99
+ def escape(attrs)
100
+ return '' if attrs.empty?
101
+ "\e[#{attrs.join(';')}m"
102
+ end
103
+
104
+ def self.color_index(color)
105
+ @color_index_cache ||= {}
106
+ @color_index_cache[color] ||= closest_color(*get_rgb(color))
107
+ end
108
+
109
+ def self.get_rgb(color)
110
+ color = $1 if color =~ /#([0-9a-f]+)/i
111
+ hexes = case color.size
112
+ when 3
113
+ color.chars.map { |c| "#{c}#{c}" }
114
+ when 6
115
+ color.scan /../
116
+ else
117
+ raise "invalid color: #{color}"
118
+ end
119
+
120
+ hexes.map { |h| h.to_i(16) }
121
+ end
122
+
123
+ def self.closest_color(r, g, b)
124
+ distance = 257 * 257 * 3 # (max distance, from #000000 to #ffffff)
125
+
126
+ match = 0
127
+
128
+ xterm_colors.each_with_index do |(cr, cg, cb), i|
129
+ d = (r - cr)**2 + (g - cg)**2 + (b - cb)**2
130
+ next if d >= distance
131
+
132
+ match = i
133
+ distance = d
134
+ end
135
+
136
+ match
137
+ end
138
+ end
139
+
140
+ # private
141
+ def escape_sequence(token)
142
+ @escape_sequences ||= {}
143
+ @escape_sequences[token.name] ||= begin
144
+ esc = EscapeSequence.new(theme.get_style(token))
145
+ # don't highlight text backgrounds
146
+ esc.style.delete(:bg) if token.name == 'Text'
147
+ esc
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -4,35 +4,10 @@ require 'strscan'
4
4
  module Rouge
5
5
  class Lexer
6
6
  class << self
7
- def make(opts={}, &b)
8
- _sup = self
9
-
10
- Class.new(self) do
11
- @lazy_load_proc = b
12
- @default_options = _sup.default_options.merge(opts)
13
- @parent = _sup
14
- end
15
- end
16
-
17
7
  def lex(stream, opts={}, &b)
18
8
  new(opts).lex(stream, &b)
19
9
  end
20
10
 
21
- protected
22
- def force_load!
23
- return self if @force_load
24
- @force_load = true
25
- @lazy_load_proc && instance_eval(&@lazy_load_proc)
26
-
27
- self
28
- end
29
- public
30
-
31
- def new(*a, &b)
32
- force_load!
33
- super(*a, &b)
34
- end
35
-
36
11
  def default_options
37
12
  @default_options ||= {}
38
13
  end
@@ -121,7 +96,6 @@ module Rouge
121
96
 
122
97
  def initialize(opts={}, &b)
123
98
  options(opts)
124
- @lazy_load_proc = b
125
99
  end
126
100
 
127
101
  def options(o={})
@@ -146,9 +120,15 @@ module Rouge
146
120
  lex(stream).to_a
147
121
  end
148
122
 
149
- def lex(string, &b)
123
+ def reset!
124
+ # noop, called after each lex is finished
125
+ end
126
+
127
+ def lex(string, opts={}, &b)
150
128
  return enum_for(:lex, string) unless block_given?
151
129
 
130
+ reset! unless opts[:continue]
131
+
152
132
  last_token = nil
153
133
  last_val = nil
154
134
  stream_tokens(StringScanner.new(string)) do |tok, val|
@@ -244,7 +224,7 @@ module Rouge
244
224
  attr_accessor :scanner
245
225
  attr_accessor :stack
246
226
  attr_accessor :lexer
247
- def initialize(lexer, scanner, stack=nil)
227
+ def initialize(lexer, scanner=nil, stack=nil)
248
228
  @lexer = lexer
249
229
  @scanner = scanner
250
230
  @stack = stack || [lexer.get_state(:root)]
@@ -258,8 +238,15 @@ module Rouge
258
238
  end
259
239
 
260
240
  def push(state_name=nil, &b)
261
- debug { " pushing #{state_name || 'anonymous state'}" }
262
- stack.push(state.relative_state(state_name, &b))
241
+ # use the top of the stack by default
242
+ if state_name || b
243
+ push_state = state.relative_state(state_name, &b)
244
+ else
245
+ push_state = self.state
246
+ end
247
+
248
+ debug { " pushing #{push_state.name}" }
249
+ stack.push(push_state)
263
250
  end
264
251
 
265
252
  def in_state?(state_name)
@@ -300,10 +287,10 @@ module Rouge
300
287
  end
301
288
 
302
289
  def delegate(lexer, text=nil)
303
- debug { " delegating to #{lexer.name}" }
290
+ debug { " delegating to #{lexer.inspect}" }
304
291
  text ||= scanner[0]
305
292
 
306
- lexer.lex(text) do |tok, val|
293
+ lexer.lex(text, :continue => true) do |tok, val|
307
294
  debug { " delegated token: #{tok.inspect}, #{val.inspect}" }
308
295
  token(tok, val)
309
296
  end
@@ -352,8 +339,8 @@ module Rouge
352
339
  else
353
340
  tok = Token[tok]
354
341
 
355
- callback = proc do |ss|
356
- token tok, ss[0]
342
+ callback = proc do
343
+ token tok
357
344
  case next_state
358
345
  when :pop!
359
346
  pop!
@@ -388,16 +375,6 @@ module Rouge
388
375
  states[name] = State.new(self, name, &b)
389
376
  end
390
377
 
391
- def initialize(parent=nil, opts={}, &defn)
392
- if parent.is_a? Hash
393
- opts = parent
394
- parent = nil
395
- end
396
-
397
- @parent = parent
398
- super(opts, &defn)
399
- end
400
-
401
378
  def self.get_state(name)
402
379
  return name if name.is_a? State
403
380
 
@@ -414,18 +391,23 @@ module Rouge
414
391
  self.class.get_state(name)
415
392
  end
416
393
 
417
- def stream_tokens(stream, &b)
418
- scan_state = ScanState.new(self, stream)
394
+ def scan_state
395
+ @scan_state ||= ScanState.new(self)
396
+ end
397
+
398
+ def reset!
399
+ @scan_state = nil
419
400
 
420
401
  self.class.start_procs.each do |pr|
421
402
  scan_state.instance_eval(&pr)
422
403
  end
423
-
424
- stream_with_state(scan_state, &b)
425
404
  end
426
405
 
427
- def stream_with_state(scan_state, &b)
406
+ def stream_tokens(stream, &b)
407
+ scan_state.scanner = stream
408
+
428
409
  until scan_state.eos?
410
+ debug { "lexer: #{self.class.tag}" }
429
411
  debug { "stack: #{scan_state.stack.map(&:name).inspect}" }
430
412
  debug { "stream: #{scan_state.scanner.peek(20).inspect}" }
431
413
  success = step(get_state(scan_state.state), scan_state, &b)
@@ -0,0 +1,54 @@
1
+ module Rouge
2
+ module Lexers
3
+ class ERB < RegexLexer
4
+ tag 'erb'
5
+ aliases 'eruby', 'rhtml'
6
+
7
+ filenames '*.erb', '*.erubis', '*.rhtml', '*.eruby'
8
+
9
+ def self.analyze_text(text)
10
+ return 0.4 if text =~ /<%.*%>/
11
+ end
12
+
13
+ attr_reader :parent
14
+ attr_reader :ruby_lexer
15
+ def initialize(opts={})
16
+ @parent = opts.delete(:parent) || 'html'
17
+ if @parent.is_a? String
18
+ lexer_class = Lexer.find(@parent)
19
+ @parent = lexer_class.new(opts)
20
+ end
21
+
22
+ @ruby_lexer = Ruby.new(opts)
23
+
24
+ super(opts)
25
+ end
26
+
27
+ open = /<%%|<%=|<%#|<%-|<%/
28
+ close = /%%>|-%>|%>/
29
+
30
+ state :root do
31
+ rule /<%#/, 'Comment', :comment
32
+
33
+ rule open, 'Comment.Preproc', :ruby
34
+
35
+ rule /.+?(?=#{open})|.+/m do
36
+ delegate lexer.parent
37
+ end
38
+ end
39
+
40
+ state :comment do
41
+ rule close, 'Comment', :pop!
42
+ rule /.+(?=#{close})|.+/m, 'Comment'
43
+ end
44
+
45
+ state :ruby do
46
+ rule close, 'Comment.Preproc', :pop!
47
+
48
+ rule /.+?(?=#{close})|.+/m do
49
+ delegate lexer.ruby_lexer
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end