ansi 1.2.5 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,204 +1,130 @@
1
- require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /win32/
2
-
3
1
  module ANSI
4
2
 
5
- # deprecate
6
- SUPPORTED = true
3
+ require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /(win32|w32)/
4
+
5
+ require 'ansi/constants'
6
+
7
+ # Global variialbe can be used to prevent ANSI codes
8
+ # from being used in ANSI's methods that do so to string.
9
+ #
10
+ # NOTE: This has no effect of methods that return ANSI codes.
11
+ $ansi = true
7
12
 
8
- # = ANSI Codes
13
+ # ANSI Codes
9
14
  #
10
15
  # Ansi::Code module makes it very easy to use ANSI codes.
11
16
  # These are esspecially nice for beautifying shell output.
12
17
  #
13
- # include Ansi::Code
14
- #
15
- # red + "Hello" + blue + "World"
18
+ # Ansi::Code.red + "Hello" + Ansi::Code.blue + "World"
16
19
  # => "\e[31mHello\e[34mWorld"
17
20
  #
18
- # red { "Hello" } + blue { "World" }
21
+ # Ansi::Code.red{ "Hello" } + Ansi::Code.blue{ "World" }
19
22
  # => "\e[31mHello\e[0m\e[34mWorld\e[0m"
20
23
  #
21
- # == Supported ANSI Commands
22
- #
23
- # The following is a list of supported display codes.
24
- #
25
- # save
26
- # restore
27
- # clear_screen
28
- # cls # synonym for :clear_screen
29
- # clear_line
30
- # clr # synonym for :clear_line
31
- # move
32
- # up
33
- # down
34
- # left
35
- # right
36
- #
37
- # The following is a list of supported "style" codes.
38
- #
39
- # clear
40
- # reset # synonym for :clear
41
- # bold
42
- # dark
43
- # italic # not widely implemented
44
- # underline
45
- # underscore # synonym for :underline
46
- # blink
47
- # rapid_blink # not widely implemented
48
- # negative # no reverse because of String#reverse
49
- # concealed
50
- # strikethrough # not widely implemented
51
- #
52
- # The following is a list of supported color codes.
53
- #
54
- # black
55
- # red
56
- # green
57
- # yellow
58
- # blue
59
- # magenta
60
- # cyan
61
- # white
62
- #
63
- # on_black
64
- # on_red
65
- # on_green
66
- # on_yellow
67
- # on_blue
68
- # on_magenta
69
- # on_cyan
70
- # on_white
24
+ # IMPORTANT! Do not mixin Ansi::Code, instead use {ANSI::Mixin}.
71
25
  #
72
- # In addition there are color combinations like +red_on_white+.
73
- #
74
- # == Acknowledgement
75
- #
76
- # This library is a partial adaptation of ANSIColor by Florian Frank.
77
- #
78
- # ANSIColor Copyright (c) 2002 Florian Frank
79
- #
80
- # == Developer's Notes
81
- #
82
- # TODO: Any ANSI codes left to add? Modes?
26
+ # See {ANSI::Code::CHART} for list of all supported codes.
83
27
  #
28
+ #--
84
29
  # TODO: up, down, right, left, etc could have yielding methods too?
30
+ #++
85
31
 
86
32
  module Code
87
33
  extend self
88
34
 
89
- CLEAR = "\e[0m"
90
- RESET = "\e[0m"
91
- BOLD = "\e[1m"
92
- DARK = "\e[2m"
93
- ITALIC = "\e[3m" # not widely implemented
94
- UNDERLINE = "\e[4m"
95
- UNDERSCORE = "\e[4m"
96
- BLINK = "\e[5m"
97
- RAPID = "\e[6m" # not widely implemented
98
- REVERSE = "\e[7m"
99
- NEGATIVE = "\e[7m" # alternate to reverse because of String#reverse
100
- CONCEALED = "\e[8m"
101
- STRIKE = "\e[9m" # not widely implemented
102
-
103
- BLACK = "\e[30m"
104
- RED = "\e[31m"
105
- GREEN = "\e[32m"
106
- YELLOW = "\e[33m"
107
- BLUE = "\e[34m"
108
- MAGENTA = "\e[35m"
109
- CYAN = "\e[36m"
110
- WHITE = "\e[37m"
111
-
112
- ON_BLACK = "\e[40m"
113
- ON_RED = "\e[41m"
114
- ON_GREEN = "\e[42m"
115
- ON_YELLOW = "\e[43m"
116
- ON_BLUE = "\e[44m"
117
- ON_MAGENTA = "\e[45m"
118
- ON_CYAN = "\e[46m"
119
- ON_WHITE = "\e[47m"
120
-
121
- # Save current cursor positon.
122
- SAVE = "\e[s"
123
-
124
- # Restore saved cursor positon.
125
- RESTORE = "\e[u"
126
-
127
- # Clear to the end of the current line.
128
- CLEAR_LINE = "\e[K"
129
-
130
- # Clear to the end of the current line.
131
- CLR = "\e[K"
132
-
133
- # Clear the screen and move cursor to home.
134
- CLEAR_SCREEN = "\e[2J"
135
-
136
- # Clear the screen and move cursor to home.
137
- CLS = "\e[2J"
35
+ # include ANSI Constants
36
+ include Constants
37
+
38
+ # Regexp for matching most ANSI codes.
39
+ PATTERN = /\e\[(\d+)m/
138
40
 
41
+ # ANSI clear code.
42
+ ENDCODE = "\e[0m"
43
+
44
+ # List of primary styles.
139
45
  def self.styles
140
46
  %w{bold dark italic underline underscore blink rapid reverse negative concealed strike}
141
47
  end
142
48
 
49
+ # List of primary colors.
50
+ def self.colors
51
+ %w{black red green yellow blue magenta cyan white}
52
+ end
53
+
54
+ =begin
143
55
  styles.each do |style|
144
56
  module_eval <<-END, __FILE__, __LINE__
145
57
  def #{style}(string=nil)
146
58
  if string
59
+ return string unless $ansi
147
60
  #warn "use ANSI block notation for future versions"
148
- return "\#{#{style.upcase}}\#{string}\#{CLEAR}"
61
+ return "\#{#{style.upcase}}\#{string}\#{ENDCODE}"
149
62
  end
150
63
  if block_given?
151
- return "\#{#{style.upcase}}\#{yield}\#{CLEAR}"
64
+ return yield unless $ansi
65
+ return "\#{#{style.upcase}}\#{yield}\#{ENDCODE}"
152
66
  end
153
67
  #{style.upcase}
154
68
  end
155
69
  END
156
70
  end
71
+ =end
157
72
 
158
- def self.colors
159
- %w{black red green yellow blue magenta cyan white}
160
- end
161
-
73
+ =begin
162
74
  # Dynamically create color methods.
163
75
 
164
76
  colors.each do |color|
165
77
  module_eval <<-END, __FILE__, __LINE__
166
78
  def #{color}(string=nil)
167
79
  if string
80
+ return string unless $ansi
168
81
  #warn "use ANSI block notation for future versions"
169
- return "\#{#{color.upcase}}\#{string}\#{CLEAR}"
82
+ return "\#{#{color.upcase}}\#{string}\#{ENDCODE}"
170
83
  end
171
84
  if block_given?
172
- return "\#{#{color.upcase}}\#{yield}\#{CLEAR}"
85
+ return yield unless $ansi
86
+ return "\#{#{color.upcase}}\#{yield}\#{ENDCODE}"
173
87
  end
174
88
  #{color.upcase}
175
89
  end
176
90
 
177
91
  def on_#{color}(string=nil)
178
92
  if string
93
+ return string unless $ansi
179
94
  #warn "use ANSI block notation for future versions"
180
- return "\#{ON_#{color.upcase}}\#{string}\#{CLEAR}"
95
+ return "\#{ON_#{color.upcase}}\#{string}\#{ENDCODE}"
181
96
  end
182
97
  if block_given?
183
- return "\#{ON_#{color.upcase}}\#{yield}\#{CLEAR}"
98
+ return yield unless $ansi
99
+ return "\#{ON_#{color.upcase}}\#{yield}\#{ENDCODE}"
184
100
  end
185
101
  ON_#{color.upcase}
186
102
  end
187
103
  END
188
104
  end
105
+ =end
189
106
 
190
- # Dynamically create color on color methods.
107
+ # Return ANSI code given a list of symbolic names.
108
+ def [](*codes)
109
+ code(*codes)
110
+ end
191
111
 
112
+ # Dynamically create color on color methods.
113
+ #
114
+ # @deprecated
115
+ #
192
116
  colors.each do |color|
193
117
  colors.each do |on_color|
194
118
  module_eval <<-END, __FILE__, __LINE__
195
119
  def #{color}_on_#{on_color}(string=nil)
196
120
  if string
121
+ return string unless $ansi
197
122
  #warn "use ANSI block notation for future versions"
198
- return #{color.upcase} + ON_#{color.upcase} + string + CLEAR
123
+ return #{color.upcase} + ON_#{color.upcase} + string + ENDCODE
199
124
  end
200
125
  if block_given?
201
- #{color.upcase} + ON_#{on_color.upcase} + yield.to_s + CLEAR
126
+ return yield unless $ansi
127
+ #{color.upcase} + ON_#{on_color.upcase} + yield.to_s + ENDCODE
202
128
  else
203
129
  #{color.upcase} + ON_#{on_color.upcase}
204
130
  end
@@ -207,45 +133,35 @@ module ANSI
207
133
  end
208
134
  end
209
135
 
210
- # Clear code.
211
- def clear
212
- CLEAR
213
- end
214
-
215
- # Reset code.
216
- def reset
217
- RESET
218
- end
219
-
220
- # Save current cursor positon.
221
- def save
222
- SAVE
223
- end
136
+ # Use method missing to dispatch ANSI code methods.
137
+ def method_missing(code, *args, &blk)
138
+ esc = nil
224
139
 
225
- # Restore saved cursor positon.
226
- def restore
227
- RESTORE
228
- end
229
-
230
- # Clear to the end of the current line.
231
- def clear_line
232
- CLEAR_LINE
233
- end
234
-
235
- # Clear to the end of the current line.
236
- def clr
237
- CLR
238
- end
140
+ if CHART.key?(code)
141
+ esc = "\e[#{CHART[code]}m"
142
+ elsif SPECIAL_CHART.key?(code)
143
+ esc = SPECIAL_CHART[code]
144
+ end
239
145
 
240
- # Clear the screen and move cursor to home.
241
- def clear_screen
242
- CLEAR_SCREEN
146
+ if esc
147
+ if string = args.first
148
+ return string unless $ansi
149
+ #warn "use ANSI block notation for future versions"
150
+ return "#{esc}#{string}#{ENDCODE}"
151
+ end
152
+ if block_given?
153
+ return yield unless $ansi
154
+ return "#{esc}#{yield}#{ENDCODE}"
155
+ end
156
+ esc
157
+ else
158
+ super(code, *args, &blk)
159
+ end
243
160
  end
244
161
 
245
- # Clear the screen and move cursor to home.
246
- def cls
247
- CLS
248
- end
162
+ # TODO: How to deal with position codes when $ansi is false?
163
+ # Should we reaise an error or just not push the codes?
164
+ # For now, we will leave this it as is.
249
165
 
250
166
  # Like +move+ but returns to original positon after
251
167
  # yielding the block.
@@ -292,127 +208,140 @@ module ANSI
292
208
  # "\e[#;#R"
293
209
  #end
294
210
 
295
- # Apply ansi codes to block yield.
211
+ # Apply ANSI codes to a first argument or block value.
296
212
  #
297
- # style(:red, :on_white){ "Valentine" }
213
+ # @example
214
+ # ansi("Valentine", :red, :on_white)
298
215
  #
299
- def style(*codes) #:yield:
300
- s = ""
301
- codes.each do |code|
302
- s << "\e[#{TABLE[code]}m"
303
- end
304
- s << yield.to_s
305
- s << CLEAR
306
- end
307
-
308
- # Alternate term for #style.
309
- alias_method :color, :style
310
-
216
+ # @example
217
+ # ansi(:red, :on_white){ "Valentine" }
311
218
  #
312
- def unstyle #:yield:
219
+ # @return [String]
220
+ # String wrapped ANSI code.
221
+ #
222
+ def ansi(*codes) #:yield:
313
223
  if block_given?
314
- yield.gsub(PATTERN, '')
224
+ string = yield.to_s
315
225
  else
316
- ''
226
+ string = codes.shift.to_s
317
227
  end
228
+
229
+ return string unless $ansi
230
+
231
+ code(*codes) + string + ENDCODE
318
232
  end
319
233
 
234
+ # Remove ANSI codes from string or block value.
320
235
  #
321
- alias_method :uncolor, :unstyle
322
-
323
- # DEPRECATE: This old term will be deprecated.
324
- def uncolered(string=nil)
325
- warn "ansi: use #uncolor or #unansi for future version"
236
+ # @param [String]
237
+ # String from which to remove ANSI codes.
238
+ #
239
+ # @return [String]
240
+ # String wrapped ANSI code.
241
+ #
242
+ #--
243
+ # TODO: Allow selective removal using *codes argument?
244
+ #++
245
+ def unansi(string=nil) #:yield:
326
246
  if block_given?
327
- yield.gsub(PATTERN, '')
328
- elsif string
329
- string.gsub(PATTERN, '')
247
+ string = yield.to_s
330
248
  else
331
- ''
249
+ string = string.to_s
332
250
  end
251
+ string.gsub(PATTERN, '')
333
252
  end
334
253
 
335
- # This method is just like #style, except it takes a string
336
- # rather than a block. The primary purpose of this method
337
- # is to speed up the String#ansi call.
254
+ # Alias for #ansi method.
338
255
  #
339
- # ansi("Valentine", :red, :on_white)
256
+ # @deprecated
257
+ # Here for backward scompatibility.
258
+ alias_method :style, :ansi
259
+
260
+ # Alias for #unansi method.
261
+ #
262
+ # @deprecated
263
+ # Here for backwards compatibility.
264
+ alias_method :unstyle, :unansi
265
+
266
+ # Alternate term for #ansi.
267
+ #
268
+ # @deprecated
269
+ # May change in future definition.
270
+ alias_method :color, :ansi
271
+
272
+ # Alias for unansi.
340
273
  #
341
- def ansi(string, *codes)
342
- s = ""
274
+ # @deprecated
275
+ # May change in future definition.
276
+ alias_method :uncolor, :unansi
277
+
278
+ # Look-up code from chart, or if Integer simply pass through.
279
+ # Also resolves :random and :on_random.
280
+ #
281
+ # @param codes [Array<Symbol,Integer]
282
+ # Symbols or integers to covnert to ANSI code.
283
+ #
284
+ # @return [String] ANSI code
285
+ def code(*codes)
286
+ list = []
343
287
  codes.each do |code|
344
- s << "\e[#{TABLE[code]}m"
288
+ list << \
289
+ case code
290
+ when Integer
291
+ code
292
+ when Array
293
+ rgb(*code)
294
+ when :random
295
+ random
296
+ when :on_random
297
+ random(true)
298
+ else
299
+ CHART[code.to_sym]
300
+ end
345
301
  end
346
- s << string
347
- s << CLEAR
302
+ "\e[" + (list * ";") + "m"
348
303
  end
349
304
 
350
- # Remove ansi codes from +string+. This method is like unstyle,
351
- # but takes a string rather than a block.
352
- def unansi(string)
353
- string.gsub(PATTERN, '')
305
+ # Provides a random primary ANSI color.
306
+ #
307
+ # @param background [Boolean]
308
+ # Use `true` for background color, otherwise foreground color.
309
+ #
310
+ # @return [Integer] ANSI color number
311
+ def random(background=false)
312
+ (background ? 40 : 30) + rand(8)
354
313
  end
355
314
 
356
- # Regexp for matching style and color codes.
357
- PATTERN = /\e\[([34][0-7]|[0-9])m/
358
-
359
- # Table of style and color codes.
360
- TABLE = {
361
- :clear => 0,
362
- :reset => 0,
363
- :bold => 1,
364
- :dark => 2,
365
- :italic => 3,
366
- :underline => 4,
367
- :underscore => 4,
368
- :blink => 5,
369
- :rapid => 6,
370
- :reverse => 7,
371
- :negative => 7,
372
- :concealed => 8,
373
- :strike => 9,
374
- :black => 30,
375
- :red => 31,
376
- :green => 32,
377
- :yellow => 33,
378
- :blue => 34,
379
- :magenta => 35,
380
- :cyan => 36,
381
- :white => 37,
382
- :on_black => 40,
383
- :on_red => 41,
384
- :on_green => 42,
385
- :on_yellow => 43,
386
- :on_blue => 44,
387
- :on_magenta => 45,
388
- :on_cyan => 46,
389
- :on_white => 47
390
- }
391
- end
315
+ # Creates an xterm-256 color from rgb value.
316
+ #
317
+ # @param background [Boolean]
318
+ # Use `true` for background color, otherwise foreground color.
319
+ #
320
+ def rgb(red, green, blue, background=false)
321
+ "#{background ? 48 : 38};5;#{rgb_value(red, green, blue)}"
322
+ end
392
323
 
393
- extend Code
394
- end
324
+ # Creates an xterm-256 color from a CSS-style color string.
325
+ def hex(string, background=false)
326
+ string.tr!('#','')
327
+ x = (string.size == 6 ? 2 : 1)
328
+ r, g, b = [0,1,2].map{ |i| string[i*x,2].to_i(16) }
329
+ rgb(r, g, b, background)
330
+ end
395
331
 
396
- #
397
- class String
398
- #
399
- def ansi(*codes)
400
- ANSI::Code.ansi(self, *codes)
401
- end
332
+ private
402
333
 
403
- #
404
- def ansi!(*codes)
405
- replace(ansi(*codes))
406
- end
334
+ # Gets closest xterm-256 color.
335
+ def rgb_256(r, g, b)
336
+ r, g, b = [r, g, b].map{ |c| rgb_valid(c); (6 * (c.to_f / 256.0)).to_i }
337
+ v = (r * 36 + g * 6 + b + 16).abs
338
+ raise ArgumentError, "RGB value outside 0-255 range" if v > 255
339
+ v
340
+ end
407
341
 
408
- #
409
- def unansi
410
- ANSI::Code.unansi(self)
411
342
  end
412
343
 
413
344
  #
414
- def unansi!
415
- replace(unansi)
416
- end
345
+ extend Code
417
346
  end
418
347