rouge 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -15,3 +15,4 @@ gem 'sinatra'
15
15
 
16
16
  # docs
17
17
  gem 'yard'
18
+ gem 'github-markup'
@@ -30,8 +30,11 @@ load load_dir.join('rouge/lexers/tex.rb')
30
30
  load load_dir.join('rouge/lexers/markdown.rb')
31
31
  load load_dir.join('rouge/lexers/yaml.rb')
32
32
 
33
+ load load_dir.join('rouge/lexers/sql.rb')
34
+
33
35
  load load_dir.join('rouge/lexers/make.rb')
34
36
  load load_dir.join('rouge/lexers/shell.rb')
37
+ load load_dir.join('rouge/lexers/viml.rb')
35
38
 
36
39
  load load_dir.join('rouge/lexers/javascript.rb')
37
40
  load load_dir.join('rouge/lexers/css.rb')
@@ -17,7 +17,7 @@ module Rouge
17
17
  exit 0
18
18
  end
19
19
 
20
- unless %w(highlight style).include?(argv.first)
20
+ unless %w(highlight style list --help -h help).include?(argv.first)
21
21
  argv.unshift 'highlight'
22
22
  end
23
23
 
@@ -30,7 +30,7 @@ module Rouge
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',
33
+ option :formatter, :aliases => '-f', :default => 'terminal256',
34
34
  :desc => ('Which formatter to use.')
35
35
  option :mimetype, :aliases => '-m',
36
36
  :desc => ('a mimetype that Rouge will use to guess the correct lexer. ' +
@@ -71,6 +71,22 @@ module Rouge
71
71
  puts theme.new(options).render
72
72
  end
73
73
 
74
+ desc 'list', 'list the available lexers, formatters, and styles'
75
+ def list
76
+ puts "== Available Lexers =="
77
+ all_lexers = Lexer.all
78
+ max_len = all_lexers.map { |l| l.tag.size }.max
79
+
80
+ Lexer.all.each do |lexer|
81
+ desc = "#{lexer.desc}"
82
+ if lexer.aliases.any?
83
+ desc << " [aliases: #{lexer.aliases.join(',')}]"
84
+ end
85
+ puts "%s: %s" % [lexer.tag, desc]
86
+ puts
87
+ end
88
+ end
89
+
74
90
  private
75
91
  # TODO: does Thor do this for me?
76
92
  def normalize_hash_keys(hash)
@@ -1,7 +1,10 @@
1
1
  module Rouge
2
+ # A Formatter takes a token stream and formats it for human viewing.
2
3
  class Formatter
3
4
  REGISTRY = {}
4
5
 
6
+ # Specify or get the unique tag for this formatter. This is used
7
+ # for specifying a formatter in `rougify`.
5
8
  def self.tag(tag=nil)
6
9
  return @tag unless tag
7
10
  REGISTRY[tag] = self
@@ -9,14 +12,18 @@ module Rouge
9
12
  @tag = tag
10
13
  end
11
14
 
15
+ # Find a formatter class given a unique tag.
12
16
  def self.find(tag)
13
17
  REGISTRY[tag]
14
18
  end
15
19
 
20
+ # Format a token stream.
16
21
  def render(tokens)
17
22
  enum_for(:stream, tokens).to_a.join
18
23
  end
19
24
 
25
+ # @abstract
26
+ # yield strings that, when concatenated, form the formatted output
20
27
  def stream(tokens, &b)
21
28
  raise 'abstract'
22
29
  end
@@ -3,13 +3,17 @@ require 'cgi'
3
3
 
4
4
  module Rouge
5
5
  module Formatters
6
+ # Transforms a token stream into HTML output.
6
7
  class HTML < Formatter
7
8
  tag 'html'
8
9
 
10
+ # @option opts :css_class
11
+ # A css class to be used for the generated <pre> tag.
9
12
  def initialize(opts={})
10
13
  @css_class = opts[:css_class] || 'highlight'
11
14
  end
12
15
 
16
+ # @yield the html output.
13
17
  def stream(tokens, &b)
14
18
  yield "<pre class=#{@css_class.inspect}>"
15
19
  tokens.each do |tok, val|
@@ -1,11 +1,17 @@
1
1
  module Rouge
2
2
  module Formatters
3
+ # A formatter for 256-color terminals
3
4
  class Terminal256 < Formatter
4
5
  tag 'terminal256'
5
6
 
7
+ # @private
6
8
  attr_reader :theme
9
+
10
+
11
+ # @option opts :theme
12
+ # (default is thankful_eyes) the theme to render with.
7
13
  def initialize(opts={})
8
- @theme = opts[:theme] || Themes::ThankfulEyes
14
+ @theme = opts[:theme] || 'thankful_eyes'
9
15
  @theme = Theme.find(@theme) if @theme.is_a? String
10
16
  end
11
17
 
@@ -95,7 +101,7 @@ module Rouge
95
101
  end
96
102
  end
97
103
 
98
- # private
104
+ private
99
105
  def escape(attrs)
100
106
  return '' if attrs.empty?
101
107
  "\e[#{attrs.join(';')}m"
@@ -2,6 +2,8 @@
2
2
  require 'strscan'
3
3
 
4
4
  module Rouge
5
+ # @abstract
6
+ # A lexer transforms text into a stream of `[token, chunk]` pairs.
5
7
  class Lexer
6
8
  class << self
7
9
  # Lexes `stream` with the given options. The lex is delegated to a
@@ -23,6 +25,20 @@ module Rouge
23
25
  registry[name.to_s]
24
26
  end
25
27
 
28
+ # Specify or get this lexer's description.
29
+ def desc(arg=:absent)
30
+ if arg == :absent
31
+ @desc
32
+ else
33
+ @desc = arg
34
+ end
35
+ end
36
+
37
+ # @return a list of all lexers.
38
+ def all
39
+ registry.values.uniq
40
+ end
41
+
26
42
  # Guess which lexer to use based on a hash of info.
27
43
  #
28
44
  # @option info :mimetype
@@ -82,6 +98,7 @@ module Rouge
82
98
  best_match
83
99
  end
84
100
 
101
+ # @private
85
102
  def register(name, lexer)
86
103
  registry[name.to_s] = lexer
87
104
  end
@@ -100,7 +117,7 @@ module Rouge
100
117
  return @tag if t.nil?
101
118
 
102
119
  @tag = t.to_s
103
- aliases @tag
120
+ Lexer.register(@tag, self)
104
121
  end
105
122
 
106
123
  # Used to specify alternate names this lexer class may be found by.
@@ -113,10 +130,12 @@ module Rouge
113
130
  #
114
131
  # Lexer.find('eruby') # => Erb
115
132
  def aliases(*args)
133
+ args.map!(&:to_s)
116
134
  args.each { |arg| Lexer.register(arg, self) }
135
+ (@aliases ||= []).concat(args)
117
136
  end
118
137
 
119
- # Specify a list of filename globs associated with this lexer
138
+ # Specify a list of filename globs associated with this lexer.
120
139
  #
121
140
  # @example
122
141
  # class Ruby < Lexer
@@ -144,16 +163,27 @@ module Rouge
144
163
 
145
164
  # -*- instance methods -*- #
146
165
 
166
+ # Create a new lexer with the given options. Individual lexers may
167
+ # specify extra options. The only current globally accepted option
168
+ # is `:debug`.
169
+ #
170
+ # @option opts :debug
171
+ # Prints debug information to stdout. The particular info depends
172
+ # on the lexer in question. In regex lexers, this will log the
173
+ # state stack at the beginning of each step, along with each regex
174
+ # tried and each stream consumed. Try it, it's pretty useful.
147
175
  def initialize(opts={})
148
176
  options(opts)
149
177
  end
150
178
 
179
+ # get and/or specify the options for this lexer.
151
180
  def options(o={})
152
181
  (@options ||= {}).merge!(o)
153
182
 
154
183
  self.class.default_options.merge(@options)
155
184
  end
156
185
 
186
+ # get or specify one option for this lexer
157
187
  def option(k, v=:absent)
158
188
  if v == :absent
159
189
  options[k]
@@ -209,7 +239,7 @@ module Rouge
209
239
 
210
240
  # @abstract
211
241
  #
212
- # Yield [token, chunk] pairs, given a prepared input stream. This
242
+ # Yield `[token, chunk]` pairs, given a prepared input stream. This
213
243
  # must be implemented.
214
244
  #
215
245
  # @param [StringScanner] stream
@@ -220,7 +250,7 @@ module Rouge
220
250
 
221
251
  # @abstract
222
252
  #
223
- # return a number between 0 and 1 indicating the likelihood that
253
+ # Return a number between 0 and 1 indicating the likelihood that
224
254
  # the text given should be lexed with this lexer. The default
225
255
  # implementation returns 0.
226
256
  #
@@ -5,6 +5,8 @@ module Rouge
5
5
  filenames '*.c', '*.h', '*.idc'
6
6
  mimetypes 'text/x-chdr', 'text/x-csrc'
7
7
 
8
+ desc "The C programming language"
9
+
8
10
  # optional comment or whitespace
9
11
  ws = %r((?:\s|//.*?\n|/[*].*?[*]/)+)
10
12
  id = /[a-zA-Z_][a-zA-Z0-9_]*/
@@ -55,6 +57,7 @@ module Rouge
55
57
  rule /__(?:#{__reserved.join('|')})\b/, 'Keyword.Reserved'
56
58
  rule /(?:true|false|NULL)\b/, 'Name.Builtin'
57
59
  rule id, 'Name'
60
+ rule /\s+/m, 'Text'
58
61
  end
59
62
 
60
63
  state :case do
@@ -4,6 +4,7 @@ require 'set'
4
4
  module Rouge
5
5
  module Lexers
6
6
  class CommonLisp < RegexLexer
7
+ desc "The Common Lisp variant of Lisp (common-lisp.net)"
7
8
  tag 'common_lisp'
8
9
  aliases 'cl', 'common-lisp'
9
10
 
@@ -1,6 +1,8 @@
1
1
  module Rouge
2
2
  module Lexers
3
3
  class Cpp < RegexLexer
4
+ desc "The C++ programming language"
5
+
4
6
  tag 'cpp'
5
7
  aliases 'c++'
6
8
  # the many varied filenames of c++ source files...
@@ -1,6 +1,8 @@
1
1
  module Rouge
2
2
  module Lexers
3
3
  class CSS < RegexLexer
4
+ desc "Cascading Style Sheets, used to style web pages"
5
+
4
6
  tag 'css'
5
7
  filenames '*.css'
6
8
  mimetypes 'text/css'
@@ -1,6 +1,8 @@
1
1
  module Rouge
2
2
  module Lexers
3
3
  class Diff < RegexLexer
4
+ desc "Lexes unified diffs or patches"
5
+
4
6
  tag 'diff'
5
7
  aliases 'patch', 'udiff'
6
8
  filenames '*.diff', '*.patch'
@@ -1,6 +1,8 @@
1
1
  module Rouge
2
2
  module Lexers
3
3
  class ERB < TemplateLexer
4
+ desc "Embedded ruby template files"
5
+
4
6
  tag 'erb'
5
7
  aliases 'eruby', 'rhtml'
6
8
 
@@ -1,6 +1,7 @@
1
1
  module Rouge
2
2
  module Lexers
3
3
  class Factor < RegexLexer
4
+ desc "Factor, the practical stack language (factorcode.org)"
4
5
  tag 'factor'
5
6
  filenames '*.factor'
6
7
  mimetypes 'text/x-factor'
@@ -1,6 +1,10 @@
1
1
  module Rouge
2
2
  module Lexers
3
+ # A lexer for the Haml templating system for Ruby.
4
+ # @see http://haml.info
3
5
  class Haml < RegexLexer
6
+ desc "The Haml templating system for Ruby (haml.info)"
7
+
4
8
  tag 'haml'
5
9
  aliases 'HAML'
6
10
 
@@ -11,9 +15,10 @@ module Rouge
11
15
  return 0.1 if text.start_with? '!!!'
12
16
  end
13
17
 
14
- # option :filters is a hash of filter name to lexer of how
15
- # various filters should be highlighted. By default, :javascript
16
- # and :stylesheet are supported.
18
+ # @option opts :filters
19
+ # A hash of filter name to lexer of how various filters should be
20
+ # highlighted. By default, :javascript, :css, :ruby, and :erb
21
+ # are supported.
17
22
  def initialize(opts={})
18
23
  (opts.delete(:filters) || {}).each do |name, lexer|
19
24
  unless lexer.respond_to? :lex
@@ -41,10 +46,10 @@ module Rouge
41
46
  'css' => CSS.new(options),
42
47
  'ruby' => ruby,
43
48
  'erb' => ERB.new(options),
49
+ 'markdown' => Markdown.new(options),
44
50
  # TODO
45
51
  # 'sass' => Sass.new(options),
46
52
  # 'textile' => Textile.new(options),
47
- # 'markdown' => Markdown.new(options),
48
53
  # 'maruku' => Maruku.new(options),
49
54
  }
50
55
  end
@@ -1,6 +1,8 @@
1
1
  module Rouge
2
2
  module Lexers
3
3
  class Haskell < RegexLexer
4
+ desc "The Haskell programming language (haskell.org)"
5
+
4
6
  tag 'haskell'
5
7
  aliases 'hs'
6
8
  filenames '*.hs'
@@ -1,6 +1,7 @@
1
1
  module Rouge
2
2
  module Lexers
3
3
  class HTML < RegexLexer
4
+ desc "HTML, the markup language of the web"
4
5
  tag 'html'
5
6
  filenames '*.htm', '*.html', '*.xhtml', '*.xslt'
6
7
  mimetypes 'text/html', 'application/xhtml+xml'
@@ -1,6 +1,8 @@
1
1
  module Rouge
2
2
  module Lexers
3
3
  class Java < RegexLexer
4
+ desc "The Java programming language (java.com)"
5
+
4
6
  tag 'java'
5
7
  filenames '*.java'
6
8
  mimetypes 'text/x-java'
@@ -1,6 +1,8 @@
1
1
  module Rouge
2
2
  module Lexers
3
3
  class Javascript < RegexLexer
4
+ desc "JavaScript, the browser scripting language"
5
+
4
6
  tag 'javascript'
5
7
  aliases 'js'
6
8
  filenames '*.js'
@@ -94,6 +96,7 @@ module Rouge
94
96
  end
95
97
 
96
98
  class JSON < RegexLexer
99
+ desc "JavaScript Object Notation (json.org)"
97
100
  tag 'json'
98
101
  filenames '*.json'
99
102
  mimetypes 'application/json'
@@ -102,7 +105,7 @@ module Rouge
102
105
  # so I'd think this wouldn't be too bad, but for large documents this
103
106
  # could mean doing two full lexes.
104
107
  def self.analyze_text(text)
105
- text.lexes_cleanly?(self) ? 0.8 : 0
108
+ return 0.8 if text =~ /\A\s*{/m && text.lexes_cleanly?(self)
106
109
  end
107
110
 
108
111
  state :root do
@@ -1,6 +1,7 @@
1
1
  module Rouge
2
2
  module Lexers
3
3
  class Make < RegexLexer
4
+ desc "Makefile syntax"
4
5
  tag 'make'
5
6
  aliases 'makefile', 'mf', 'gnumake', 'bsdmake'
6
7
  filenames '*.make', 'Makefile', 'makefile', 'Makefile.*', 'GNUmakefile'
@@ -1,6 +1,8 @@
1
1
  module Rouge
2
2
  module Lexers
3
3
  class Markdown < RegexLexer
4
+ desc "Markdown, a light-weight markup language for authors"
5
+
4
6
  tag 'markdown'
5
7
  aliases 'md', 'mkd'
6
8
  filenames '*.markdown', '*.md', '*.mkd'
@@ -1,6 +1,8 @@
1
1
  module Rouge
2
2
  module Lexers
3
3
  class Perl < RegexLexer
4
+ desc "The Perl scripting language (perl.org)"
5
+
4
6
  tag 'perl'
5
7
  aliases 'pl'
6
8
 
@@ -1,6 +1,7 @@
1
1
  module Rouge
2
2
  module Lexers
3
3
  class PHP < TemplateLexer
4
+ desc "The PHP scripting language (php.net)"
4
5
  tag 'php'
5
6
  aliases 'php', 'php3', 'php4', 'php5'
6
7
  filenames '*.php', '*.php[345]'
@@ -18,12 +19,15 @@ module Rouge
18
19
  super(opts)
19
20
  end
20
21
 
22
+ def self.builtins
23
+ load Pathname.new(__FILE__).dirname.join('php/builtins.rb')
24
+ self.builtins
25
+ end
26
+
21
27
  def builtins
22
28
  return [] unless @funcnamehighlighting
23
29
 
24
30
  @builtins ||= Set.new.tap do |builtins|
25
- require Pathname.new(__FILE__).dirname.join('php/builtins.rb')
26
-
27
31
  self.class.builtins.each do |mod, fns|
28
32
  next if @disabledmodules.include? mod
29
33
  builtins.merge(fns)