hylite 1.0.0
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.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/Gemfile +2 -0
- data/Readme.md +71 -0
- data/bin/hilight_syntax +4 -0
- data/bin/hylite +12 -0
- data/bin/syntax_hilight +4 -0
- data/hylite.gemspec +23 -0
- data/lib/hylite.rb +34 -0
- data/lib/hylite/choose_hyliter.rb +36 -0
- data/lib/hylite/cli.rb +64 -0
- data/lib/hylite/hyliters.rb +56 -0
- data/lib/hylite/version.rb +3 -0
- data/notes +121 -0
- data/spec/binary_spec.rb +108 -0
- data/spec/choose_hyliter.rb +48 -0
- data/spec/hylite_spec.rb +40 -0
- data/spec/spec_helpers.rb +13 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: '029f1390d68bcdad670b11ba3c3bd1c7688745dd'
|
4
|
+
data.tar.gz: 5e1a2079b48cc1fbe2b501c36f155611647402a1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 525bf92d906fc94f8eb4891162c1cf7d21aaea4d75b9ec8b04e73309674131d43d98c1f1382c505579e7fd8aa42acdb4f1b4d99d18b48955311e96172a6159c0
|
7
|
+
data.tar.gz: 21175e7b41dff749412da917726f9045a3651a308188b2f3cfe44a82e4197bd4811ad8d439f21a5bf689d406a407f5f0e2fb8cf6b62bf7c1861f4d9f524b38a6
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Readme.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
Hylite
|
2
|
+
======
|
3
|
+
|
4
|
+
Syntax Highlighting for scripters.
|
5
|
+
|
6
|
+
It has a simple binary-interface and Ruby interface that tries to find a
|
7
|
+
syntax highlighting tool on your machine and then highlight your code using that tool.
|
8
|
+
|
9
|
+
The intent:
|
10
|
+
|
11
|
+
1. Allow a script to find and use an existing syntax highlighter without needing
|
12
|
+
to add one as a dependency.
|
13
|
+
2. All syntax highlighting that I've seen have stupidly difficult interfaces
|
14
|
+
(often buggy, difficult to discover, the obvious use case requires non-obvious
|
15
|
+
configuration which is difficult to discover and has mediocre defaults),
|
16
|
+
the intent here is to improve discoverability, have it do the obvious thing
|
17
|
+
by default, and choose reasonable defaults so that you rarely have to configure it.
|
18
|
+
3. If you find ways that it doesn't do this, let me know. Eg I didn't test the
|
19
|
+
themes on a light background to make sure they look good there. That might make
|
20
|
+
the defaults only work well on dark backgrounds.
|
21
|
+
|
22
|
+
If you're not scripting, you'll want to use one of the libraries this tool wraps:
|
23
|
+
|
24
|
+
* [Rouge](http://rouge.jneen.net)
|
25
|
+
* [Coderay](http://coderay.rubychan.de)
|
26
|
+
* [Pygments](http://pygments.org)
|
27
|
+
|
28
|
+
|
29
|
+
Todo
|
30
|
+
----
|
31
|
+
|
32
|
+
* Allow user to pass a filename as that's a pretty obvious way to use it,
|
33
|
+
and that's probably a nicer interface for non-Ruby projects.
|
34
|
+
* Possibly allow it to guess the default (eg Rouge will do this)
|
35
|
+
|
36
|
+
|
37
|
+
Interface
|
38
|
+
---------
|
39
|
+
|
40
|
+
```sh
|
41
|
+
# Simplest interface
|
42
|
+
$ cat my_code.rb | hylite
|
43
|
+
|
44
|
+
# Highlight other languages
|
45
|
+
$ cat my_code.c | hylite --lang c
|
46
|
+
```
|
47
|
+
|
48
|
+
|
49
|
+
Development
|
50
|
+
-----------
|
51
|
+
|
52
|
+
Assuming a working Ruby development environment (try [chruby](https://github.com/postmodern/chruby) if you don't have one).
|
53
|
+
|
54
|
+
```sh
|
55
|
+
# Install Bundler for dependency management, if you don't already have it
|
56
|
+
$ gem install bundler
|
57
|
+
|
58
|
+
# Tell bundler to install the dev dependencies
|
59
|
+
$ bundle install
|
60
|
+
|
61
|
+
# Run the tests
|
62
|
+
$ mrspec
|
63
|
+
```
|
64
|
+
|
65
|
+
|
66
|
+
License
|
67
|
+
-------
|
68
|
+
|
69
|
+
[WTFPL](http://www.wtfpl.net/about/), Just do what the fuck you want to.
|
70
|
+
|
71
|
+
NO WARRANTY.
|
data/bin/hilight_syntax
ADDED
data/bin/hylite
ADDED
data/bin/syntax_hilight
ADDED
data/hylite.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
$:.push File.expand_path("lib", __dir__)
|
2
|
+
require "hylite/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "hylite"
|
6
|
+
s.version = Hylite::VERSION
|
7
|
+
s.authors = ["Josh Cheek"]
|
8
|
+
s.email = ["josh.cheek@gmail.com"]
|
9
|
+
s.homepage = "https://github.com/JoshCheek/hylite"
|
10
|
+
s.summary = %q{Syntax Highlighting for scripters}
|
11
|
+
s.description = %q{Provides a simple binary interface and Ruby interface to highlight your code using whatever tools you already have on your machine.}
|
12
|
+
s.license = "WTFPL"
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n") - Dir['mascots/*']
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.executables = ['hylite', 'syntax_hilight', 'hilight_syntax']
|
17
|
+
s.require_paths = ['lib']
|
18
|
+
|
19
|
+
s.add_development_dependency "rspec", "~> 3.0"
|
20
|
+
s.add_development_dependency "rouge", "~> 2.0"
|
21
|
+
s.add_development_dependency "coderay", "~> 1.0"
|
22
|
+
s.add_development_dependency "ultraviolet", "~> 1.0"
|
23
|
+
end
|
data/lib/hylite.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'hylite/choose_hyliter'
|
2
|
+
|
3
|
+
class Hylite
|
4
|
+
def self.call(*args)
|
5
|
+
new(*args).call
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :lang
|
9
|
+
|
10
|
+
def initialize(to_highlight, options={})
|
11
|
+
self.to_highlight = to_highlight
|
12
|
+
options.each do |key, value|
|
13
|
+
if key =~ /^l/
|
14
|
+
self.lang = value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
self.lang ||= 'ruby'
|
18
|
+
end
|
19
|
+
|
20
|
+
def call
|
21
|
+
code = to_highlight
|
22
|
+
code = code.read if code.respond_to? :read
|
23
|
+
hyliter(code, lang).call
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_accessor :to_highlight
|
29
|
+
attr_writer :lang
|
30
|
+
|
31
|
+
def hyliter(code, lang)
|
32
|
+
ChooseHyliter.call(code, lang)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'hylite/hyliters'
|
3
|
+
|
4
|
+
class Hylite
|
5
|
+
module ChooseHyliter
|
6
|
+
extend self
|
7
|
+
|
8
|
+
def call(code, lang)
|
9
|
+
case
|
10
|
+
when rouge_available? then Rouge.new(code, lang)
|
11
|
+
when pygments_available? then Pygments.new(code, lang)
|
12
|
+
when coderay_available? then CodeRay.new(code, lang)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def rouge_available?
|
17
|
+
require 'rouge'
|
18
|
+
true
|
19
|
+
rescue LoadError
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
def pygments_available?
|
24
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).any? do |dir|
|
25
|
+
File.exist? File.join(dir, 'pygmentize')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def coderay_available?
|
30
|
+
require 'rouge'
|
31
|
+
true
|
32
|
+
rescue LoadError
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/hylite/cli.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'hylite'
|
2
|
+
|
3
|
+
class Hylite
|
4
|
+
class CLI
|
5
|
+
def initialize(stdin, argv)
|
6
|
+
self.stdin = stdin
|
7
|
+
self.argv = argv
|
8
|
+
end
|
9
|
+
|
10
|
+
def errors
|
11
|
+
config.errors
|
12
|
+
end
|
13
|
+
|
14
|
+
def result
|
15
|
+
ensure_evaluated
|
16
|
+
@result
|
17
|
+
end
|
18
|
+
|
19
|
+
def success?
|
20
|
+
ensure_evaluated
|
21
|
+
errors.none?
|
22
|
+
end
|
23
|
+
|
24
|
+
def errors
|
25
|
+
config.fetch :errors
|
26
|
+
end
|
27
|
+
|
28
|
+
def config
|
29
|
+
@config ||= parse(argv)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_accessor :stdin, :argv
|
35
|
+
|
36
|
+
def ensure_evaluated
|
37
|
+
return if @evaluated
|
38
|
+
@evaluated = true
|
39
|
+
@success = true
|
40
|
+
@result = Hylite.call(stdin, config)
|
41
|
+
end
|
42
|
+
|
43
|
+
def parse(args)
|
44
|
+
config = {errors: [], help: false, lang: nil}
|
45
|
+
args = args.dup
|
46
|
+
while args.any?
|
47
|
+
arg = args.shift
|
48
|
+
case arg
|
49
|
+
when '-h', '--help'
|
50
|
+
config[:help] = true
|
51
|
+
when '-l', /^--l.*/
|
52
|
+
if lang = args.shift
|
53
|
+
config[:lang] = lang
|
54
|
+
else
|
55
|
+
config[:errors] << "Expected a language after #{arg.inspect}"
|
56
|
+
end
|
57
|
+
else
|
58
|
+
config[:errors] << "Unknown argument #{arg.inspect}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
config
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
class Hylite
|
4
|
+
class Hyliter
|
5
|
+
attr_reader :code, :lang
|
6
|
+
def initialize(code, lang)
|
7
|
+
@code, @lang = code, lang
|
8
|
+
end
|
9
|
+
def type
|
10
|
+
raise NotImplementedError, 'Subclass should define'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Rouge < Hyliter
|
15
|
+
def type
|
16
|
+
:rouge
|
17
|
+
end
|
18
|
+
def call
|
19
|
+
# From Fish, you can see all styles with:
|
20
|
+
# for style in (rougify help style | tail -1 | tr -d ' ' | tr , \n); echo \n===== $style =====; rougify highlight -t $style -l ruby bin/hylite ; end
|
21
|
+
theme = ::Rouge::Theme.find 'monokai'
|
22
|
+
formatter = ::Rouge::Formatters::Terminal256.new theme
|
23
|
+
lexer = ::Rouge::Lexer.find @lang
|
24
|
+
tokens = lexer.lex @code
|
25
|
+
formatter.format(tokens)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Pygments < Hyliter
|
30
|
+
def type
|
31
|
+
:pygments
|
32
|
+
end
|
33
|
+
def call
|
34
|
+
# From Fish, you can see all styles with:
|
35
|
+
# for style in (pygmentize -L styles | sed -n '/\*/s/[*: ]//gp'); echo \n===== $style =====; pygmentize -f terminal256 -O style=$style -l ruby < lib/hylite.rb ; end
|
36
|
+
out, err, status = Open3.capture3(
|
37
|
+
'pygmentize',
|
38
|
+
'-f', 'terminal256',
|
39
|
+
'-O', 'style=monokai',
|
40
|
+
'-l', lang,
|
41
|
+
stdin_data: code
|
42
|
+
)
|
43
|
+
return out if status.success? && err.empty?
|
44
|
+
raise "Uhhh, what led to this, I want to test it but don't know what can cause it / how to mimic it (and therefore what it should do)"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class CodeRay < Hyliter
|
49
|
+
def type
|
50
|
+
:coderay
|
51
|
+
end
|
52
|
+
def call
|
53
|
+
::CodeRay.encode(code, lang, :terminal)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/notes
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Rouge
|
4
|
+
# * cat lib/hylite.rb | time rougify highlight -l ruby
|
5
|
+
# * slower (0.24s, sometimes 2x that)
|
6
|
+
# * 121 languages (coderay has 31, rouge 121)
|
7
|
+
# * Has 15 themes
|
8
|
+
|
9
|
+
# require 'rouge'
|
10
|
+
#
|
11
|
+
# # See all styles (from fish)
|
12
|
+
# # for style in (rougify help style | tail -1 | tr -d ' ' | tr , \n); echo \n===== $style =====; rougify highlight -t $style -l ruby bin/rougify ; end
|
13
|
+
# Rouge::Theme.registry.keys
|
14
|
+
#
|
15
|
+
# # Using the lib
|
16
|
+
# formatter = Rouge::Formatters::Terminal256.new theme: 'colorful'
|
17
|
+
# lexer = Rouge::Lexers::Ruby.new
|
18
|
+
# tokens = lexer.lex raw_code
|
19
|
+
# formatter.format(tokens)
|
20
|
+
#
|
21
|
+
# # Number of languages
|
22
|
+
# Rouge::Lexer.all.length # => 113
|
23
|
+
#
|
24
|
+
# # Inferring the language (supports a mimetype, too, but not useful for this)
|
25
|
+
# Rouge::Lexer.guesses(filename: 'file.rb') # => [Rouge::Lexers::Ruby]
|
26
|
+
# Rouge::Lexer.guesses(filename: 'file.py') # => [Rouge::Lexers::Python]
|
27
|
+
# Rouge::Lexer.guesses(source: "#!/usr/bin/env ruby\n1+1") # => [Rouge::Lexers::Ruby]
|
28
|
+
# Rouge::Lexer.guesses(source: "#!/usr/bin/env python\n1+1") # => [Rouge::Lexers::Python]
|
29
|
+
# Rouge::Lexer.guesses(source: "1+1") # => []
|
30
|
+
#
|
31
|
+
# Rouge.constants
|
32
|
+
|
33
|
+
# CodeRay
|
34
|
+
# * cat lib/hylite.rb | time coderay -ruby
|
35
|
+
# * 3-4x faster (0.07s)
|
36
|
+
# * 31 languages
|
37
|
+
# * Has the nicest default theme
|
38
|
+
# * Has only theme
|
39
|
+
|
40
|
+
# require 'coderay'
|
41
|
+
#
|
42
|
+
# # Using the lib
|
43
|
+
# CodeRay.encode '1+1', :ruby, :terminal # => "\e[1;34m1\e[0m+\e[1;34m1\e[0m"
|
44
|
+
#
|
45
|
+
# # Number of languages
|
46
|
+
# CodeRay::Scanners.list.length # => 27
|
47
|
+
#
|
48
|
+
# # Inferring language from filename (true means it should try checking the shebang)
|
49
|
+
# CodeRay::FileType.fetch 'somefile.zomg', :default_type, true # => :default_type
|
50
|
+
# CodeRay::FileType.fetch 'somefile.rb', :default_type, true # => :ruby
|
51
|
+
|
52
|
+
# Pygmentize
|
53
|
+
# * $ cat lib/hylite.rb | time pygmentize -l ruby
|
54
|
+
# * $ cat lib/hylite.rb | time ruby -e 'system "pygmentize -l ruby"'
|
55
|
+
# * slow (0.18s, occasionallly 0.30s, but 0.24 when shelling out from Ruby)
|
56
|
+
# * 402 languages (pygmentize -L lexers | ag '^\*' | wc -l)
|
57
|
+
# * 26 themes (pygmentize -L styles | ag '^\*' | wc -l)
|
58
|
+
# $ pygmentize -L styles
|
59
|
+
# $ pygmentize -L formatters
|
60
|
+
|
61
|
+
# Vim
|
62
|
+
# * http://superuser.com/questions/554047/export-vim-syntax-highlighting-to-output-to-shell
|
63
|
+
# * http://www.vim.org/scripts/script.php?script_id=4325
|
64
|
+
# * http://unix.stackexchange.com/questions/90990/less-command-and-syntax-highlighting
|
65
|
+
|
66
|
+
|
67
|
+
# ---------------------------------------------------------
|
68
|
+
# How to control which libraries it can see:
|
69
|
+
|
70
|
+
require 'rubygems'
|
71
|
+
require 'open3'
|
72
|
+
|
73
|
+
coderay = Gem::Specification.find_by_name('coderay')
|
74
|
+
coderay_paths = coderay.full_require_paths.join(":")
|
75
|
+
|
76
|
+
rouge = Gem::Specification.find_by_name('rouge')
|
77
|
+
rouge_paths = rouge.full_require_paths.join(":")
|
78
|
+
|
79
|
+
[ ['CodeRay', ['-I', coderay_paths]],
|
80
|
+
['Rouge', ['-I', rouge_paths]],
|
81
|
+
['Pygments', []],
|
82
|
+
].each do |name, args|
|
83
|
+
puts "==== #{name} ====="
|
84
|
+
system 'ruby', '--disable-gem', *args, '-e', <<-'RUBY'
|
85
|
+
which = 'pygments'
|
86
|
+
|
87
|
+
begin
|
88
|
+
require 'rouge'
|
89
|
+
which = 'rouge'
|
90
|
+
rescue LoadError
|
91
|
+
puts "\e[31mCould not load rouge\e[0m"
|
92
|
+
end
|
93
|
+
|
94
|
+
begin
|
95
|
+
require 'coderay'
|
96
|
+
which = 'coderay'
|
97
|
+
rescue LoadError
|
98
|
+
puts "\e[31mCould not load coderay\e[0m"
|
99
|
+
end
|
100
|
+
|
101
|
+
case which
|
102
|
+
when 'coderay'
|
103
|
+
puts "\e[32mUsing CodeRay\e[0m", CodeRay.encode("1+1", :ruby, :terminal)
|
104
|
+
when 'rouge'
|
105
|
+
theme = Rouge::Theme.find 'tulip'
|
106
|
+
formatter = Rouge::Formatters::Terminal256.new theme
|
107
|
+
lexer = Rouge::Lexers::Ruby.new
|
108
|
+
tokens = lexer.lex "1+1"
|
109
|
+
puts "\e[32mUsing Rouge\e[0m", formatter.format(tokens)
|
110
|
+
when 'pygments'
|
111
|
+
require 'open3'
|
112
|
+
out, err, status = Open3.capture3 'pygmentize', '-f', 'terminal256', '-O', 'style=fruity', '-l', 'ruby', stdin_data: '1+1'
|
113
|
+
raise [status, err.inspect] unless status.success?
|
114
|
+
raise err unless err.empty?
|
115
|
+
puts "\e[32mUsing pygments\e[0m", out
|
116
|
+
else
|
117
|
+
raise "What!? #{which.inspect}"
|
118
|
+
end
|
119
|
+
RUBY
|
120
|
+
end
|
121
|
+
|
data/spec/binary_spec.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'hylite/cli'
|
3
|
+
require 'spec_helpers'
|
4
|
+
|
5
|
+
bin_dir = File.expand_path '../bin', __dir__
|
6
|
+
ENV["PATH"] = bin_dir + ":" + ENV["PATH"]
|
7
|
+
|
8
|
+
RSpec.describe 'binaries' do
|
9
|
+
describe 'hylite' do
|
10
|
+
it 'reads code from stdin, highlights it, prints it to stdout' do
|
11
|
+
stdout, stderr, status = Open3.capture3 'hylite', stdin_data: '1+1'
|
12
|
+
expect(stderr).to be_empty
|
13
|
+
expect(status).to be_success
|
14
|
+
tokens = highlighted_tokens(stdout)
|
15
|
+
expect(tokens).to include :color
|
16
|
+
expect(tokens.select { |t| t.kind_of? String }).to eq %W[1 + 1 \n]
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when it has an error' do
|
20
|
+
it 'prints the error to stderr and exits with a failure code' do
|
21
|
+
stdout, stderr, status = Open3.capture3 'hylite -notanarg', stdin_data: '1+1'
|
22
|
+
expect(stderr).to include "notanarg"
|
23
|
+
expect(status).to_not be_success
|
24
|
+
expect(stdout).to be_empty
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'arguments' do
|
29
|
+
def unset
|
30
|
+
@unset ||= Object.new
|
31
|
+
end
|
32
|
+
|
33
|
+
def assert_parses(argv, key, value=unset)
|
34
|
+
cli = Hylite::CLI.new("", argv)
|
35
|
+
expect(cli.config[key]).to eq value unless value == unset
|
36
|
+
cli.config[key]
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'prints a help screen for -h / --help and exits successfully' do
|
40
|
+
assert_parses [], :help, false
|
41
|
+
assert_parses [], :errors, []
|
42
|
+
|
43
|
+
assert_parses ['-h'], :help, true
|
44
|
+
assert_parses ['-h'], :errors, []
|
45
|
+
|
46
|
+
assert_parses ['--help'], :help, true
|
47
|
+
assert_parses ['--help'], :errors, []
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'language' do
|
51
|
+
it 'is not set by default (uses the lib\'s default of Ruby)' do
|
52
|
+
assert_parses [], :lang, nil
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'can be specified with -l, --language, or --lmisspelled' do
|
56
|
+
assert_parses ['-l', 'java'], :lang, 'java'
|
57
|
+
assert_parses ['-l', 'cpp'], :lang, 'cpp'
|
58
|
+
assert_parses ['--lang', 'cpp'], :lang, 'cpp'
|
59
|
+
assert_parses ['--lmisspelled', 'cpp'], :lang, 'cpp'
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'sets an error if it sees a language arg without a language' do
|
63
|
+
assert_parses ["-l", "cpp"], :errors, []
|
64
|
+
errors = assert_parses ["-l"], :errors
|
65
|
+
expect(errors.length).to eq 1
|
66
|
+
expect(errors[0]).to match /language/
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'highlights according to the provided language' do
|
70
|
+
ruby = Hylite.call '1', lang: 'ruby'
|
71
|
+
css = Hylite.call '1', lang: 'css'
|
72
|
+
expect(ruby).to_not eq css
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'sets an error if it sees an arg it doesn\'t understand' do
|
77
|
+
errors = assert_parses ["asdf"], :errors
|
78
|
+
expect(errors.length).to eq 1
|
79
|
+
expect(errors[0]).to match /asdf/
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'passes the config, parsed from the arguments, down to the lib' do
|
83
|
+
ruby_stdout, ruby_stderr, ruby_status = Open3.capture3 'hylite -l ruby', stdin_data: '1+1'
|
84
|
+
css_stdout, css_stderr, css_status = Open3.capture3 'hylite -l css', stdin_data: '1+1'
|
85
|
+
|
86
|
+
expect(ruby_stderr).to eq css_stderr
|
87
|
+
expect(ruby_status).to eq css_status
|
88
|
+
expect(ruby_stdout).to_not eq css_stdout
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe 'binaries that exist for discoverability' do
|
94
|
+
specify 'syntax_hilight: warns you to use hylite, but still works' do
|
95
|
+
stdout, stderr, status = Open3.capture3 'syntax_hilight', stdin_data: '1+1'
|
96
|
+
expect(stderr).to match /hylite/
|
97
|
+
expect(status).to be_success
|
98
|
+
expect(stdout).to_not be_empty
|
99
|
+
end
|
100
|
+
|
101
|
+
specify 'highlight_syntax: warns you to use hylite, but still works' do
|
102
|
+
stdout, stderr, status = Open3.capture3 'highlight_syntax', stdin_data: '1+1'
|
103
|
+
expect(stderr).to match /hylite/
|
104
|
+
expect(status).to be_success
|
105
|
+
expect(stdout).to_not be_empty
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'hylite/choose_hyliter'
|
2
|
+
require 'rouge'
|
3
|
+
|
4
|
+
RSpec.describe 'ChooseHyliter' do
|
5
|
+
# ugh, might be better to inject require than this nonsense >.<
|
6
|
+
|
7
|
+
it 'uses rouge if available' do
|
8
|
+
hyliter = Hylite::ChooseHyliter.call("#a { color: #FFF; }" , "css")
|
9
|
+
expect(hyliter.type).to eq :rouge
|
10
|
+
|
11
|
+
hylited = hyliter.call
|
12
|
+
expect(hyliter.call).to include 'FFF'
|
13
|
+
expect(hyliter.call).to include "\e[" # an escape sequence in there somewhere
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
it 'does not use rouge if it does not support the requested language'
|
18
|
+
|
19
|
+
|
20
|
+
it 'uses pygments if rouge, isn\'t available' do
|
21
|
+
allow(Hylite::ChooseHyliter).to receive(:require).with('rouge').and_raise(LoadError)
|
22
|
+
|
23
|
+
hyliter = Hylite::ChooseHyliter.call("#a { color: #FFF; }" , "css")
|
24
|
+
expect(hyliter.type).to eq :pygments
|
25
|
+
|
26
|
+
hylited = hyliter.call
|
27
|
+
expect(hyliter.call).to include 'FFF'
|
28
|
+
expect(hyliter.call).to include "\e[" # an escape sequence in there somewhere
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
it 'uses coderay if rouge and pygmentize aren\'t available' do
|
33
|
+
require 'coderay'
|
34
|
+
allow(File).to receive(:exist?).and_return(false)
|
35
|
+
allow(Hylite::ChooseHyliter).to receive(:require).with('rouge').and_raise(LoadError)
|
36
|
+
allow(Hylite::ChooseHyliter).to receive(:require).with('coderay').and_return(true)
|
37
|
+
|
38
|
+
hyliter = Hylite::ChooseHyliter.call("#a { color: #FFF; }" , "css")
|
39
|
+
expect(hyliter.type).to eq :coderay
|
40
|
+
|
41
|
+
hylited = hyliter.call
|
42
|
+
expect(hyliter.call).to include 'FFF'
|
43
|
+
expect(hyliter.call).to include "\e[" # an escape sequence in there somewhere
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
it 'tells you how to install these other libs if none of them are available'
|
48
|
+
end
|
data/spec/hylite_spec.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'spec_helpers'
|
3
|
+
require 'hylite'
|
4
|
+
|
5
|
+
RSpec.describe 'hylite' do
|
6
|
+
it 'invokes whichever hyliter "ChooseHyliter" returns', t:true do
|
7
|
+
expect(Hylite::ChooseHyliter).to receive(:call).with("to hylite", 'some lang').and_return(-> { "hylited" })
|
8
|
+
hylited = Hylite.new("to hylite", l: "some lang").call
|
9
|
+
expect(hylited).to eq "hylited"
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'defaults the language to Ruby' do
|
13
|
+
expect(Hylite.new('' ).lang).to eq 'ruby'
|
14
|
+
expect(Hylite.new('', l: nil).lang).to eq 'ruby'
|
15
|
+
expect(Hylite.new('', l: 'css').lang).to_not eq 'ruby'
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
it 'can be overridden with the :l, :language, or :lmisspelled keywords' do
|
20
|
+
h = Hylite.new '', l: 'forth'
|
21
|
+
expect(h.lang).to eq 'forth'
|
22
|
+
|
23
|
+
h = Hylite.new '', lang: 'forth'
|
24
|
+
expect(h.lang).to eq 'forth'
|
25
|
+
|
26
|
+
h = Hylite.new '', lmisspelled: 'forth'
|
27
|
+
expect(h.lang).to eq 'forth'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'accepts strings or streams to highlight' do
|
31
|
+
# Based on CodeRay's formatting of "1":
|
32
|
+
# ["\e[1;34m", "1", "\e[0m"]
|
33
|
+
expected_tokens = [:color, "1", :color]
|
34
|
+
string = '1'.freeze
|
35
|
+
stream = StringIO.new string
|
36
|
+
|
37
|
+
expect(highlighted_tokens Hylite.call string).to eq expected_tokens
|
38
|
+
expect(highlighted_tokens Hylite.call stream).to eq expected_tokens
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module SpecHelpers
|
2
|
+
def highlighted_tokens(ansi_string)
|
3
|
+
ansi_string.scan(/\e.*?m|[^\e]+/).map do |token|
|
4
|
+
token[0] == "\e" ? :color : token
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.include SpecHelpers
|
11
|
+
config.fail_fast = true
|
12
|
+
config.color = true
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hylite
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Josh Cheek
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-12-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rouge
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: coderay
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: ultraviolet
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
69
|
+
description: Provides a simple binary interface and Ruby interface to highlight your
|
70
|
+
code using whatever tools you already have on your machine.
|
71
|
+
email:
|
72
|
+
- josh.cheek@gmail.com
|
73
|
+
executables:
|
74
|
+
- hylite
|
75
|
+
- syntax_hilight
|
76
|
+
- hilight_syntax
|
77
|
+
extensions: []
|
78
|
+
extra_rdoc_files: []
|
79
|
+
files:
|
80
|
+
- ".gitignore"
|
81
|
+
- Gemfile
|
82
|
+
- Readme.md
|
83
|
+
- bin/hilight_syntax
|
84
|
+
- bin/hylite
|
85
|
+
- bin/syntax_hilight
|
86
|
+
- hylite.gemspec
|
87
|
+
- lib/hylite.rb
|
88
|
+
- lib/hylite/choose_hyliter.rb
|
89
|
+
- lib/hylite/cli.rb
|
90
|
+
- lib/hylite/hyliters.rb
|
91
|
+
- lib/hylite/version.rb
|
92
|
+
- notes
|
93
|
+
- spec/binary_spec.rb
|
94
|
+
- spec/choose_hyliter.rb
|
95
|
+
- spec/hylite_spec.rb
|
96
|
+
- spec/spec_helpers.rb
|
97
|
+
homepage: https://github.com/JoshCheek/hylite
|
98
|
+
licenses:
|
99
|
+
- WTFPL
|
100
|
+
metadata: {}
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubyforge_project:
|
117
|
+
rubygems_version: 2.6.8
|
118
|
+
signing_key:
|
119
|
+
specification_version: 4
|
120
|
+
summary: Syntax Highlighting for scripters
|
121
|
+
test_files:
|
122
|
+
- spec/binary_spec.rb
|
123
|
+
- spec/choose_hyliter.rb
|
124
|
+
- spec/hylite_spec.rb
|
125
|
+
- spec/spec_helpers.rb
|