rugments 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +52 -0
  3. data/README.md +195 -0
  4. data/bin/rugmentize +6 -0
  5. data/lib/rugments/cli.rb +357 -0
  6. data/lib/rugments/formatter.rb +29 -0
  7. data/lib/rugments/formatters/html.rb +142 -0
  8. data/lib/rugments/formatters/null.rb +17 -0
  9. data/lib/rugments/formatters/terminal256.rb +174 -0
  10. data/lib/rugments/lexer.rb +431 -0
  11. data/lib/rugments/lexers/apache/keywords.yml +453 -0
  12. data/lib/rugments/lexers/apache.rb +67 -0
  13. data/lib/rugments/lexers/apple_script.rb +366 -0
  14. data/lib/rugments/lexers/c.rb +210 -0
  15. data/lib/rugments/lexers/clojure.rb +109 -0
  16. data/lib/rugments/lexers/coffeescript.rb +172 -0
  17. data/lib/rugments/lexers/common_lisp.rb +343 -0
  18. data/lib/rugments/lexers/conf.rb +22 -0
  19. data/lib/rugments/lexers/cpp.rb +63 -0
  20. data/lib/rugments/lexers/csharp.rb +85 -0
  21. data/lib/rugments/lexers/css.rb +269 -0
  22. data/lib/rugments/lexers/dart.rb +102 -0
  23. data/lib/rugments/lexers/diff.rb +39 -0
  24. data/lib/rugments/lexers/elixir.rb +105 -0
  25. data/lib/rugments/lexers/erb.rb +54 -0
  26. data/lib/rugments/lexers/erlang.rb +116 -0
  27. data/lib/rugments/lexers/factor.rb +300 -0
  28. data/lib/rugments/lexers/gherkin/keywords.rb +13 -0
  29. data/lib/rugments/lexers/gherkin.rb +135 -0
  30. data/lib/rugments/lexers/go.rb +176 -0
  31. data/lib/rugments/lexers/groovy.rb +102 -0
  32. data/lib/rugments/lexers/haml.rb +226 -0
  33. data/lib/rugments/lexers/handlebars.rb +77 -0
  34. data/lib/rugments/lexers/haskell.rb +181 -0
  35. data/lib/rugments/lexers/html.rb +92 -0
  36. data/lib/rugments/lexers/http.rb +78 -0
  37. data/lib/rugments/lexers/ini.rb +55 -0
  38. data/lib/rugments/lexers/io.rb +66 -0
  39. data/lib/rugments/lexers/java.rb +74 -0
  40. data/lib/rugments/lexers/javascript.rb +258 -0
  41. data/lib/rugments/lexers/literate_coffeescript.rb +31 -0
  42. data/lib/rugments/lexers/literate_haskell.rb +34 -0
  43. data/lib/rugments/lexers/llvm.rb +82 -0
  44. data/lib/rugments/lexers/lua/builtins.rb +21 -0
  45. data/lib/rugments/lexers/lua.rb +120 -0
  46. data/lib/rugments/lexers/make.rb +114 -0
  47. data/lib/rugments/lexers/markdown.rb +151 -0
  48. data/lib/rugments/lexers/matlab/builtins.rb +10 -0
  49. data/lib/rugments/lexers/matlab.rb +70 -0
  50. data/lib/rugments/lexers/moonscript.rb +108 -0
  51. data/lib/rugments/lexers/nginx.rb +69 -0
  52. data/lib/rugments/lexers/nim.rb +149 -0
  53. data/lib/rugments/lexers/objective_c.rb +188 -0
  54. data/lib/rugments/lexers/ocaml.rb +109 -0
  55. data/lib/rugments/lexers/perl.rb +195 -0
  56. data/lib/rugments/lexers/php/builtins.rb +192 -0
  57. data/lib/rugments/lexers/php.rb +162 -0
  58. data/lib/rugments/lexers/plain_text.rb +23 -0
  59. data/lib/rugments/lexers/prolog.rb +62 -0
  60. data/lib/rugments/lexers/properties.rb +53 -0
  61. data/lib/rugments/lexers/puppet.rb +126 -0
  62. data/lib/rugments/lexers/python.rb +225 -0
  63. data/lib/rugments/lexers/qml.rb +70 -0
  64. data/lib/rugments/lexers/r.rb +55 -0
  65. data/lib/rugments/lexers/racket.rb +540 -0
  66. data/lib/rugments/lexers/ruby.rb +413 -0
  67. data/lib/rugments/lexers/rust.rb +188 -0
  68. data/lib/rugments/lexers/sass/common.rb +172 -0
  69. data/lib/rugments/lexers/sass.rb +72 -0
  70. data/lib/rugments/lexers/scala.rb +140 -0
  71. data/lib/rugments/lexers/scheme.rb +109 -0
  72. data/lib/rugments/lexers/scss.rb +32 -0
  73. data/lib/rugments/lexers/sed.rb +167 -0
  74. data/lib/rugments/lexers/shell.rb +150 -0
  75. data/lib/rugments/lexers/slim.rb +222 -0
  76. data/lib/rugments/lexers/smalltalk.rb +114 -0
  77. data/lib/rugments/lexers/sml.rb +345 -0
  78. data/lib/rugments/lexers/sql.rb +138 -0
  79. data/lib/rugments/lexers/swift.rb +153 -0
  80. data/lib/rugments/lexers/tcl.rb +189 -0
  81. data/lib/rugments/lexers/tex.rb +70 -0
  82. data/lib/rugments/lexers/toml.rb +68 -0
  83. data/lib/rugments/lexers/vb.rb +162 -0
  84. data/lib/rugments/lexers/viml/keywords.rb +11 -0
  85. data/lib/rugments/lexers/viml.rb +99 -0
  86. data/lib/rugments/lexers/xml.rb +57 -0
  87. data/lib/rugments/lexers/yaml.rb +362 -0
  88. data/lib/rugments/plugins/redcarpet.rb +28 -0
  89. data/lib/rugments/regex_lexer.rb +432 -0
  90. data/lib/rugments/template_lexer.rb +23 -0
  91. data/lib/rugments/text_analyzer.rb +46 -0
  92. data/lib/rugments/theme.rb +202 -0
  93. data/lib/rugments/themes/base16.rb +128 -0
  94. data/lib/rugments/themes/colorful.rb +65 -0
  95. data/lib/rugments/themes/github.rb +69 -0
  96. data/lib/rugments/themes/monokai.rb +88 -0
  97. data/lib/rugments/themes/monokai_sublime.rb +89 -0
  98. data/lib/rugments/themes/thankful_eyes.rb +69 -0
  99. data/lib/rugments/token.rb +180 -0
  100. data/lib/rugments/util.rb +99 -0
  101. data/lib/rugments/version.rb +3 -0
  102. data/lib/rugments.rb +33 -0
  103. metadata +149 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 26f2cc3f22f83d8cf8402e83519c5387099c994c
4
+ data.tar.gz: 02981428ba1aea39859eb53ff59328d445a08eaf
5
+ SHA512:
6
+ metadata.gz: a141db121829a1bf723722cf20b2a1cfb2bb72615d4c06b999ade59a855d2b9f1ccedeb0327c3518137e8076713f9cd02261004321eb20b8fffbe80f185757d1
7
+ data.tar.gz: 8f776f6add6c85bad26d41b5218cea4bcdd0f03488f949185d4e31aac1dc70e74eab28a1a804c85309d2987420c6a878812a4db803174258c5c9dda708651bf6
data/LICENSE ADDED
@@ -0,0 +1,52 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2012-2014 Jeanine Adkisson
4
+ Copyright (c) 2014 Stefan Tatschner
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
23
+
24
+
25
+ Many of the lexers in this project are adaptations of those in Pygments
26
+ (pygments.org). The license for Pygments is as follows:
27
+
28
+ Copyright (c) 2006-2014 by the respective authors (see AUTHORS file).
29
+ All rights reserved.
30
+
31
+ Redistribution and use in source and binary forms, with or without
32
+ modification, are permitted provided that the following conditions are
33
+ met:
34
+
35
+ * Redistributions of source code must retain the above copyright
36
+ notice, this list of conditions and the following disclaimer.
37
+
38
+ * Redistributions in binary form must reproduce the above copyright
39
+ notice, this list of conditions and the following disclaimer in the
40
+ documentation and/or other materials provided with the distribution.
41
+
42
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
45
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
46
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,195 @@
1
+ # Rugments
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/rugments.svg)](http://badge.fury.io/rb/rugments)
4
+
5
+ Rouge is a pure-ruby syntax highlighter. It can highlight over 60 languages, and output HTML or ANSI 256-color text. Its HTML output is compatible with stylesheets designed for [pygments][].
6
+
7
+ If you'd like to help out with this project, assign yourself something from the [issues][] page, and send me a pull request (even if it's not done yet!). Bonus points for feature branches. In particular, I would appreciate help with the following lexers, from someone who has more experience with the language than I do:
8
+
9
+ * Delphi/Pascal
10
+
11
+ Also, if anyone with design skills feels like helping me make a website for rouge, I'd really appreciate the help. So far all I've got is the [demo page][pretty colors].
12
+
13
+ [issues]: https://github.com/jneen/rouge/issues "Help Out"
14
+ [pygments]: http://pygments.org/ "Pygments"
15
+
16
+ ## Usage
17
+
18
+ First, take a look at the [pretty colors][].
19
+
20
+ [pretty colors]: http://rouge.jayferd.us/demo
21
+
22
+ ``` ruby
23
+ # make some nice lexed html
24
+ source = File.read('/etc/bashrc')
25
+ formatter = Rouge::Formatters::HTML.new(css_class: 'highlight')
26
+ lexer = Rouge::Lexers::Shell.new
27
+ formatter.format(lexer.lex(source))
28
+
29
+ # Get some CSS
30
+ Rouge::Themes::Base16.mode(:light).render(scope: '.highlight')
31
+ # Or use Theme#find with string input
32
+ Rouge::Theme.find('base16.light').render(scope: '.highlight')
33
+ ```
34
+
35
+ ### Full options
36
+ #### Formatter options
37
+ ##### css_class: 'highlight'
38
+ Apply a class to the syntax-highlighted output. Set to false to not apply any css class.
39
+
40
+ ##### line_numbers: false
41
+ Generate line numbers.
42
+
43
+ ##### start_line: 1
44
+ Index to start line numbers.
45
+
46
+ ##### inline_theme: nil
47
+ A `Rouge::CSSTheme` used to highlight the output with inline styles instead of classes. Allows string inputs (separate mode with a dot):
48
+
49
+ ```
50
+ %w[colorful github monokai monokai.sublime thankful_eyes base16
51
+ base16.dark base16.light base16.solarized base16.monokai]
52
+ ```
53
+
54
+ ##### wrap: true
55
+ Wrap the highlighted content in a container. Defaults to `<pre><code>`, or `<div>` if line numbers are enabled.
56
+
57
+ #### Lexer options
58
+ ##### debug: false
59
+ Print a trace of the lex on stdout
60
+
61
+ ##### parent: ''
62
+ Allows you to specify which language the template is inside
63
+
64
+ #### CSS theme options
65
+ ##### scope: '.highlight'
66
+ CSS selector that styles are applied to, e.g. `Rouge::Themes::Monokai.mode(:sublime).render(scope: 'code')`
67
+
68
+ Rouge aims to be simple to extend, and to be a drop-in replacement for pygments, with the same quality of output. Also, Rouge ships with a `rougify` command which allows you to easily highlight files in your terminal:
69
+
70
+ ``` bash
71
+ $ rougify foo.rb
72
+ $ rougify style monokai.sublime > syntax.css
73
+ ```
74
+
75
+ ### Advantages to pygments.rb
76
+ * No need to [spawn Python processes](https://github.com/tmm1/pygments.rb).
77
+
78
+ ### Advantages to CodeRay
79
+ * The HTML output from Rouge is fully compatible with stylesheets designed for pygments.
80
+ * The lexers are implemented with a dedicated DSL, rather than being hand-coded.
81
+ * Rouge supports every language CodeRay does except for Pascal/Delphi (pull requests happily accepted!), and more.
82
+
83
+ ## You can even use it with Redcarpet
84
+
85
+ ``` ruby
86
+ require 'redcarpet'
87
+ require 'rouge'
88
+ require 'rouge/plugins/redcarpet'
89
+
90
+ class HTML < Redcarpet::Render::HTML
91
+ include Rouge::Plugins::Redcarpet # yep, that's it.
92
+ end
93
+ ```
94
+
95
+ If you have `:fenced_code_blocks` enabled, you can specify languages, and even options with CGI syntax, like `php?start_inline=1`, or `erb?parent=javascript`.
96
+
97
+ ## Encodings
98
+
99
+ Rouge is only for UTF-8 strings. If you'd like to highlight a string with a different encoding, please convert it to UTF-8 first.
100
+
101
+ ## Other integrations
102
+
103
+ * Middleman: [middleman-syntax](https://github.com/middleman/middleman-syntax) (@bhollis)
104
+ * Middleman: [middleman-rouge][] (@Linuus)
105
+ * RDoc: [rdoc-rouge][] (@zzak)
106
+
107
+ [middleman-rouge]: https://github.com/Linuus/middleman-rouge
108
+ [rdoc-rouge]: https://github.com/zzak/rdoc-rouge
109
+
110
+ ## Contributing
111
+
112
+ ### Installing Ruby
113
+
114
+ If you're here to implement a lexer for your awesome language, there's a good chance you don't already have a ruby development environment set up. Follow the [instructions on the wiki](https://github.com/jneen/rouge/wiki/Setting-up-Ruby) to get up and running. If you have trouble getting set up, let me know - I'm always happy to help.
115
+
116
+ ### Run the tests
117
+
118
+ You can test the core of Rouge simply by running `rake` (no `bundle exec` required). It's also set up with `guard`, if you like.
119
+
120
+ To test a lexer visually, run `rackup` from the root and go to `localhost:9292/#{some_lexer}` where `some_lexer` is the tag or an alias of a lexer you'd like to test. If you add `?debug=1`, helpful debugging info will be printed on stdout.
121
+
122
+ ### API Documentation
123
+
124
+ is at http://rubydoc.info/gems/rouge/frames.
125
+
126
+ ### Using the lexer DSL
127
+
128
+ You can probably learn a lot just by reading through the existing lexers. Basically, a lexer consists of a collection of states, each of which has several rules. A rule consists of a regular expression and an action, which yields tokens and manipulates the state stack. Each rule in the state on top of the stack is tried *in order* until a match is found, at which point the action is run, the match consumed from the stream, and the process repeated with the new lexer on the top of the stack. Each lexer has a special state called `:root`, and the initial state stack consists of just this state.
129
+
130
+ Here's how you might use it:
131
+
132
+ ``` ruby
133
+ class MyLexer < Rouge::RegexLexer
134
+ state :root do
135
+ # the "easy way"
136
+
137
+ # simple rules
138
+ rule /0x[0-9a-f]+/, Num::Hex
139
+
140
+ # simple state stack manipulation
141
+ rule /{-/, Comment, :next_state
142
+ rule /-}/, Comment, :pop!
143
+
144
+ # the "flexible way"
145
+ rule /abc/ do |m|
146
+ # m is the match, for accessing match groups manually
147
+
148
+ # you can do the following things:
149
+ pop!
150
+ push :another_state
151
+ push # assumed to be the current state
152
+ state? :some_state # check if the current state is :some_state
153
+ in_state? :some_state # check if :some_state is in the state stack
154
+
155
+ # yield a token. if no second argument is supplied, the value is
156
+ # taken to be the whole match.
157
+ # The sum of all the tokens yielded must be equivalent to the whole
158
+ # match - otherwise characters will go missing from the user's input.
159
+ token Generic::Output, m[0]
160
+
161
+ # calls SomeOtherLexer.lex(str) and yields its output. See the
162
+ # HTML lexer for a nice example of this.
163
+ # if no second argument is supplied, it is assumed to be the whole
164
+ # match string.
165
+ delegate SomeOtherLexer, str
166
+
167
+ # the context object is the lexer itself, so you can stash state here
168
+ @count ||= 0
169
+ @count += 1
170
+
171
+ # advanced: push a dynamically created anonymous state
172
+ push do
173
+ rule /.../, Generic::Output
174
+ end
175
+ end
176
+
177
+ rule /(\w+)(:)/
178
+ # "groups" yields the matched groups in order
179
+ groups Name::Label, Punctuation
180
+ end
181
+ end
182
+
183
+ start do
184
+ # this is run whenever a fresh lex is started
185
+ end
186
+ end
187
+ ```
188
+
189
+ ## Tips
190
+
191
+ I don't get paid to maintain rouge. If you've found this software useful, consider dropping a tip in the [bucket](http://www.gittip.com/jneen).
192
+
193
+ ## License
194
+
195
+ Rouge is released under the MIT license. Please see the `LICENSE` file for more information.
data/bin/rugmentize ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "thor"
4
+
5
+ class Cli < Thor
6
+ end
@@ -0,0 +1,357 @@
1
+ # not required by the main lib.
2
+ # to use this module, require 'rouge/cli'.
3
+
4
+ module Rugments
5
+ class FileReader
6
+ attr_reader :input
7
+ def initialize(input)
8
+ @input = input
9
+ end
10
+
11
+ def file
12
+ case input
13
+ when '-'
14
+ $stdin
15
+ when String
16
+ File.new(input)
17
+ when ->(i){ i.respond_to? :read }
18
+ input
19
+ end
20
+ end
21
+
22
+ def read
23
+ @read ||= begin
24
+ file.read
25
+ rescue => e
26
+ $stderr.puts "unable to open #{input}: #{e.message}"
27
+ exit 1
28
+ ensure
29
+ file.close
30
+ end
31
+ end
32
+ end
33
+
34
+ class CLI
35
+ def self.doc
36
+ return enum_for(:doc) unless block_given?
37
+
38
+ yield %|usage: rougify [command] [args...]|
39
+ yield %||
40
+ yield %|where <command> is one of:|
41
+ yield %| highlight #{Highlight.desc}|
42
+ yield %| help #{Help.desc}|
43
+ yield %| style #{Style.desc}|
44
+ yield %| list #{List.desc}|
45
+ yield %| version #{Version.desc}|
46
+ yield %||
47
+ yield %|See `rougify help <command>` for more info.|
48
+ end
49
+
50
+ class Error < StandardError
51
+ attr_reader :message, :status
52
+ def initialize(message, status=1)
53
+ @message = message
54
+ @status = status
55
+ end
56
+ end
57
+
58
+ def self.parse(argv=ARGV)
59
+ argv = normalize_syntax(argv)
60
+
61
+ mode = argv.shift
62
+
63
+ klass = class_from_arg(mode)
64
+ return klass.parse(argv) if klass
65
+
66
+ case mode
67
+ when '-h', '--help', 'help', '-help'
68
+ Help.parse(argv)
69
+ else
70
+ argv.unshift(mode) if mode
71
+ Highlight.parse(argv)
72
+ end
73
+ end
74
+
75
+ def initialize(options={})
76
+ end
77
+
78
+ def self.error!(msg, status=1)
79
+ raise Error.new(msg, status)
80
+ end
81
+
82
+ def error!(*a)
83
+ self.class.error!(*a)
84
+ end
85
+
86
+ def self.class_from_arg(arg)
87
+ case arg
88
+ when 'version', '--version'
89
+ Version
90
+ when 'help'
91
+ Help
92
+ when 'highlight', 'hi'
93
+ Highlight
94
+ when 'style'
95
+ Style
96
+ when 'list'
97
+ List
98
+ end
99
+ end
100
+
101
+ class Version < CLI
102
+ def self.desc
103
+ "print the rouge version number"
104
+ end
105
+
106
+ def self.parse(*); new; end
107
+
108
+ def run
109
+ puts Rouge.version
110
+ end
111
+ end
112
+
113
+ class Help < CLI
114
+ def self.desc
115
+ "print help info"
116
+ end
117
+
118
+ def self.doc
119
+ return enum_for(:doc) unless block_given?
120
+
121
+ yield %|usage: rougify help <command>|
122
+ yield %||
123
+ yield %|print help info for <command>.|
124
+ end
125
+
126
+ def self.parse(argv)
127
+ opts = { :mode => CLI }
128
+ until argv.empty?
129
+ arg = argv.shift
130
+ klass = class_from_arg(arg)
131
+ if klass
132
+ opts[:mode] = klass
133
+ next
134
+ end
135
+ end
136
+ new(opts)
137
+ end
138
+
139
+ def initialize(opts={})
140
+ @mode = opts[:mode]
141
+ end
142
+
143
+ def run
144
+ @mode.doc.each(&method(:puts))
145
+ end
146
+ end
147
+
148
+ class Highlight < CLI
149
+ def self.desc
150
+ "highlight code"
151
+ end
152
+
153
+ def self.doc
154
+ return enum_for(:doc) unless block_given?
155
+
156
+ yield %[usage: rougify highlight <filename> [options...]]
157
+ yield %[ rougify highlight [options...]]
158
+ yield %[]
159
+ yield %[--input-file|-i <filename> specify a file to read, or - to use stdin]
160
+ yield %[]
161
+ yield %[--lexer|-l <lexer> specify the lexer to use.]
162
+ yield %[ If not provided, rougify will try to guess]
163
+ yield %[ based on --mimetype, the filename, and the]
164
+ yield %[ file contents.]
165
+ yield %[]
166
+ yield %[--mimetype|-m <mimetype> specify a mimetype for lexer guessing]
167
+ yield %[]
168
+ yield %[--lexer-opts|-L <opts> specify lexer options in CGI format]
169
+ yield %[ (opt1=val1&opt2=val2)]
170
+ yield %[]
171
+ yield %[--formatter-opts|-F <opts> specify formatter options in CGI format]
172
+ yield %[ (opt1=val1&opt2=val2)]
173
+ end
174
+
175
+ def self.parse(argv)
176
+ opts = {
177
+ :formatter => 'terminal256',
178
+ :input_file => '-',
179
+ :lexer_opts => {},
180
+ :formatter_opts => {},
181
+ }
182
+
183
+ until argv.empty?
184
+ arg = argv.shift
185
+ case arg
186
+ when '--input-file', '-i'
187
+ opts[:input_file] = argv.shift
188
+ when '--mimetype', '-m'
189
+ opts[:mimetype] = argv.shift
190
+ when '--lexer', '-l'
191
+ opts[:lexer] = argv.shift
192
+ when '--formatter', '-f'
193
+ opts[:formatter] = argv.shift
194
+ when '--lexer-opts', '-L'
195
+ opts[:lexer_opts] = parse_cgi(argv.shift)
196
+ when '--formatter-opts', '-F'
197
+ opts[:formatter_opts] = parse_cgi(argv.shift)
198
+ when /^--/
199
+ error! "unknown option #{arg.inspect}"
200
+ else
201
+ opts[:input_file] = arg
202
+ end
203
+ end
204
+
205
+ new(opts)
206
+ end
207
+
208
+ def input_stream
209
+ @input_stream ||= FileReader.new(@input_file)
210
+ end
211
+
212
+ def input
213
+ @input ||= input_stream.read
214
+ end
215
+
216
+ def lexer_class
217
+ @lexer_class ||= Lexer.guess(
218
+ :filename => @input_file,
219
+ :mimetype => @mimetype,
220
+ :source => input_stream,
221
+ )
222
+ end
223
+
224
+ def lexer
225
+ @lexer ||= lexer_class.new(@lexer_opts)
226
+ end
227
+
228
+ attr_reader :input_file, :lexer_name, :mimetype, :formatter
229
+
230
+ def initialize(opts={})
231
+ @input_file = opts[:input_file]
232
+
233
+ if opts[:lexer]
234
+ @lexer_class = Lexer.find(opts[:lexer]) \
235
+ or error! "unkown lexer #{opts[:lexer].inspect}"
236
+ else
237
+ @lexer_name = opts[:lexer]
238
+ @mimetype = opts[:mimetype]
239
+ end
240
+
241
+ @lexer_opts = opts[:lexer_opts]
242
+
243
+ formatter_class = Formatter.find(opts[:formatter]) \
244
+ or error! "unknown formatter #{opts[:formatter]}"
245
+
246
+ @formatter = formatter_class.new(opts[:formatter_opts])
247
+ end
248
+
249
+ def run
250
+ formatter.format(lexer.lex(input), &method(:print))
251
+ end
252
+
253
+ private
254
+ def self.parse_cgi(str)
255
+ pairs = CGI.parse(str).map { |k, v| [k.to_sym, v.first] }
256
+ Hash[pairs]
257
+ end
258
+ end
259
+
260
+ class Style < CLI
261
+ def self.desc
262
+ "print CSS styles"
263
+ end
264
+
265
+ def self.doc
266
+ return enum_for(:doc) unless block_given?
267
+
268
+ yield %|usage: rougify style [<theme-name>] [<options>]|
269
+ yield %||
270
+ yield %|Print CSS styles for the given theme. Extra options are|
271
+ yield %|passed to the theme. Theme defaults to thankful_eyes.|
272
+ yield %||
273
+ yield %|options:|
274
+ yield %| --scope (default: .highlight) a css selector to scope by|
275
+ yield %||
276
+ yield %|available themes:|
277
+ yield %| #{Theme.registry.keys.sort.join(', ')}|
278
+ end
279
+
280
+ def self.parse(argv)
281
+ opts = { :theme_name => 'thankful_eyes' }
282
+
283
+ until argv.empty?
284
+ arg = argv.shift
285
+ case arg
286
+ when /--(\w+)/
287
+ opts[$1.tr('-', '_').to_sym] = argv.shift
288
+ else
289
+ opts[:theme_name] = arg
290
+ end
291
+ end
292
+
293
+ new(opts)
294
+ end
295
+
296
+ def initialize(opts)
297
+ theme_name = opts.delete(:theme_name)
298
+ theme_class = Theme.find(theme_name) \
299
+ or error! "unknown theme: #{theme_name}"
300
+
301
+ @theme = theme_class.new(opts)
302
+ end
303
+
304
+ def run
305
+ @theme.render(&method(:puts))
306
+ end
307
+ end
308
+
309
+ class List < CLI
310
+ def self.desc
311
+ "list available lexers"
312
+ end
313
+
314
+ def self.doc
315
+ return enum_for(:doc) unless block_given?
316
+
317
+ yield %|usage: rouge list|
318
+ yield %||
319
+ yield %|print a list of all available lexers with their descriptions.|
320
+ end
321
+
322
+ def self.parse(argv)
323
+ new
324
+ end
325
+
326
+ def run
327
+ puts "== Available Lexers =="
328
+
329
+ Lexer.all.sort_by(&:tag).each do |lexer|
330
+ desc = "#{lexer.desc}"
331
+ if lexer.aliases.any?
332
+ desc << " [aliases: #{lexer.aliases.join(',')}]"
333
+ end
334
+ puts "%s: %s" % [lexer.tag, desc]
335
+ puts
336
+ end
337
+ end
338
+ end
339
+
340
+ private
341
+ def self.normalize_syntax(argv)
342
+ out = []
343
+ argv.each do |arg|
344
+ case arg
345
+ when /^(--\w+)=(.*)$/
346
+ out << $1 << $2
347
+ when /^(-\w)(.+)$/
348
+ out << $1 << $2
349
+ else
350
+ out << arg
351
+ end
352
+ end
353
+
354
+ out
355
+ end
356
+ end
357
+ end
@@ -0,0 +1,29 @@
1
+ module Rugments
2
+ # A Formatter takes a token stream and formats it for human viewing.
3
+ class Formatter
4
+ REGISTRY = {}
5
+
6
+ # Specify or get the unique tag for this formatter. This is used
7
+ # for specifying a formatter in `rougify`.
8
+ def self.tag(tag = nil)
9
+ return @tag unless tag
10
+ REGISTRY[tag] = self
11
+
12
+ @tag = tag
13
+ end
14
+
15
+ # Find a formatter class given a unique tag.
16
+ def self.find(tag)
17
+ REGISTRY[tag]
18
+ end
19
+
20
+ # Format a token stream. Delegates to {#format}.
21
+ def self.format(tokens, opts = {}, &b)
22
+ new(opts).format(tokens, &b)
23
+ end
24
+ end
25
+ end
26
+
27
+ require_relative 'formatters/html'
28
+ require_relative 'formatters/terminal256'
29
+ require_relative 'formatters/null'