pry-theme 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +1 -0
- data/.travis.yml +8 -1
- data/CHANGELOG.md +40 -0
- data/Gemfile +1 -1
- data/README.md +26 -48
- data/Rakefile +10 -1
- data/VERSION +1 -0
- data/lib/pry-theme/basic_editor.rb +116 -0
- data/lib/pry-theme/color.rb +431 -0
- data/lib/pry-theme/color_table.rb +39 -0
- data/lib/pry-theme/colors/color16.rb +35 -0
- data/lib/pry-theme/colors/color256.rb +30 -0
- data/lib/pry-theme/colors/color8.rb +31 -0
- data/lib/pry-theme/commands.rb +237 -275
- data/lib/pry-theme/declaration.rb +120 -0
- data/lib/pry-theme/definition.rb +111 -0
- data/lib/pry-theme/formattable.rb +26 -0
- data/lib/pry-theme/hex.rb +76 -0
- data/lib/pry-theme/preview.rb +74 -0
- data/lib/pry-theme/rgb.rb +238 -13
- data/lib/pry-theme/term.rb +66 -0
- data/lib/pry-theme/theme.rb +116 -26
- data/lib/pry-theme/theme_list.rb +52 -0
- data/lib/pry-theme/when_started_hook.rb +25 -27
- data/lib/pry-theme.rb +84 -158
- data/pry-theme.gemspec +14 -18
- data/spec/color_table.rb +53 -0
- data/spec/colors/color16_spec.rb +255 -0
- data/spec/colors/color256_spec.rb +323 -0
- data/spec/colors/color8_spec.rb +254 -0
- data/spec/commands_spec.rb +203 -0
- data/spec/helper.rb +16 -0
- data/spec/hex_spec.rb +52 -0
- data/spec/rgb_spec.rb +81 -0
- data/spec/term_spec.rb +23 -0
- data/spec/theme_spec.rb +486 -0
- data/themes/github.prytheme.rb +49 -0
- data/themes/monokai.prytheme.rb +48 -0
- data/themes/pry-classic-16.prytheme.rb +48 -0
- data/themes/pry-classic-256.prytheme.rb +48 -0
- data/themes/pry-classic-8.prytheme.rb +48 -0
- data/themes/pry-cold.prytheme.rb +49 -0
- data/themes/pry-love-16.prytheme.rb +48 -0
- data/themes/pry-love-8.prytheme.rb +48 -0
- data/themes/pry-modern-16.prytheme.rb +48 -0
- data/themes/pry-modern-256.prytheme.rb +48 -0
- data/themes/pry-modern-8.prytheme.rb +48 -0
- data/themes/pry-monochrome.prytheme.rb +32 -0
- data/themes/pry-siberia-16.prytheme.rb +48 -0
- data/themes/pry-siberia-8.prytheme.rb +48 -0
- data/themes/pry-tepid-16.prytheme.rb +48 -0
- data/themes/pry-tepid-8.prytheme.rb +48 -0
- data/themes/pry-zealand-16.prytheme.rb +48 -0
- data/themes/pry-zealand-8.prytheme.rb +49 -0
- data/themes/railscasts.prytheme.rb +50 -0
- data/themes/solarized.prytheme.rb +48 -0
- data/themes/tomorrow.prytheme.rb +48 -0
- data/themes/twilight.prytheme.rb +48 -0
- data/themes/vim-default.prytheme.rb +50 -0
- data/themes/vim-detailed.prytheme.rb +50 -0
- data/themes/zenburn.prytheme.rb +48 -0
- metadata +56 -41
- data/lib/pry-theme/color_converter.rb +0 -55
- data/lib/pry-theme/helper.rb +0 -87
- data/lib/pry-theme/palette.rb +0 -85
- data/lib/pry-theme/term_notation.rb +0 -17
- data/lib/pry-theme/version.rb +0 -3
- data/test/fixtures/pry-classic.prytheme +0 -38
- data/test/helper.rb +0 -56
- data/test/test_color_converter.rb +0 -38
- data/test/test_commands.rb +0 -55
- data/test/test_helper.rb +0 -45
- data/test/test_palette.rb +0 -11
- data/themes/github.prytheme +0 -43
- data/themes/monokai.prytheme +0 -42
- data/themes/pry-classic.prytheme +0 -43
- data/themes/pry-cold.prytheme +0 -43
- data/themes/pry-modern.prytheme +0 -42
- data/themes/railscasts.prytheme +0 -44
- data/themes/saturday.prytheme +0 -42
- data/themes/solarized.prytheme +0 -43
- data/themes/tomorrow.prytheme +0 -43
- data/themes/twilight.prytheme +0 -42
- data/themes/vim-default.prytheme +0 -42
- data/themes/vim-detailed.prytheme +0 -42
- data/themes/zenburn.prytheme +0 -43
@@ -0,0 +1,120 @@
|
|
1
|
+
module PryTheme
|
2
|
+
class Color
|
3
|
+
|
4
|
+
# @since 0.2.0
|
5
|
+
# @api private
|
6
|
+
class Declaration
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def translate(decl, color_model)
|
10
|
+
decl = Declaration.new(decl, color_model)
|
11
|
+
decl.parse
|
12
|
+
decl.to_color
|
13
|
+
end
|
14
|
+
alias_method :t, :translate
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(color_decl, color_model)
|
18
|
+
validate_effects(color_decl, color_model)
|
19
|
+
|
20
|
+
@color_decl = color_decl
|
21
|
+
@color_model = color_model
|
22
|
+
@color_class = PryTheme.const_get(:"Color#{ color_model }")
|
23
|
+
@effects = {}
|
24
|
+
@parsed = false
|
25
|
+
end
|
26
|
+
|
27
|
+
def parse
|
28
|
+
if @parsed
|
29
|
+
return
|
30
|
+
else
|
31
|
+
case @color_decl.size
|
32
|
+
when 3 then build_from_two_layers
|
33
|
+
when 2 then build_from_two_args
|
34
|
+
when 1 then build_from_arg
|
35
|
+
end
|
36
|
+
@parsed = true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_color
|
41
|
+
[:readable, :hex, :rgb, :term].each do |type|
|
42
|
+
begin
|
43
|
+
return @color_class.new({
|
44
|
+
:from => type,
|
45
|
+
:foreground => @fg,
|
46
|
+
:background => @bg
|
47
|
+
}.merge!(@effects))
|
48
|
+
rescue ArgumentError, TypeError
|
49
|
+
next
|
50
|
+
end
|
51
|
+
end
|
52
|
+
raise PryTheme::ThemeError,
|
53
|
+
%|malformed color declaration (#{ [@fg, @bg].compact.join(', ') })|
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def validate_effects(color_decl, color_model)
|
59
|
+
incorrect_color_model = (color_model != 256)
|
60
|
+
incorrect_declaration = (color_decl.any? do |decl|
|
61
|
+
decl.is_a?(Array) && decl.all? { |elem| elem.is_a?(Symbol) }
|
62
|
+
end)
|
63
|
+
|
64
|
+
if incorrect_color_model && incorrect_declaration
|
65
|
+
raise PryTheme::ThemeError,
|
66
|
+
'effects are available only for 256-color themes'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def build_effects
|
71
|
+
if @color_decl.any?
|
72
|
+
@effects = @color_decl.shift.inject({}) { |h, k| h[k] = true; h }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def build_from_two_layers
|
77
|
+
@fg, @bg = 2.times.map { @color_decl.shift }
|
78
|
+
build_effects
|
79
|
+
end
|
80
|
+
|
81
|
+
def build_from_two_args
|
82
|
+
if decl_has_bg_key?
|
83
|
+
@bg = @color_decl.first[:bg]
|
84
|
+
@color_decl.shift
|
85
|
+
else
|
86
|
+
@fg = @color_decl.shift
|
87
|
+
if @color_decl.last.is_a?(Array)
|
88
|
+
@bg = @color_decl.shift if decl_contains_rgb?
|
89
|
+
else
|
90
|
+
@bg = @color_decl.shift
|
91
|
+
end
|
92
|
+
end
|
93
|
+
build_effects
|
94
|
+
end
|
95
|
+
|
96
|
+
def build_from_arg
|
97
|
+
f = @color_decl.first
|
98
|
+
if decl_has_bg_key?
|
99
|
+
@bg = f[:bg]
|
100
|
+
@color_decl.shift
|
101
|
+
elsif f.is_a?(String) || f.is_a?(Fixnum)
|
102
|
+
@fg = @color_decl.shift
|
103
|
+
else
|
104
|
+
build_effects
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def decl_has_bg_key?
|
109
|
+
f = @color_decl.first
|
110
|
+
f.is_a?(Hash) && f.has_key?(:bg)
|
111
|
+
end
|
112
|
+
|
113
|
+
def decl_contains_rgb?
|
114
|
+
l = @color_decl.last
|
115
|
+
l.size == 3 && l.all? { |decl| decl.is_a?(Fixnum) }
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module PryTheme
|
2
|
+
class Theme
|
3
|
+
|
4
|
+
# @since 0.2.0
|
5
|
+
# @api private
|
6
|
+
module DynamicMethod
|
7
|
+
def def_dynamic_methods(*dynamic_methods)
|
8
|
+
dynamic_methods.each { |attr|
|
9
|
+
define_method(attr) do |*args|
|
10
|
+
name = :"@#{ attr }"
|
11
|
+
if args.first
|
12
|
+
decl =
|
13
|
+
Color::Declaration.t(args, instance_variable_get(:@color_model))
|
14
|
+
instance_variable_set(name, decl)
|
15
|
+
end
|
16
|
+
instance_variable_get(name)
|
17
|
+
end
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# @since 0.2.0
|
23
|
+
# @api private
|
24
|
+
module DefaultAttrs
|
25
|
+
def set_default_attrs(attrs)
|
26
|
+
default_color = PryTheme.const_get(:"Color#{ @color_model }").new
|
27
|
+
attrs.each do |attr|
|
28
|
+
instance_variable_set(:"@#{ attr }", default_color.dup)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def set_nested_attrs
|
33
|
+
regexp { set_default_attrs(Definition::Regexp::ATTRS) }
|
34
|
+
shell { set_default_attrs(Definition::Shell::ATTRS) }
|
35
|
+
string { set_default_attrs(Definition::String::ATTRS) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def method_missing(meth, *args, &block)
|
39
|
+
raise PryTheme::ThemeError, %|unknown option "#{ meth }"|
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# @since 0.2.0
|
44
|
+
# @api private
|
45
|
+
# @todo: possibly, try to avoid duplication.
|
46
|
+
class Definition
|
47
|
+
extend DynamicMethod
|
48
|
+
include DefaultAttrs
|
49
|
+
|
50
|
+
ATTRS = [
|
51
|
+
:class_, :class_variable, :comment, :constant, :error, :float,
|
52
|
+
:global_variable, :inline_delimiter, :instance_variable, :integer,
|
53
|
+
:keyword, :method, :predefined_constant, :symbol
|
54
|
+
]
|
55
|
+
|
56
|
+
def_dynamic_methods *ATTRS
|
57
|
+
|
58
|
+
def initialize(color_model, &block)
|
59
|
+
@color_model = color_model
|
60
|
+
set_default_attrs(ATTRS) and set_nested_attrs
|
61
|
+
instance_eval(&block)
|
62
|
+
end
|
63
|
+
|
64
|
+
def regexp(&block)
|
65
|
+
@regexp = Definition::Regexp.new(@color_model, &block) if block_given?
|
66
|
+
@regexp
|
67
|
+
end
|
68
|
+
|
69
|
+
def shell(&block)
|
70
|
+
@shell = Definition::Shell.new(@color_model, &block) if block_given?
|
71
|
+
@shell
|
72
|
+
end
|
73
|
+
|
74
|
+
def string(&block)
|
75
|
+
@string = Definition::String.new(@color_model, &block) if block_given?
|
76
|
+
@string
|
77
|
+
end
|
78
|
+
|
79
|
+
class Compound
|
80
|
+
extend DynamicMethod
|
81
|
+
include DefaultAttrs
|
82
|
+
|
83
|
+
ATTRS = [:self_, :char, :content, :delimiter, :escape]
|
84
|
+
|
85
|
+
def_dynamic_methods *ATTRS
|
86
|
+
|
87
|
+
def initialize(color_model, &block)
|
88
|
+
@color_model = color_model
|
89
|
+
set_default_attrs(ATTRS)
|
90
|
+
instance_eval(&block)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class Regexp < Compound
|
95
|
+
ATTRS = [:modifier]
|
96
|
+
|
97
|
+
def_dynamic_methods *ATTRS
|
98
|
+
|
99
|
+
def initialize(color_model, &block)
|
100
|
+
@color_model = color_model
|
101
|
+
set_default_attrs(ATTRS)
|
102
|
+
super
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
Shell = Class.new(Compound)
|
107
|
+
String = Class.new(Compound)
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module PryTheme
|
2
|
+
module Formattable
|
3
|
+
|
4
|
+
FORMATTING = {
|
5
|
+
:bold => 1,
|
6
|
+
:italic => 3,
|
7
|
+
:underline => 4
|
8
|
+
}
|
9
|
+
|
10
|
+
def bold
|
11
|
+
options[:bold] && FORMATTING[:bold]
|
12
|
+
end
|
13
|
+
def bold?; !!bold; end
|
14
|
+
|
15
|
+
def italic
|
16
|
+
options[:italic] && FORMATTING[:italic]
|
17
|
+
end
|
18
|
+
def italic?; !!italic; end
|
19
|
+
|
20
|
+
def underline
|
21
|
+
options[:underline] && FORMATTING[:underline]
|
22
|
+
end
|
23
|
+
def underline?; !!underline; end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module PryTheme
|
2
|
+
# @since 0.2.0
|
3
|
+
# @api private
|
4
|
+
#
|
5
|
+
# Represents a HEX colour. It's possible to convert a HEX instance into {TERM}
|
6
|
+
# or {RGB} colours. However, this conversion is half-duplex (see {RGB}). This
|
7
|
+
# class validates its input (you won't see malformed or nonexistent HEX
|
8
|
+
# colours).
|
9
|
+
#
|
10
|
+
# @note Conversion to {TERM} relies on {RGB#to_term}, as a {HEX} instance
|
11
|
+
# converts itself to {RGB} first, and only then to {TERM}.
|
12
|
+
# @example Conversion to RGB
|
13
|
+
# HEX.new('#ffffff').to_rgb #=> (RGB: 255, 255, 255)
|
14
|
+
# @example Conversion to TERM
|
15
|
+
# HEX.new('#ffffff').to_term(16) #=> (TERM-16: 15)
|
16
|
+
#
|
17
|
+
# # Approximation.
|
18
|
+
# HEX.new('#fc33ea').to_term #=> (TERM-256: 207)
|
19
|
+
class HEX
|
20
|
+
|
21
|
+
# Represents a single HEX "digit".
|
22
|
+
BYTE = /[A-F\d]{2}/i
|
23
|
+
|
24
|
+
# A hex String must be prefixed with an octothorp. Use any letter case.
|
25
|
+
PATTERN = /\A#(#{ BYTE }){3}\z/i
|
26
|
+
|
27
|
+
# @param [String] value must be a valid hex number
|
28
|
+
def initialize(value)
|
29
|
+
validate_value(value)
|
30
|
+
@value = value
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [String]
|
34
|
+
def inspect
|
35
|
+
"(HEX: #{ @value })"
|
36
|
+
end
|
37
|
+
|
38
|
+
# @example
|
39
|
+
# HEX.new('#33aabb').to_s #=> "#33aabb"
|
40
|
+
# @return [String]
|
41
|
+
def to_s
|
42
|
+
@value
|
43
|
+
end
|
44
|
+
|
45
|
+
# Converts `self` into {RGB}.
|
46
|
+
# @return [RGB]
|
47
|
+
def to_rgb
|
48
|
+
RGB.new(@value[1..-1].scan(BYTE).map! { |b| b.to_i(16) })
|
49
|
+
end
|
50
|
+
|
51
|
+
# Converts `self` into {TERM}.
|
52
|
+
# @return [RGB]
|
53
|
+
def to_term(color_model = 256)
|
54
|
+
to_rgb.to_term(color_model)
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Validates whether +value+ is a valid hex colour value.
|
60
|
+
#
|
61
|
+
# @param [String] value
|
62
|
+
# @raise [TypeError] if +value+ isn't String
|
63
|
+
# @raise [ArgumentError] if +value+ is malformed
|
64
|
+
# @return [void]
|
65
|
+
def validate_value(value)
|
66
|
+
unless value.is_a?(String)
|
67
|
+
raise TypeError, "can't convert #{ value.class } into PryTheme::HEX"
|
68
|
+
end
|
69
|
+
if value !~ PryTheme::HEX::PATTERN
|
70
|
+
raise ArgumentError, %|invalid value for PryTheme::HEX#new(): "#{ value }"|
|
71
|
+
end
|
72
|
+
true
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module PryTheme
|
2
|
+
class Preview
|
3
|
+
|
4
|
+
def initialize(theme)
|
5
|
+
@theme = theme
|
6
|
+
end
|
7
|
+
|
8
|
+
def short
|
9
|
+
cur_theme = ThemeList.current_theme
|
10
|
+
@theme.activate
|
11
|
+
[header, description, '--', short_snippet].join("\n")
|
12
|
+
ensure
|
13
|
+
@theme.disable
|
14
|
+
cur_theme.activate
|
15
|
+
end
|
16
|
+
|
17
|
+
def long
|
18
|
+
long_snippet
|
19
|
+
end
|
20
|
+
|
21
|
+
def description
|
22
|
+
@theme.description
|
23
|
+
end
|
24
|
+
|
25
|
+
def header
|
26
|
+
Pry::Helpers::Text.bold("#{ @theme.name } / #{ @theme.color_model }")
|
27
|
+
end
|
28
|
+
|
29
|
+
def banner(msg)
|
30
|
+
safe_width = 80
|
31
|
+
delimiter = ('-' * safe_width)
|
32
|
+
[delimiter,
|
33
|
+
Pry::Helpers::Text.bold(msg.center(safe_width)),
|
34
|
+
delimiter
|
35
|
+
].join("\n") + "\n"
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def short_snippet
|
41
|
+
code = Pry::Helpers::CommandHelpers.unindent(<<-'CODE')
|
42
|
+
1: class Theme
|
43
|
+
2: def method
|
44
|
+
3: @ivar, @@cvar, lvar = 10_000, 400.00, "string"
|
45
|
+
4: end
|
46
|
+
5: end
|
47
|
+
CODE
|
48
|
+
Pry::Helpers::BaseHelpers.colorize_code(code)
|
49
|
+
end
|
50
|
+
|
51
|
+
def long_snippet
|
52
|
+
code = Pry::Helpers::CommandHelpers.unindent(<<-CODE)
|
53
|
+
# "#{ @theme.name }" theme.
|
54
|
+
class PryTheme::ThisIsAClass
|
55
|
+
def this_is_a_method
|
56
|
+
THIS_IS_A_CONSTANT = :this_is_a_symbol
|
57
|
+
this_is_a_local_var = "\#{this} \#@is a string.\\n"
|
58
|
+
this_is_a_float = 10_000.00
|
59
|
+
this_is_an_integer = 10_000
|
60
|
+
|
61
|
+
# TRUE and FALSE are predefined constants.
|
62
|
+
$this_is_a_global_variable = TRUE or FALSE
|
63
|
+
|
64
|
+
@this_is_an_instance_variable = `echo '\#@hi \#{system} call\\n'`
|
65
|
+
@@this_is_a_class_variable = @@@\\\\$ # An error.
|
66
|
+
|
67
|
+
/[0-9]{1,3}this \#{is} a regexp\\w+/xi
|
68
|
+
end
|
69
|
+
end
|
70
|
+
CODE
|
71
|
+
Pry::Helpers::BaseHelpers.colorize_code(code)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/pry-theme/rgb.rb
CHANGED
@@ -1,23 +1,248 @@
|
|
1
1
|
module PryTheme
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
2
|
+
# @since 0.2.0
|
3
|
+
# @api private
|
4
|
+
#
|
5
|
+
# Represents an RGB colour. It's possible to convert an RGB instance into
|
6
|
+
# {HEX} or {TERM} colours. However, this conversion is half-duplex. If an RGB
|
7
|
+
# instance gets converted to {TERM} format, there is a high chance that it
|
8
|
+
# will be approximated to fit in range of colour model (colour model can be
|
9
|
+
# set via an argument of the conversion method). This class validates its
|
10
|
+
# input (you won't see malformed of nonexistent RGB colours).
|
11
|
+
#
|
12
|
+
# @example Conversion to HEX
|
13
|
+
# RGB.new([0, 0, 0]).to_hex #=> (HEX: #000000)
|
14
|
+
# @example Conversion to TERM
|
15
|
+
# RGB.new([0, 0, 0]).to_term(8) #=> (TERM-8: 0)
|
16
|
+
#
|
17
|
+
# # Approximation.
|
18
|
+
# RGB.new([254, 244, 231]).to_term(8) #=> (TERM-8: 7)
|
19
|
+
class RGB
|
20
|
+
|
21
|
+
# 8 colours. For the standard GNU/Linux terminal emulator.
|
22
|
+
LINUX = [
|
23
|
+
[ 0, 0, 0], [128, 0, 0], [ 0, 128, 0],
|
24
|
+
[128, 128, 0], [ 0, 0, 128], [128, 0, 128],
|
25
|
+
[ 0, 128, 128], [192, 192, 192]
|
26
|
+
]
|
27
|
+
|
28
|
+
# 16 colours. For cmd.exe on Windows and other miserable terminals.
|
29
|
+
SYSTEM = LINUX + [
|
30
|
+
[128, 128, 128], [255, 0, 0], [ 0, 255, 0], [255, 255, 0],
|
31
|
+
[ 0, 0, 255], [255, 0, 255], [ 0, 255, 255], [255, 255, 255]
|
11
32
|
]
|
12
33
|
|
34
|
+
# The next 216 colours. For men.
|
13
35
|
COLORS = [
|
14
|
-
[0,
|
36
|
+
[ 0, 0, 0], [ 0, 0, 95], [ 0, 0, 135], [ 0, 0, 175],
|
37
|
+
[ 0, 0, 215], [ 0, 0, 255], [ 0, 95, 0], [ 0, 95, 95],
|
38
|
+
[ 0, 95, 135], [ 0, 95, 175], [ 0, 95, 215], [ 0, 95, 255],
|
39
|
+
[ 0, 135, 0], [ 0, 135, 95], [ 0, 135, 135], [ 0, 135, 175],
|
40
|
+
[ 0, 135, 215], [ 0, 135, 255], [ 0, 175, 0], [ 0, 175, 95],
|
41
|
+
[ 0, 175, 135], [ 0, 175, 175], [ 0, 175, 215], [ 0, 175, 255],
|
42
|
+
[ 0, 215, 0], [ 0, 215, 95], [ 0, 215, 135], [ 0, 215, 175],
|
43
|
+
[ 0, 215, 215], [ 0, 215, 255], [ 0, 255, 0], [ 0, 255, 95],
|
44
|
+
[ 0, 255, 135], [ 0, 255, 175], [ 0, 255, 215], [ 0, 255, 255],
|
45
|
+
[ 95, 0, 0], [ 95, 0, 95], [ 95, 0, 135], [ 95, 0, 175],
|
46
|
+
[ 95, 0, 215], [ 95, 0, 255], [ 95, 95, 0], [ 95, 95, 95],
|
47
|
+
[ 95, 95, 135], [ 95, 95, 175], [ 95, 95, 215], [ 95, 95, 255],
|
48
|
+
[ 95, 135, 0], [ 95, 135, 95], [ 95, 135, 135], [ 95, 135, 175],
|
49
|
+
[ 95, 135, 215], [ 95, 135, 255], [ 95, 175, 0], [ 95, 175, 95],
|
50
|
+
[ 95, 175, 135], [ 95, 175, 175], [ 95, 175, 215], [ 95, 175, 255],
|
51
|
+
[ 95, 215, 0], [ 95, 215, 95], [ 95, 215, 135], [ 95, 215, 175],
|
52
|
+
[ 95, 215, 215], [ 95, 215, 255], [ 95, 255, 0], [ 95, 255, 95],
|
53
|
+
[ 95, 255, 135], [ 95, 255, 175], [ 95, 255, 215], [ 95, 255, 255],
|
54
|
+
[135, 0, 0], [135, 0, 95], [135, 0, 135], [135, 0, 175],
|
55
|
+
[135, 0, 215], [135, 0, 255], [135, 95, 0], [135, 95, 95],
|
56
|
+
[135, 95, 135], [135, 95, 175], [135, 95, 215], [135, 95, 255],
|
57
|
+
[135, 135, 0], [135, 135, 95], [135, 135, 135], [135, 135, 175],
|
58
|
+
[135, 135, 215], [135, 135, 255], [135, 175, 0], [135, 175, 95],
|
59
|
+
[135, 175, 135], [135, 175, 175], [135, 175, 215], [135, 175, 255],
|
60
|
+
[135, 215, 0], [135, 215, 95], [135, 215, 135], [135, 215, 175],
|
61
|
+
[135, 215, 215], [135, 215, 255], [135, 255, 0], [135, 255, 95],
|
62
|
+
[135, 255, 135], [135, 255, 175], [135, 255, 215], [135, 255, 255],
|
63
|
+
[175, 0, 0], [175, 0, 95], [175, 0, 135], [175, 0, 175],
|
64
|
+
[175, 0, 215], [175, 0, 255], [175, 95, 0], [175, 95, 95],
|
65
|
+
[175, 95, 135], [175, 95, 175], [175, 95, 215], [175, 95, 255],
|
66
|
+
[175, 135, 0], [175, 135, 95], [175, 135, 135], [175, 135, 175],
|
67
|
+
[175, 135, 215], [175, 135, 255], [175, 175, 0], [175, 175, 95],
|
68
|
+
[175, 175, 135], [175, 175, 175], [175, 175, 215], [175, 175, 255],
|
69
|
+
[175, 215, 0], [175, 215, 95], [175, 215, 135], [175, 215, 175],
|
70
|
+
[175, 215, 215], [175, 215, 255], [175, 255, 0], [175, 255, 95],
|
71
|
+
[175, 255, 135], [175, 255, 175], [175, 255, 215], [175, 255, 255],
|
72
|
+
[215, 0, 0], [215, 0, 95], [215, 0, 135], [215, 0, 175],
|
73
|
+
[215, 0, 215], [215, 0, 255], [215, 95, 0], [215, 95, 95],
|
74
|
+
[215, 95, 135], [215, 95, 175], [215, 95, 215], [215, 95, 255],
|
75
|
+
[215, 135, 0], [215, 135, 95], [215, 135, 135], [215, 135, 175],
|
76
|
+
[215, 135, 215], [215, 135, 255], [215, 175, 0], [215, 175, 95],
|
77
|
+
[215, 175, 135], [215, 175, 175], [215, 175, 175], [215, 175, 215],
|
78
|
+
[215, 175, 255], [215, 215, 0], [215, 215, 95], [215, 215, 135],
|
79
|
+
[215, 215, 175], [215, 215, 215], [215, 215, 255], [215, 255, 0],
|
80
|
+
[215, 255, 95], [215, 255, 135], [215, 255, 175], [215, 255, 215],
|
81
|
+
[215, 255, 255], [255, 0, 0], [255, 0, 95], [255, 0, 135],
|
82
|
+
[255, 0, 175], [255, 0, 215], [255, 0, 255], [255, 95, 0],
|
83
|
+
[255, 95, 95], [255, 95, 135], [255, 95, 175], [255, 95, 215],
|
84
|
+
[255, 95, 255], [255, 135, 0], [255, 135, 95], [255, 135, 135],
|
85
|
+
[255, 135, 175], [255, 135, 215], [255, 135, 255], [255, 175, 0],
|
86
|
+
[255, 175, 95], [255, 175, 135], [255, 175, 175], [255, 175, 215],
|
87
|
+
[255, 175, 255], [255, 215, 0], [255, 215, 95], [255, 215, 135],
|
88
|
+
[255, 215, 175], [255, 215, 215], [255, 215, 255], [255, 255, 0],
|
89
|
+
[255, 255, 95], [255, 255, 135], [255, 255, 175], [255, 255, 215]
|
15
90
|
]
|
16
91
|
|
17
|
-
|
92
|
+
# The next 16 colours. For zen.
|
93
|
+
GREYSCALE = (0x08..0xEE).step(0x0A).map { |v| [v] * 3 }
|
94
|
+
|
95
|
+
# Combine everything into a full featured 256 colour RGB model.
|
96
|
+
TABLE = SYSTEM + COLORS + GREYSCALE
|
97
|
+
|
98
|
+
# The key points that are used to calculate the nearest match of an RGB.
|
99
|
+
BYTEPOINTS_256 = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff]
|
100
|
+
|
101
|
+
# @param [Array<Integer>, String] value a String will be converted to Array
|
102
|
+
# @raise [TypeError] if the +value+ is neither Array or String
|
103
|
+
def initialize(value)
|
104
|
+
@value =
|
105
|
+
case value
|
106
|
+
when Array
|
107
|
+
validate_array(value)
|
108
|
+
value
|
109
|
+
when String
|
110
|
+
validate_array(value = value.scan(/\d+/).map!(&:to_i))
|
111
|
+
value
|
112
|
+
else
|
113
|
+
raise TypeError, "can't convert #{ value.class } into PryTheme::RGB"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# @return [String]
|
118
|
+
def inspect
|
119
|
+
"(RGB: #{ to_s })"
|
120
|
+
end
|
121
|
+
|
122
|
+
# Converts the RGB to a terminal colour equivalent.
|
123
|
+
#
|
124
|
+
# @note Accepts the following numbers: 256, 16, 8.
|
125
|
+
# @param [Integer] color_model
|
126
|
+
# @raise [ArgumentError] if +color_model+ parameter is incorrect
|
127
|
+
# @return [TERM] a TERM representation of the RGB
|
128
|
+
def to_term(color_model = 256)
|
129
|
+
term = case color_model
|
130
|
+
when 256 then PryTheme::RGB::TABLE.index(@value)
|
131
|
+
when 16 then PryTheme::RGB::SYSTEM.index(@value)
|
132
|
+
when 8 then PryTheme::RGB::LINUX.index(@value)
|
133
|
+
else raise ArgumentError,
|
134
|
+
"invalid value for PryTheme::HEX#to_term(): #{ @value }"
|
135
|
+
end
|
136
|
+
term = find_among_term_colors(term, color_model) if term.nil?
|
137
|
+
PryTheme::TERM.new(term, color_model)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Converts the RGB to a HEX colour equivalent.
|
141
|
+
# @return [HEX] a HEX representation of the RGB
|
142
|
+
def to_hex
|
143
|
+
PryTheme::HEX.new("#%02x%02x%02x" % @value)
|
144
|
+
end
|
145
|
+
|
146
|
+
# @example
|
147
|
+
# RGB.new([0, 12, 255]).to_s #=> "0, 12, 255"
|
148
|
+
# @return [String]
|
149
|
+
def to_s
|
150
|
+
@value.join(', ')
|
151
|
+
end
|
152
|
+
|
153
|
+
# @example
|
154
|
+
# RGB.new([0, 12, 255]).to_s #=> [0, 12, 255]
|
155
|
+
# @return [Array<Integer>]
|
156
|
+
def to_a
|
157
|
+
@value
|
158
|
+
end
|
159
|
+
|
160
|
+
# @example
|
161
|
+
# RGB.new([0, 0, 0]).to_css #=> 'rgb(0, 0, 0)'
|
162
|
+
# @return [String]
|
163
|
+
def to_css
|
164
|
+
"rgb(#{ to_s })"
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
# Checks whether the +ary+ has correct number of elements and these elements
|
170
|
+
# are valid RGB numbers.
|
171
|
+
#
|
172
|
+
# @param [Array<Integer>] ary
|
173
|
+
# @raise [ArgumentError] if the +ary+ is invalid
|
174
|
+
# @return [void]
|
175
|
+
def validate_array(ary)
|
176
|
+
correct_size = ary.size.equal?(3)
|
177
|
+
correct_vals = ary.all?{ |val| val.is_a?(Fixnum) && val.between?(0, 255) }
|
178
|
+
return true if correct_size && correct_vals
|
179
|
+
raise ArgumentError,
|
180
|
+
%|invalid value for PryTheme::RGB#validate_array(): "#{ ary }"|
|
181
|
+
end
|
182
|
+
|
183
|
+
# Approximates the given +byte+ to a terminal colour value within range of
|
184
|
+
# 256 colours.
|
185
|
+
#
|
186
|
+
# @param [Integer] byte a number between 0 and 255
|
187
|
+
# @return [Integer] approximated number
|
188
|
+
def nearest_term_256(byte)
|
189
|
+
for i in 0..4
|
190
|
+
lower, upper = BYTEPOINTS_256[i], BYTEPOINTS_256[i + 1]
|
191
|
+
next unless byte.between?(lower, upper)
|
192
|
+
|
193
|
+
distance_from_lower = (lower - byte).abs
|
194
|
+
distance_from_upper = (upper - byte).abs
|
195
|
+
closest = distance_from_lower < distance_from_upper ? lower : upper
|
196
|
+
end
|
197
|
+
closest
|
198
|
+
end
|
199
|
+
|
200
|
+
# The same as {#nearest_term_256}, but returns a number beteen 0 and 15.
|
201
|
+
#
|
202
|
+
# @note Oh, come on. At least it works!
|
203
|
+
# @todo use more realistic algorithm.
|
204
|
+
def nearest_term_16(byte)
|
205
|
+
byte / 16
|
206
|
+
end
|
207
|
+
|
208
|
+
# The same as {#nearest_term_256}, but returns a number beteen 0 and 7.
|
209
|
+
#
|
210
|
+
# @note Oh, come on. At least it works!
|
211
|
+
# @todo use more realistic algorithm.
|
212
|
+
def nearest_term_8(byte)
|
213
|
+
byte / 32
|
214
|
+
end
|
215
|
+
|
216
|
+
# Finds an approximated +term+ colour among the colour numbers within the
|
217
|
+
# given +color_model+.
|
218
|
+
#
|
219
|
+
# @param [Integer] term a colour to be approximated
|
220
|
+
# @param [Integer] color_model possible values {#to_term}
|
221
|
+
# @return [Integer] approximated number, which fits in range of color_model
|
222
|
+
def find_among_term_colors(term, color_model)
|
223
|
+
rgb = @value.map { |byte| nearest_term_256(byte) }
|
224
|
+
term = PryTheme::RGB::TABLE.index(rgb)
|
225
|
+
approximate(term, color_model)
|
226
|
+
end
|
227
|
+
|
228
|
+
# Approximates +term+ in correspondence with +color_model+
|
229
|
+
#
|
230
|
+
# @see #nearest_term_16
|
231
|
+
# @see #nearest_term_8
|
232
|
+
# @param [Integer] term a colour to be approximated
|
233
|
+
# @param [Integer] color_model possible values {#to_term}
|
234
|
+
# @return [Integer] approximated number, which fits in range of color_model
|
235
|
+
def approximate(term, color_model)
|
236
|
+
needs_approximation = (term > color_model - 1)
|
18
237
|
|
19
|
-
|
20
|
-
|
238
|
+
if needs_approximation
|
239
|
+
case color_model
|
240
|
+
when 16 then nearest_term_16(term)
|
241
|
+
when 8 then nearest_term_8(term)
|
242
|
+
end
|
243
|
+
else
|
244
|
+
term
|
245
|
+
end
|
21
246
|
end
|
22
247
|
|
23
248
|
end
|