hansi 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rspec +4 -0
- data/.travis.yml +2 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.md +230 -0
- data/hansi.gemspec +22 -0
- data/hansi.png +0 -0
- data/lib/hansi.rb +53 -0
- data/lib/hansi/ansi_code.rb +16 -0
- data/lib/hansi/color.rb +115 -0
- data/lib/hansi/color_parser.rb +93 -0
- data/lib/hansi/color_renderer.rb +20 -0
- data/lib/hansi/mode_detector.rb +200 -0
- data/lib/hansi/palettes.rb +591 -0
- data/lib/hansi/sexp_renderer.rb +27 -0
- data/lib/hansi/special.rb +25 -0
- data/lib/hansi/string_renderer.rb +103 -0
- data/lib/hansi/theme.rb +66 -0
- data/lib/hansi/themes.rb +24 -0
- data/lib/hansi/version.rb +3 -0
- data/spec/hansi/color_parser_spec.rb +17 -0
- data/spec/hansi/color_renderer_spec.rb +6 -0
- data/spec/hansi/color_spec.rb +46 -0
- data/spec/hansi/mode_detector_spec.rb +35 -0
- data/spec/hansi/sexp_renderer_spec.rb +7 -0
- data/spec/hansi/special_spec.rb +6 -0
- data/spec/hansi/string_renderer_spec.rb +32 -0
- data/spec/hansi/theme_spec.rb +36 -0
- data/spec/hansi_spec.rb +41 -0
- data/spec/support.rb +6 -0
- data/spec/support/coverage.rb +14 -0
- data/spec/support/env.rb +10 -0
- data/spec/support/escape_matcher.rb +28 -0
- data/spec/support/parse_matcher.rb +28 -0
- data/spec/support/render_matcher.rb +28 -0
- metadata +56 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e1c99a2ac8ce470c64e37c42a2e94af03d80a0fe
|
4
|
+
data.tar.gz: 8c8e39771a0a0c2fab16b746d937643655b3cdd7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a394c636b3fd0e8d4456377ad2b2c79223374612f9c71cf3a4f24b5df325bca79c01ebd1a9f0057e3155ef428af796f7d70532eb52d7796a2ba1d185347c8cd9
|
7
|
+
data.tar.gz: 64b7011cbd5a09b5aec138544197f86de4a703f773dcaba9c1c06ba99e6d55b1e54830fd54a0581a67aa039fb739f79f5fe85b801223ecafafcee11386619f4a
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Konstantin Haase
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
# Der ANSI Hansi
|
2
|
+
|
3
|
+
Welcome to *The ANSI Hansi*. This is your *Hipster ANSI color library*.
|
4
|
+
|
5
|
+
It allows you to produce colorized console output.
|
6
|
+
|
7
|
+
Many ANSI color libraries are already out there. However, this library tackles a few issues most of them have:
|
8
|
+
|
9
|
+
* It supports **8 color**, **16 color**, **88 color**, **256 color** and **24 bit (True Color)** mode.
|
10
|
+
* It transparently **converts colors between modes** without you having to worry about this. It uses the YUV distance (rather than the RGB distance) to closer match how our brain perceives color similarity.
|
11
|
+
* It supports **proper color nesting**.
|
12
|
+
* It can **automatically detect** how many colors the current terminal supports.
|
13
|
+
* It does **not enforce a DSL** to be used (in fact, it does not include a DSL, but it makes it really easy to build your own DSL).
|
14
|
+
* Makes it easy to define **string templates** for highlighting, but doesn't force you to use them.
|
15
|
+
* It supports **themes**, but doesn't force you to use them. Themes make semantic coloring easier.
|
16
|
+
* It supports converting **ANSI colors to CSS rules**. It does not support parsing an ANSI colored string into HTML, this would be outside the scope of this library.
|
17
|
+
* It has zero dependencies and does not include a native extension.
|
18
|
+
* It does not monkey patch anything.
|
19
|
+
|
20
|
+
## General Usage
|
21
|
+
|
22
|
+
The main API entry points are `Hansi.render(input)` , which will generate a colorized string, depending on the input, and `Hansi[input]`, which will give you a color object. You can use Hansi for your purposes by just using one of the two, but they give you different levels of access.
|
23
|
+
|
24
|
+
The following code:
|
25
|
+
|
26
|
+
``` ruby
|
27
|
+
require 'hansi'
|
28
|
+
|
29
|
+
# simple usage
|
30
|
+
puts Hansi.render(:red, "WARNING!!")
|
31
|
+
puts Hansi.render("Hello *world*!", "*" => :bold)
|
32
|
+
|
33
|
+
# generate some colors
|
34
|
+
steps = (0..255).step(15)
|
35
|
+
render = -> options { print Hansi.render(Hansi[options], ':') }
|
36
|
+
|
37
|
+
steps.each do |red|
|
38
|
+
steps.each { |green| render[ red: red, green: green ]}
|
39
|
+
steps.each { |blue| render[ red: red, green: 255 - blue, blue: blue]}
|
40
|
+
steps.each { |blue| render[ red: red, blue: 255 - blue ]}
|
41
|
+
puts
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
Will result in output similar to this screenshot (if your terminal supports true color):
|
46
|
+
|
47
|
+
![](hansi.png)
|
48
|
+
|
49
|
+
### Rendering Strings
|
50
|
+
|
51
|
+
You can render a string in a given color:
|
52
|
+
|
53
|
+
``` ruby
|
54
|
+
puts Hansi.render(:red, "this is red")
|
55
|
+
|
56
|
+
red = Hansi["#f00"]
|
57
|
+
puts Hansi.render(red, "this is red")
|
58
|
+
```
|
59
|
+
|
60
|
+
You can render an s-expression stile nested array (good for building your own DSL on top):
|
61
|
+
|
62
|
+
``` ruby
|
63
|
+
sexp = [:red, "Hello", [:yellow, ENV["USER"]], "- how are you?"]
|
64
|
+
puts Hansi.render(sexp, join: " ")
|
65
|
+
```
|
66
|
+
|
67
|
+
It is also possible to use template strings. These can use simple markup (anything enclosed between certain characters), or HTML style tags, or a combination of the two.
|
68
|
+
|
69
|
+
``` ruby
|
70
|
+
# a simple template
|
71
|
+
puts Hansi.render("foo *bar* _blah_", "*" => :red, "_" => :green)
|
72
|
+
|
73
|
+
# escaping a character
|
74
|
+
puts Hansi.render('foo *bar* _blah\_blah_', "*" => :red, "_" => :green)
|
75
|
+
|
76
|
+
# using tags, with interpolation
|
77
|
+
puts Hansi.render("<gold>Hello <underline>%s</underline>!</gold>", ENV['USER'], tags: true)
|
78
|
+
```
|
79
|
+
|
80
|
+
You can also use `render` to turn a color object into its ANIS code.
|
81
|
+
|
82
|
+
The `render` method takes a `mode` option to enforce a color mode.
|
83
|
+
|
84
|
+
``` ruby
|
85
|
+
color = Hansi["#f80"]
|
86
|
+
Hansi.render(color, mode: 256) # => "\e[38;5;208m"
|
87
|
+
Hansi.render(color, mode: 16) # => "\e[33m"
|
88
|
+
```
|
89
|
+
|
90
|
+
### Themes
|
91
|
+
|
92
|
+
The render method takes a `theme` option. This option can have one of the following values:
|
93
|
+
|
94
|
+
* An instance of `Hansi::Theme`.
|
95
|
+
* A symbol for a predefined theme (currently `:default` or `:solarized`).
|
96
|
+
* A hash mapping rules (symbols) to other rules or color values.
|
97
|
+
* An array of any of the above.
|
98
|
+
|
99
|
+
``` ruby
|
100
|
+
|
101
|
+
my_theme = Hansi::Theme.new(foo: :yellow)
|
102
|
+
|
103
|
+
puts Hansi.render("<foo>hi</foo>", tags: true, theme: my_theme) # bright yellow
|
104
|
+
puts Hansi.render("<foo>hi</foo>", tags: true, theme: { foo: :yellow }) # bright yellow
|
105
|
+
puts Hansi.render("<foo>hi</foo>", tags: true, theme: [:solarized, my_theme]) # solarized yellow
|
106
|
+
puts Hansi.render("<yellow>hi</yellow>", tags: true, theme: :solarized) # solarized yellow
|
107
|
+
```
|
108
|
+
|
109
|
+
When creating a theme, you can also pass in other themes to inherit rules from:
|
110
|
+
|
111
|
+
``` ruby
|
112
|
+
my_theme = Hansi::Theme.new(:solarized, em: :base0, b: :base1)
|
113
|
+
puts Hansi.render("This <em>is</em> <b>important</b>!", theme: my_theme)
|
114
|
+
```
|
115
|
+
|
116
|
+
It is also possible to register your theme globally:
|
117
|
+
|
118
|
+
``` ruby
|
119
|
+
Hansi::Theme[:my_theme] = Hansi::Theme.new(:solarized, em: :base0, b: :base1)
|
120
|
+
puts Hansi.render("This <em>is</em> <b>important</b>!", theme: :my_theme)
|
121
|
+
```
|
122
|
+
|
123
|
+
### Color Objects
|
124
|
+
|
125
|
+
You can get access to a color object via `Hansi[]` or `Hansi::Theme#[]`.
|
126
|
+
|
127
|
+
``` ruby
|
128
|
+
Hansi[:yellow].red # => 255
|
129
|
+
Hansi::Theme[:solarized][:yellow].red # => 181
|
130
|
+
|
131
|
+
Hansi["#ff8300"].to_ansi(mode: 256) # => "\e[38;5;208m"
|
132
|
+
Hansi["#ff8300"].to_web_name # => :darkorange
|
133
|
+
Hansi["#ff8300"].to_web_name(exact: true) # => nil
|
134
|
+
```
|
135
|
+
|
136
|
+
You can also use a color object to find the closest color in a set of colors:
|
137
|
+
|
138
|
+
``` ruby
|
139
|
+
colors = [
|
140
|
+
Hansi[:red],
|
141
|
+
Hansi[:green],
|
142
|
+
Hansi[:blue],
|
143
|
+
Hansi[:orange]
|
144
|
+
]
|
145
|
+
|
146
|
+
Hansi[:yellow].closest(colors) # => Hansi[:orange]
|
147
|
+
```
|
148
|
+
|
149
|
+
## Advanced Usage
|
150
|
+
|
151
|
+
### Enforcing the default color mode
|
152
|
+
|
153
|
+
You can override the color mode Hansi has detected for the current terminal:
|
154
|
+
|
155
|
+
``` ruby
|
156
|
+
puts "Detected colors: %d" % Hansi.mode
|
157
|
+
Hansi.mode = Hansi::TRUE_COLOR
|
158
|
+
```
|
159
|
+
|
160
|
+
### Create your own DSL
|
161
|
+
|
162
|
+
Rather than defining a DSL, Hansi aims to be easily integrated with whatever tooling you use for building command line applications.
|
163
|
+
|
164
|
+
Combining for instance the s-expression style rendering with `Hansi.color_names` makes creaking a method name based DSL straight forward:
|
165
|
+
|
166
|
+
``` ruby
|
167
|
+
module ColorDSL
|
168
|
+
def color(*args)
|
169
|
+
Struct.new(:to_ary, :to_s).new(args, Hansi.render(args))
|
170
|
+
end
|
171
|
+
|
172
|
+
Hansi.color_names.each do |name|
|
173
|
+
define_method(name) { |*args| color(name, *args) }
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
extend ColorDSL
|
178
|
+
puts "Hello #{red("w", green("o", blue("r"), "l"), "d")}!"
|
179
|
+
```
|
180
|
+
|
181
|
+
### Generating CSS
|
182
|
+
|
183
|
+
Hansi does not turn ANSI escape codes into HTML for you, this would be outside of the scope for this project. However, depending on your use case, you might be able to generate semantic HTML yourself from whichever data structure you use.
|
184
|
+
|
185
|
+
In this case, Hansi can generate CSS rules for you.
|
186
|
+
|
187
|
+
``` ruby
|
188
|
+
Hansi[:red].to_css_rule # => "color: #ff0000;"
|
189
|
+
```
|
190
|
+
|
191
|
+
It can also generate a full stylesheet for a theme:
|
192
|
+
|
193
|
+
``` ruby
|
194
|
+
my_theme = Hansi::Theme.new(headline: :green, text: :springgreen, aside: :text, important: :bold)
|
195
|
+
puts my_theme.to_css
|
196
|
+
```
|
197
|
+
|
198
|
+
``` css
|
199
|
+
.headline {
|
200
|
+
color: #008000;
|
201
|
+
}
|
202
|
+
|
203
|
+
.text, .aside {
|
204
|
+
color: #00ff7f;
|
205
|
+
}
|
206
|
+
|
207
|
+
.important {
|
208
|
+
font-weight: bold;
|
209
|
+
}
|
210
|
+
```
|
211
|
+
|
212
|
+
You can pass a block for generating the css selector for a given rule name:
|
213
|
+
|
214
|
+
``` ruby
|
215
|
+
puts my_theme.to_css { |name| ".hansi .#{name}" }
|
216
|
+
```
|
217
|
+
|
218
|
+
``` css
|
219
|
+
.hansi .headline {
|
220
|
+
color: #008000;
|
221
|
+
}
|
222
|
+
|
223
|
+
.hansi .text, .hansi .aside {
|
224
|
+
color: #00ff7f;
|
225
|
+
}
|
226
|
+
|
227
|
+
.hansi .important {
|
228
|
+
font-weight: bold;
|
229
|
+
}
|
230
|
+
```
|
data/hansi.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
$:.unshift File.expand_path("../lib", __FILE__)
|
2
|
+
require "hansi/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "hansi"
|
6
|
+
s.version = Hansi::VERSION
|
7
|
+
s.author = "Konstantin Haase"
|
8
|
+
s.email = "konstantin.mailinglists@googlemail.com"
|
9
|
+
s.homepage = "https://github.com/rkh/hansi"
|
10
|
+
s.summary = %q{Hipster ANSI color library}
|
11
|
+
s.description = %q{Der ANSI Hansi - create colorized console output.}
|
12
|
+
s.license = 'MIT'
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
|
+
s.required_ruby_version = '>= 2.0.0'
|
17
|
+
|
18
|
+
s.add_development_dependency 'tool', '~> 0.2'
|
19
|
+
s.add_development_dependency 'rspec'
|
20
|
+
s.add_development_dependency 'simplecov'
|
21
|
+
s.add_development_dependency 'coveralls'
|
22
|
+
end
|
data/hansi.png
ADDED
Binary file
|
data/lib/hansi.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
module Hansi
|
2
|
+
TRUE_COLOR = 256**3
|
3
|
+
|
4
|
+
def self.[](*args)
|
5
|
+
ColorParser.parse(*args)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.mode
|
9
|
+
@mode ||= mode_for(ENV)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.mode=(value)
|
13
|
+
@mode = value
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.mode_for(env, **options)
|
17
|
+
ModeDetector.new(env, **options).mode
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.render(*input, **options)
|
21
|
+
renderer_for(input.first).render(*input, **options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.renderer_for(input)
|
25
|
+
case input
|
26
|
+
when String then StringRenderer
|
27
|
+
when Symbol, Array then SexpRenderer
|
28
|
+
when AnsiCode then ColorRenderer
|
29
|
+
else raise ArgumentError, "don't know how to render %p" % input
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.reset
|
34
|
+
Hansi[:reset].to_ansi
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.color_names
|
38
|
+
PALETTES['web'].keys
|
39
|
+
end
|
40
|
+
|
41
|
+
require 'hansi/ansi_code'
|
42
|
+
require 'hansi/color'
|
43
|
+
require 'hansi/special'
|
44
|
+
|
45
|
+
require 'hansi/color_parser'
|
46
|
+
require 'hansi/color_renderer'
|
47
|
+
require 'hansi/mode_detector'
|
48
|
+
require 'hansi/palettes'
|
49
|
+
require 'hansi/sexp_renderer'
|
50
|
+
require 'hansi/string_renderer'
|
51
|
+
require 'hansi/theme'
|
52
|
+
require 'hansi/themes'
|
53
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Hansi
|
2
|
+
class AnsiCode
|
3
|
+
def to_ansi_code(**options)
|
4
|
+
end
|
5
|
+
|
6
|
+
def to_css_rule
|
7
|
+
"/* cannot convert #{inspect} to css */"
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_css(*names, &block)
|
11
|
+
block ||= -> key { ".#{key}" }
|
12
|
+
name = names.map(&block).join(', ')
|
13
|
+
"#{name} {\n #{to_css_rule.gsub(/;\n?\s+(\S)/, ";\n \\1")}\n}\n"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/hansi/color.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
module Hansi
|
2
|
+
class Color < AnsiCode
|
3
|
+
attr_reader :red, :green, :blue, :distance_cache
|
4
|
+
protected :distance_cache
|
5
|
+
|
6
|
+
def initialize(red, green, blue)
|
7
|
+
@red, @green, @blue = red, green, blue
|
8
|
+
@distance_cache = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def hash
|
12
|
+
to_i.hash
|
13
|
+
end
|
14
|
+
|
15
|
+
def ==(other)
|
16
|
+
other.class == self.class and other.to_i == self.to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
def eql?(other)
|
20
|
+
other.class.eql?(self.class) and other.to_i.eql?(self.to_i)
|
21
|
+
end
|
22
|
+
|
23
|
+
def distance(other)
|
24
|
+
distance_cache[other.to_i] ||= other.distance_cache[to_i] || begin
|
25
|
+
y1, u1, v1 = to_yuv
|
26
|
+
y2, u2, v2 = other.to_yuv
|
27
|
+
dy, du, dv = y1 - y2, u1 - u2, v1 - v2
|
28
|
+
Math.sqrt(dy**2 + du**2 + dv**2)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def closest(set)
|
33
|
+
if set.respond_to? :to_hash
|
34
|
+
hash = set.to_hash
|
35
|
+
hash.key(closest(hash.values))
|
36
|
+
elsif set.include? self
|
37
|
+
self
|
38
|
+
else
|
39
|
+
set.grep(Color).min_by { |c| distance(c) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_yuv
|
44
|
+
@yuv ||= begin
|
45
|
+
y = (0.257 * red) + (0.504 * green) + (0.098 * blue) + 16
|
46
|
+
u = -(0.148 * red) - (0.291 * green) + (0.439 * blue) + 128
|
47
|
+
v = (0.439 * red) - (0.368 * green) - (0.071 * blue) + 128
|
48
|
+
[y, u, v].freeze
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_i
|
53
|
+
(red << 16) + (green << 8) + blue
|
54
|
+
end
|
55
|
+
|
56
|
+
def inspect
|
57
|
+
"#<%p:%d,%d,%d>" % [self.class, red, green, blue]
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_s
|
61
|
+
"#%06x" % to_i
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_css_rule
|
65
|
+
"color: #{self};"
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_ansi(mode: Hansi.mode, **options)
|
69
|
+
case Integer === mode ? mode : Integer(mode.to_s[/\d+/])
|
70
|
+
when 256 then to_ansi_256colors(**options)
|
71
|
+
when 24, TRUE_COLOR then to_ansi_24bit(**options)
|
72
|
+
when 88 then to_ansi_88colors(**options)
|
73
|
+
when 16 then to_ansi_16colors(**options)
|
74
|
+
when 8 then to_ansi_8colors(**options)
|
75
|
+
when 1, 0 then ""
|
76
|
+
else raise ArgumentError, "unknown mode %p" % mode
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_ansi_24bit(**options)
|
81
|
+
"\e[38;2;%d;%d;%dm" % [red, green, blue]
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_ansi_256colors(**options)
|
85
|
+
from_palette('xterm-256color', 'xterm', **options)
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_ansi_88colors(**options)
|
89
|
+
from_palette('xterm-88color', 'xterm', **options)
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_ansi_16colors(**options)
|
93
|
+
from_palette('xterm', **options)
|
94
|
+
end
|
95
|
+
|
96
|
+
def to_ansi_8colors(**options)
|
97
|
+
from_palette('ansi', **options)
|
98
|
+
end
|
99
|
+
|
100
|
+
def to_web_name(**options)
|
101
|
+
from_palette('web', **options)
|
102
|
+
end
|
103
|
+
|
104
|
+
def from_palette(main, *fallback, exact: false)
|
105
|
+
@from_palette ||= { true => {}, false => {} }
|
106
|
+
cached = @from_palette[exact]
|
107
|
+
cached[main] ||= PALETTES[main].key(self)
|
108
|
+
cached[main] ||= closest(PALETTES[main]) unless exact
|
109
|
+
cached[main] ||= from_palette(*fallback, exact: exact) if fallback.any?
|
110
|
+
cached[main]
|
111
|
+
end
|
112
|
+
|
113
|
+
private :from_palette
|
114
|
+
end
|
115
|
+
end
|