rugments 1.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +52 -0
- data/README.md +195 -0
- data/bin/rugmentize +6 -0
- data/lib/rugments/cli.rb +357 -0
- data/lib/rugments/formatter.rb +29 -0
- data/lib/rugments/formatters/html.rb +142 -0
- data/lib/rugments/formatters/null.rb +17 -0
- data/lib/rugments/formatters/terminal256.rb +174 -0
- data/lib/rugments/lexer.rb +431 -0
- data/lib/rugments/lexers/apache/keywords.yml +453 -0
- data/lib/rugments/lexers/apache.rb +67 -0
- data/lib/rugments/lexers/apple_script.rb +366 -0
- data/lib/rugments/lexers/c.rb +210 -0
- data/lib/rugments/lexers/clojure.rb +109 -0
- data/lib/rugments/lexers/coffeescript.rb +172 -0
- data/lib/rugments/lexers/common_lisp.rb +343 -0
- data/lib/rugments/lexers/conf.rb +22 -0
- data/lib/rugments/lexers/cpp.rb +63 -0
- data/lib/rugments/lexers/csharp.rb +85 -0
- data/lib/rugments/lexers/css.rb +269 -0
- data/lib/rugments/lexers/dart.rb +102 -0
- data/lib/rugments/lexers/diff.rb +39 -0
- data/lib/rugments/lexers/elixir.rb +105 -0
- data/lib/rugments/lexers/erb.rb +54 -0
- data/lib/rugments/lexers/erlang.rb +116 -0
- data/lib/rugments/lexers/factor.rb +300 -0
- data/lib/rugments/lexers/gherkin/keywords.rb +13 -0
- data/lib/rugments/lexers/gherkin.rb +135 -0
- data/lib/rugments/lexers/go.rb +176 -0
- data/lib/rugments/lexers/groovy.rb +102 -0
- data/lib/rugments/lexers/haml.rb +226 -0
- data/lib/rugments/lexers/handlebars.rb +77 -0
- data/lib/rugments/lexers/haskell.rb +181 -0
- data/lib/rugments/lexers/html.rb +92 -0
- data/lib/rugments/lexers/http.rb +78 -0
- data/lib/rugments/lexers/ini.rb +55 -0
- data/lib/rugments/lexers/io.rb +66 -0
- data/lib/rugments/lexers/java.rb +74 -0
- data/lib/rugments/lexers/javascript.rb +258 -0
- data/lib/rugments/lexers/literate_coffeescript.rb +31 -0
- data/lib/rugments/lexers/literate_haskell.rb +34 -0
- data/lib/rugments/lexers/llvm.rb +82 -0
- data/lib/rugments/lexers/lua/builtins.rb +21 -0
- data/lib/rugments/lexers/lua.rb +120 -0
- data/lib/rugments/lexers/make.rb +114 -0
- data/lib/rugments/lexers/markdown.rb +151 -0
- data/lib/rugments/lexers/matlab/builtins.rb +10 -0
- data/lib/rugments/lexers/matlab.rb +70 -0
- data/lib/rugments/lexers/moonscript.rb +108 -0
- data/lib/rugments/lexers/nginx.rb +69 -0
- data/lib/rugments/lexers/nim.rb +149 -0
- data/lib/rugments/lexers/objective_c.rb +188 -0
- data/lib/rugments/lexers/ocaml.rb +109 -0
- data/lib/rugments/lexers/perl.rb +195 -0
- data/lib/rugments/lexers/php/builtins.rb +192 -0
- data/lib/rugments/lexers/php.rb +162 -0
- data/lib/rugments/lexers/plain_text.rb +23 -0
- data/lib/rugments/lexers/prolog.rb +62 -0
- data/lib/rugments/lexers/properties.rb +53 -0
- data/lib/rugments/lexers/puppet.rb +126 -0
- data/lib/rugments/lexers/python.rb +225 -0
- data/lib/rugments/lexers/qml.rb +70 -0
- data/lib/rugments/lexers/r.rb +55 -0
- data/lib/rugments/lexers/racket.rb +540 -0
- data/lib/rugments/lexers/ruby.rb +413 -0
- data/lib/rugments/lexers/rust.rb +188 -0
- data/lib/rugments/lexers/sass/common.rb +172 -0
- data/lib/rugments/lexers/sass.rb +72 -0
- data/lib/rugments/lexers/scala.rb +140 -0
- data/lib/rugments/lexers/scheme.rb +109 -0
- data/lib/rugments/lexers/scss.rb +32 -0
- data/lib/rugments/lexers/sed.rb +167 -0
- data/lib/rugments/lexers/shell.rb +150 -0
- data/lib/rugments/lexers/slim.rb +222 -0
- data/lib/rugments/lexers/smalltalk.rb +114 -0
- data/lib/rugments/lexers/sml.rb +345 -0
- data/lib/rugments/lexers/sql.rb +138 -0
- data/lib/rugments/lexers/swift.rb +153 -0
- data/lib/rugments/lexers/tcl.rb +189 -0
- data/lib/rugments/lexers/tex.rb +70 -0
- data/lib/rugments/lexers/toml.rb +68 -0
- data/lib/rugments/lexers/vb.rb +162 -0
- data/lib/rugments/lexers/viml/keywords.rb +11 -0
- data/lib/rugments/lexers/viml.rb +99 -0
- data/lib/rugments/lexers/xml.rb +57 -0
- data/lib/rugments/lexers/yaml.rb +362 -0
- data/lib/rugments/plugins/redcarpet.rb +28 -0
- data/lib/rugments/regex_lexer.rb +432 -0
- data/lib/rugments/template_lexer.rb +23 -0
- data/lib/rugments/text_analyzer.rb +46 -0
- data/lib/rugments/theme.rb +202 -0
- data/lib/rugments/themes/base16.rb +128 -0
- data/lib/rugments/themes/colorful.rb +65 -0
- data/lib/rugments/themes/github.rb +69 -0
- data/lib/rugments/themes/monokai.rb +88 -0
- data/lib/rugments/themes/monokai_sublime.rb +89 -0
- data/lib/rugments/themes/thankful_eyes.rb +69 -0
- data/lib/rugments/token.rb +180 -0
- data/lib/rugments/util.rb +99 -0
- data/lib/rugments/version.rb +3 -0
- data/lib/rugments.rb +33 -0
- 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
data/lib/rugments/cli.rb
ADDED
@@ -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'
|