rouge 0.0.13 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
@@ -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