kolor 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 88da60fa7cd1a6902ce9fb10e02e302c7aad67a9eed4795951dae6804f82a4f3
4
+ data.tar.gz: edfd12747056bff1941ffdd2cc6f8c2cf88b5e6030b6a46e85fbee3d5d95a632
5
+ SHA512:
6
+ metadata.gz: c5876e47d82fb9a977aeb08d005a2a8b4aece912912f9214ae749f05d4f295890c2be4e1150d783a36b64be6a93b0458148a3c2b43ad9e48a0edd9fed88796f8
7
+ data.tar.gz: 6a809ff99c76a57ffb7cad178d9b5ead628e8acd12e6cf6a1b6a6f6e6adbf0b6ef0cd722c6f97d69567ddcbf08170dd9d9a31de9602d6e6a6bc4e9f5c3f710a9
data/LICENSE ADDED
@@ -0,0 +1,8 @@
1
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
2
+
3
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
4
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
5
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
6
+ 4. Redistributions of any form whatsoever must retain the following acknowledgment: 'This product includes software developed by the Łasačka (https://github.com/lasaczka/) saikinmirai@gmail.com'
7
+
8
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/bin/kolor ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/kolor/cli'
5
+
6
+ Kolor::CLI.new(ARGV).run
data/lib/kolor/cli.rb ADDED
@@ -0,0 +1,310 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../kolor'
4
+ require_relative 'internal/config'
5
+ require 'optparse'
6
+
7
+ module Kolor
8
+ ##
9
+ # Kolor::CLI provides a command-line interface for the Kolor library.
10
+ #
11
+ # It supports:
12
+ # - Foreground and background colors
13
+ # - Text styles (bold, underline, etc.)
14
+ # - Predefined themes (via kolor/extra)
15
+ # - RGB and hex color input
16
+ # - Gradients and rainbow effects
17
+ # - Utility commands like listing options or showing a demo
18
+ #
19
+ # Input can be passed as arguments or piped via stdin.
20
+ # Output is automatically colorized unless redirected, in which case colors are disabled unless `KOLOR_FORCE` is set.
21
+ #
22
+ # @example Basic usage
23
+ # kolor --red "Hello"
24
+ #
25
+ # @example Piped input
26
+ # echo "Hello" | kolor --green --bold
27
+ #
28
+ # @example Theme usage (requires kolor/extra)
29
+ # kolor --success "Done!"
30
+ #
31
+ # @example List available styles
32
+ # kolor --list-styles
33
+ #
34
+ # @example Show demo
35
+ # kolor --demo
36
+ class CLI
37
+ ##
38
+ # Initializes the CLI with given arguments.
39
+ #
40
+ # @param args [Array<String>] command-line arguments (defaults to ARGV)
41
+ def initialize(args = ARGV)
42
+ @args = args
43
+ @options = {}
44
+ end
45
+
46
+ ##
47
+ # Runs the CLI command.
48
+ #
49
+ # Loads config, parses options, and dispatches to appropriate handler.
50
+ #
51
+ # @return [void]
52
+ def run
53
+ Kolor::Config.init if extra_available?
54
+ parse_options
55
+
56
+ if @options[:list_colors]
57
+ list_colors
58
+ elsif @options[:list_styles]
59
+ list_styles
60
+ elsif @options[:list_themes]
61
+ list_themes
62
+ elsif @options[:demo]
63
+ show_demo
64
+ elsif @options[:version]
65
+ puts "Kolor #{Kolor::VERSION}"
66
+ elsif @options[:help]
67
+ puts @option_parser
68
+ else
69
+ colorize_text
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ ##
76
+ # Parses CLI options using OptionParser.
77
+ #
78
+ # Populates @options hash with parsed flags and values.
79
+ #
80
+ # @return [void]
81
+ def parse_options
82
+ @option_parser = OptionParser.new do |opts|
83
+ opts.banner = "Usage: kolor [options] TEXT"
84
+ opts.separator ""
85
+ opts.separator "Examples:"
86
+ opts.separator " kolor --red 'Hello World'"
87
+ opts.separator " kolor --green --bold 'Success!'"
88
+ opts.separator " echo 'Hello' | kolor --red"
89
+ opts.separator " kolor --success 'Done!' (requires kolor/extra)"
90
+ opts.separator ""
91
+ opts.separator "Options:"
92
+
93
+ Kolor::Enum::Foreground.keys.each do |color|
94
+ opts.on("--#{color}", "Apply #{color} foreground") { @options[:foreground] = color }
95
+ end
96
+
97
+ Kolor::Enum::Background.keys.each do |color|
98
+ opts.on("--on-#{color}", "Apply #{color} background") { @options[:background] = color }
99
+ end
100
+
101
+ Kolor::Enum::Style.keys.reject { |s| s == :clear }.each do |style|
102
+ opts.on("--#{style}", "Apply #{style} style") do
103
+ @options[:styles] ||= []
104
+ @options[:styles] << style
105
+ end
106
+ end
107
+
108
+ opts.on("--success", "Apply success theme (green + bold)") do
109
+ @options[:theme] = :success
110
+ require_extra
111
+ end
112
+
113
+ opts.on("--error", "Apply error theme (white on red + bold)") do
114
+ @options[:theme] = :error
115
+ require_extra
116
+ end
117
+
118
+ opts.on("--warning", "Apply warning theme (yellow + bold)") do
119
+ @options[:theme] = :warning
120
+ require_extra
121
+ end
122
+
123
+ opts.on("--info", "Apply info theme (cyan)") do
124
+ @options[:theme] = :info
125
+ require_extra
126
+ end
127
+
128
+ opts.on("--debug", "Apply debug theme (magenta)") do
129
+ @options[:theme] = :debug
130
+ require_extra
131
+ end
132
+
133
+ opts.on("--rgb R,G,B", Array, "Apply RGB color (e.g., 255,0,0)") do |rgb|
134
+ require_extra
135
+ @options[:rgb] = rgb.map(&:to_i)
136
+ end
137
+
138
+ opts.on("--with_hex COLOR", "Apply with_hex color (e.g., FF0000)") do |hex|
139
+ require_extra
140
+ @options[:with_hex] = hex
141
+ end
142
+
143
+ opts.on("--gradient START,END", Array, "Apply gradient (e.g., red,blue)") do |colors|
144
+ require_extra
145
+ @options[:gradient] = colors.map(&:to_sym)
146
+ end
147
+
148
+ opts.on("--rainbow", "Apply rainbow effect") do
149
+ require_extra
150
+ @options[:rainbow] = true
151
+ end
152
+
153
+ opts.on("--list-colors", "List available colors") { @options[:list_colors] = true }
154
+ opts.on("--list-styles", "List available styles") { @options[:list_styles] = true }
155
+ opts.on("--list-themes", "List available themes") { @options[:list_themes] = true }
156
+ opts.on("--demo", "Show color demonstration") { @options[:demo] = true }
157
+ opts.on("--no-color", "Disable colors") { Kolor.disable! }
158
+ opts.on("-v", "--version", "Show version") { @options[:version] = true }
159
+ opts.on("-h", "--help", "Show this help") { @options[:help] = true }
160
+ end
161
+
162
+ @option_parser.parse!(@args)
163
+ end
164
+
165
+ ##
166
+ # Requires kolor/extra and exits with error if not available.
167
+ #
168
+ # @return [void]
169
+ def require_extra
170
+ require_relative 'extra'
171
+ rescue LoadError
172
+ puts "Error: kolor/extra is required for this feature"
173
+ exit 1
174
+ end
175
+
176
+ ##
177
+ # Checks if kolor/extra is available.
178
+ #
179
+ # @return [Boolean]
180
+ def extra_available?
181
+ require_relative 'extra'
182
+ true
183
+ rescue LoadError
184
+ false
185
+ end
186
+
187
+ ##
188
+ # Applies selected colors/styles/themes to input text and prints result.
189
+ #
190
+ # @return [void]
191
+ def colorize_text
192
+ text = if @args.empty?
193
+ if $stdin.tty?
194
+ puts "Error: No text provided"
195
+ puts @option_parser
196
+ exit 1
197
+ else
198
+ $stdin.read.chomp
199
+ end
200
+ else
201
+ @args.join(' ')
202
+ end
203
+
204
+ Kolor.disable! if !$stdout.tty? && Kolor.enabled? && !ENV['KOLOR_FORCE']
205
+
206
+ if @options[:gradient]
207
+ text = text.gradient(*@options[:gradient])
208
+ elsif @options[:rainbow]
209
+ text = text.rainbow
210
+ elsif @options[:theme]
211
+ text = text.public_send(@options[:theme])
212
+ else
213
+ text = text.rgb(*@options[:rgb]) if @options[:rgb]&.size == 3
214
+ text = text.with_hex(@options[:with_hex]) if @options[:with_hex]
215
+ text = text.public_send(@options[:foreground]) if @options[:foreground]
216
+ text = text.public_send("on_#{@options[:background]}") if @options[:background]
217
+ @options[:styles]&.each { |style| text = text.public_send(style) }
218
+ end
219
+
220
+ puts text
221
+ end
222
+
223
+ ##
224
+ # Lists available foreground colors.
225
+ #
226
+ # @return [void]
227
+ def list_colors
228
+ puts "Available colors:\n\n"
229
+ Kolor::Enum::Foreground.keys.each do |color|
230
+ puts " #{color.to_s.ljust(10)} - " + "Sample text".public_send(color)
231
+ end
232
+ end
233
+
234
+ ##
235
+ # Lists available text styles.
236
+ #
237
+ # @return [void]
238
+ def list_styles
239
+ puts "Available styles:\n\n"
240
+ Kolor::Enum::Style.keys.reject { |s| s == :clear }.each do |style|
241
+ puts " #{style.to_s.ljust(10)} - " + "Sample text".public_send(style)
242
+ end
243
+ end
244
+
245
+ ##
246
+ # Lists available themes (requires kolor/extra).
247
+ #
248
+ # @return [void]
249
+ def list_themes
250
+ require_extra
251
+ puts "Available themes:\n\n"
252
+ Kolor::Extra.themes.each do |theme|
253
+ config = Kolor::Extra.get_theme(theme)
254
+ description = []
255
+ description << config[:foreground].to_s if config[:foreground]
256
+ description << "on_#{config[:background]}" if config[:background]
257
+ description += config[:styles].map(&:to_s)
258
+ puts " #{theme.to_s.ljust(10)} - " + "Sample text".public_send(theme) +
259
+ " (#{description.join(', ')})"
260
+ end
261
+ end
262
+
263
+ ##
264
+ # Displays a full demo of colors, backgrounds, styles, and themes.
265
+ #
266
+ # @return [void]
267
+ def show_demo
268
+ puts "=== Kolor Demo ==="
269
+ puts ""
270
+
271
+ puts "Basic colors:"
272
+ Kolor::Enum::Foreground.keys.each do |color|
273
+ print "#{color}: ".ljust(12)
274
+ puts "The quick brown fox".public_send(color)
275
+ end
276
+ puts ""
277
+
278
+ puts "Background colors:"
279
+ Kolor::Enum::Background.keys.each do |color|
280
+ print "on_#{color}: ".ljust(12)
281
+ puts "The quick brown fox".public_send("on_#{color}")
282
+ end
283
+ puts ""
284
+
285
+ puts "Styles:"
286
+ Kolor::Enum::Style.keys.reject { |s| s == :clear }.each do |style|
287
+ print "#{style}: ".ljust(12)
288
+ puts "The quick brown fox".public_send(style)
289
+ end
290
+ puts ""
291
+
292
+ puts "Combinations:"
293
+ puts "Red on white: " + "The quick brown fox".red.on_white
294
+ puts "Bold green: " + "The quick brown fox".green.bold
295
+ puts "Complex: " + "The quick brown fox".red.on_blue.bold.underline
296
+ puts ""
297
+
298
+ if extra_available?
299
+ puts "Themes:"
300
+ Kolor::Extra.themes.each do |theme|
301
+ puts "#{theme}: ".ljust(12) + "The quick brown fox".public_send(theme)
302
+ end
303
+ puts ""
304
+
305
+ puts "Rainbow:"
306
+ puts "The quick brown fox jumps over the lazy dog".rainbow
307
+ end
308
+ end
309
+ end
310
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Kolor::Enum::Background defines ANSI background color codes.
4
+ # Each entry maps a symbolic name to its corresponding ANSI value.
5
+ class Kolor::Enum::Background < Kolor::Enum
6
+ type Integer
7
+
8
+ # @return [Kolor::Enum::Background] black background (ANSI 40)
9
+ entry :black, 40
10
+
11
+ # @return [Kolor::Enum::Background] red background (ANSI 41)
12
+ entry :red, 41
13
+
14
+ # @return [Kolor::Enum::Background] green background (ANSI 42)
15
+ entry :green, 42
16
+
17
+ # @return [Kolor::Enum::Background] yellow background (ANSI 43)
18
+ entry :yellow, 43
19
+
20
+ # @return [Kolor::Enum::Background] blue background (ANSI 44)
21
+ entry :blue, 44
22
+
23
+ # @return [Kolor::Enum::Background] magenta background (ANSI 45)
24
+ entry :magenta, 45
25
+
26
+ # @return [Kolor::Enum::Background] cyan background (ANSI 46)
27
+ entry :cyan, 46
28
+
29
+ # @return [Kolor::Enum::Background] white background (ANSI 47)
30
+ entry :white, 47
31
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Kolor::Enum::Foreground defines ANSI foreground color codes.
4
+ # Each entry maps a symbolic name to its corresponding ANSI value.
5
+ class Kolor::Enum::Foreground < Kolor::Enum
6
+ type Integer
7
+
8
+ # @return [Kolor::Enum::Foreground] black foreground (ANSI 30)
9
+ entry :black, 30
10
+
11
+ # @return [Kolor::Enum::Foreground] red foreground (ANSI 31)
12
+ entry :red, 31
13
+
14
+ # @return [Kolor::Enum::Foreground] green foreground (ANSI 32)
15
+ entry :green, 32
16
+
17
+ # @return [Kolor::Enum::Foreground] yellow foreground (ANSI 33)
18
+ entry :yellow, 33
19
+
20
+ # @return [Kolor::Enum::Foreground] blue foreground (ANSI 34)
21
+ entry :blue, 34
22
+
23
+ # @return [Kolor::Enum::Foreground] magenta foreground (ANSI 35)
24
+ entry :magenta, 35
25
+
26
+ # @return [Kolor::Enum::Foreground] cyan foreground (ANSI 36)
27
+ entry :cyan, 36
28
+
29
+ # @return [Kolor::Enum::Foreground] white foreground (ANSI 37)
30
+ entry :white, 37
31
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Kolor::Enum::Style defines ANSI text style codes.
4
+ # These control formatting like bold, underline, and reversed text.
5
+ class Kolor::Enum::Style < Kolor::Enum
6
+ type Integer
7
+
8
+ # @return [Kolor::Enum::Style] reset all styles (ANSI 0)
9
+ entry :clear, 0
10
+
11
+ # @return [Kolor::Enum::Style] bold text (ANSI 1)
12
+ entry :bold, 1
13
+
14
+ # @return [Kolor::Enum::Style] underlined text (ANSI 4)
15
+ entry :underline, 4
16
+
17
+ # @return [Kolor::Enum::Style] reversed foreground/background (ANSI 7)
18
+ entry :reversed, 7
19
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Kolor::Enum::Theme defines named color themes for terminal output.
4
+ # Each theme is a structured hash containing:
5
+ # - foreground: the main text color
6
+ # - background: optional background color
7
+ # - styles: optional array of text styles (e.g. :bold, :underline)
8
+ #
9
+ # These themes are used to apply consistent formatting across messages,
10
+ # and can be extended or overridden via Kolor::Extra.theme.
11
+ #
12
+ # @example
13
+ # Kolor::Enum::Theme[:success].value
14
+ # # => { foreground: :green, background: nil, styles: [:bold] }
15
+ class Kolor::Enum::Theme < Kolor::Enum
16
+ type Hash
17
+
18
+ # @return [Kolor::Enum::Theme] green bold text for success messages
19
+ entry :success, { foreground: :green, background: nil, styles: [:bold] }
20
+
21
+ # @return [Kolor::Enum::Theme] white text on red background for errors
22
+ entry :error, { foreground: :white, background: :red, styles: [:bold] }
23
+
24
+ # @return [Kolor::Enum::Theme] yellow bold text for warnings
25
+ entry :warning, { foreground: :yellow, background: nil, styles: [:bold] }
26
+
27
+ # @return [Kolor::Enum::Theme] cyan text for informational messages
28
+ entry :info, { foreground: :cyan, background: nil, styles: [] }
29
+
30
+ # @return [Kolor::Enum::Theme] magenta text for debugging output
31
+ entry :debug, { foreground: :magenta, background: nil, styles: [] }
32
+ end