sc-ansi 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.
- data/.document +5 -0
- data/.gitignore +22 -0
- data/LICENSE +20 -0
- data/README.rdoc +54 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/lib/ansi.rb +177 -0
- data/lib/ansi/code.rb +91 -0
- data/lib/ansi/color.rb +127 -0
- data/lib/ansi/cursor.rb +26 -0
- data/lib/ansi/display.rb +54 -0
- data/lib/ansi/match.rb +35 -0
- data/lib/ansi/vt100.rb +177 -0
- data/lib/core_ext/object.rb +15 -0
- data/lib/core_ext/string.rb +34 -0
- data/lib/sc-ansi.rb +9 -0
- data/sc-ansi.gemspec +79 -0
- data/spec/lib/ansi/color_spec.rb +102 -0
- data/spec/lib/ansi/cursor_spec.rb +37 -0
- data/spec/lib/ansi/display_spec.rb +21 -0
- data/spec/lib/ansi/match_spec.rb +53 -0
- data/spec/lib/ansi_spec.rb +44 -0
- data/spec/lib/core_ext/object_spec.rb +19 -0
- data/spec/lib/core_ext/string_spec.rb +68 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- metadata +122 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Colin MacKenzie IV
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
= sc-ansi
|
2
|
+
|
3
|
+
Handles every aspect (that I could think of) of dealing with ANSI escape sequences. You can produce ANSI codes easily
|
4
|
+
enough:
|
5
|
+
|
6
|
+
require 'sc-ansi' # or just require 'ansi' if you prefer.
|
7
|
+
|
8
|
+
"a string!".red #=> a red string!
|
9
|
+
"a string!".blue #=> a blue string!
|
10
|
+
"a string!".red + "another string!".blue #=> a red string and a blue string!
|
11
|
+
|
12
|
+
# or...
|
13
|
+
include ANSI
|
14
|
+
|
15
|
+
red { "a string!" } #=> a red string!
|
16
|
+
blue { "a string!" } #=> a blue string!
|
17
|
+
|
18
|
+
red + "a string!" + blue + "another string!" #=> a red string and a blue string!
|
19
|
+
|
20
|
+
== Parsing ANSI Codes
|
21
|
+
|
22
|
+
The unique thing about sc-ansi is that it can also parse ANSI codes out of an input string. Useful if you're writing
|
23
|
+
your own console application and you want to interpret, say, the UP arrow for history recall.
|
24
|
+
|
25
|
+
include ANSI # for the escape codes
|
26
|
+
|
27
|
+
string = move_up + " hello " + move_down #=> "\e[A hello \e[B"
|
28
|
+
string.ansi_sequences #=> [ ANSI::CURSOR_UP, ANSI::CURSOR_DOWN ]
|
29
|
+
|
30
|
+
string.replace_ansi do |sequence| # sequence is an instance of ANSI::Match
|
31
|
+
case sequence
|
32
|
+
when ANSI::CURSOR_UP # or ANSI::CUU
|
33
|
+
"(up)"
|
34
|
+
when ANSI::CURSOR_DOWN # or ANSI::CUD
|
35
|
+
"(down)"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
#=> "(up) hello (down)"
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
== Note on Patches/Pull Requests
|
43
|
+
|
44
|
+
* Fork the project.
|
45
|
+
* Make your feature addition or bug fix.
|
46
|
+
* Add tests for it. This is important so I don't break it in a
|
47
|
+
future version unintentionally.
|
48
|
+
* Commit, do not mess with rakefile, version, or history.
|
49
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
50
|
+
* Send me a pull request. Bonus points for topic branches.
|
51
|
+
|
52
|
+
== Copyright
|
53
|
+
|
54
|
+
Copyright (c) 2010 Colin MacKenzie IV. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "sc-ansi"
|
8
|
+
gem.summary = %Q{Handles every aspect (that I could think of) of dealing with ANSI escape sequences.}
|
9
|
+
gem.description = %Q{Handles every aspect (that I could think of) of dealing with ANSI escape sequences.}
|
10
|
+
gem.email = "sinisterchipmunk@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/sinisterchipmunk/sc-ansi"
|
12
|
+
gem.authors = ["Colin MacKenzie IV"]
|
13
|
+
gem.add_dependency "sc-core-ext", ">= 1.2.1"
|
14
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'spec/rake/spectask'
|
23
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
24
|
+
spec.libs << 'lib' << 'spec'
|
25
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
26
|
+
end
|
27
|
+
|
28
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
29
|
+
spec.libs << 'lib' << 'spec'
|
30
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
31
|
+
spec.rcov = true
|
32
|
+
spec.rcov_opts << "-x" << "/Library,spec"
|
33
|
+
end
|
34
|
+
|
35
|
+
task :spec => :check_dependencies
|
36
|
+
|
37
|
+
task :default => :spec
|
38
|
+
|
39
|
+
require 'rake/rdoctask'
|
40
|
+
Rake::RDocTask.new do |rdoc|
|
41
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
42
|
+
|
43
|
+
rdoc.rdoc_dir = 'rdoc'
|
44
|
+
rdoc.title = "sc-ansi #{version}"
|
45
|
+
rdoc.rdoc_files.include('README*')
|
46
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
47
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/lib/ansi.rb
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
# The main module for producing and/or parsing ANSI escape sequences. You can include this module into your class, or
|
2
|
+
# access it directly:
|
3
|
+
#
|
4
|
+
# ANSI.red { "a red string" }
|
5
|
+
#
|
6
|
+
# include ANSI
|
7
|
+
# red { "a red string" }
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# To see which ANSI escape sequences can be generated, take a look at the following files:
|
11
|
+
# lib/ansi/cursor.rb - sequences related to the cursor position
|
12
|
+
# lib/ansi/color.rb - sequences related to text color and decoration
|
13
|
+
# lib/ansi/display.rb - sequences related to the display, such as resolution
|
14
|
+
# lib/ansi/vt100.rb - sequences compatible with VT100 terminals
|
15
|
+
#
|
16
|
+
# You can also define your own ANSI sequences. Obviously, they won't actually work unless the target system supports
|
17
|
+
# them, but this is useful in case you need one that I somehow missed.
|
18
|
+
#
|
19
|
+
# ANSI.define("sequence_name", "sn") { |an_argument| "the sequence with #{an_argument}" }
|
20
|
+
#
|
21
|
+
# Now you can use the new sequence like so:
|
22
|
+
#
|
23
|
+
# ANSI.sequence_name(1) #=> "the sequence with 1"
|
24
|
+
# ANSI.sn(7) #=> "the sequence with 7"
|
25
|
+
#
|
26
|
+
# You can also define sequences that take blocks. In this case, the block argument will be the last argument:
|
27
|
+
#
|
28
|
+
# ANSI.define("block_sequence", "bss") { |arg1, block| "the seq #{arg1} with #{block.call}" }
|
29
|
+
#
|
30
|
+
# ANSI.block_sequence(1) { 55 }
|
31
|
+
# #=> "the seq 1 with 55"
|
32
|
+
#
|
33
|
+
# ANSI.bss(35) { 72 }
|
34
|
+
# #=> "the seq 35 with 72"
|
35
|
+
#
|
36
|
+
# Obviously, the ability to define these sequences (with or without blocks) is probably more useful to me than to you
|
37
|
+
# -- but it's in there if you need it.
|
38
|
+
#
|
39
|
+
module ANSI
|
40
|
+
class << self
|
41
|
+
def codes
|
42
|
+
@codes ||= []
|
43
|
+
end
|
44
|
+
|
45
|
+
# Causes ANSI to unload all generated methods and wipe out the #codes index, and then reload
|
46
|
+
# its internal files. The codes stored in #codes themselves are unaffected, though they will
|
47
|
+
# float into oblivion and be processed by the garbage collector if you haven't captured them
|
48
|
+
# in some way.
|
49
|
+
def reset!
|
50
|
+
codes.clear
|
51
|
+
dynamically_defined_methods.each { |c| undef_method(c) }
|
52
|
+
dynamically_defined_methods.clear
|
53
|
+
arities.clear
|
54
|
+
|
55
|
+
load File.join(File.dirname(__FILE__), "ansi/cursor.rb")
|
56
|
+
load File.join(File.dirname(__FILE__), "ansi/display.rb")
|
57
|
+
load File.join(File.dirname(__FILE__), "ansi/color.rb")
|
58
|
+
load File.join(File.dirname(__FILE__), "ansi/vt100.rb")
|
59
|
+
end
|
60
|
+
|
61
|
+
def dynamically_defined_methods
|
62
|
+
@dynamically_defined_methods ||= []
|
63
|
+
end
|
64
|
+
|
65
|
+
# The arity of the block that was used to define a particular method.
|
66
|
+
def arities
|
67
|
+
@arities ||= {}
|
68
|
+
end
|
69
|
+
|
70
|
+
# Dynamically generates an escape sequence for the specified method name. Arguments are replaced
|
71
|
+
# with "{?}".
|
72
|
+
def generate_sequence(method_name)
|
73
|
+
test_sequence(arities[method_name]) { |*args| send(method_name, *args) }
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_sequence(arity, &block)
|
77
|
+
args = []
|
78
|
+
arity.times { args << "{?}" } if arity
|
79
|
+
begin
|
80
|
+
return block.call(*args)
|
81
|
+
rescue TypeError => err
|
82
|
+
if err.message =~ /\(expected Proc\)/
|
83
|
+
args.pop
|
84
|
+
args << nil
|
85
|
+
retry
|
86
|
+
else
|
87
|
+
raise err
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Attempts to find an ANSI escape sequence which matches the specified string. The string
|
93
|
+
# is expected to use the notation "{?}" for each parameter instead of a real value. For
|
94
|
+
# instance, the sequence which would return MOVE_UP would look like: "\e[{?}A" instead of
|
95
|
+
# "\e[1A"
|
96
|
+
def recognize(str)
|
97
|
+
match = nil
|
98
|
+
String::ANSI_ESCAPE_SEQUENCE_RX =~ str
|
99
|
+
if $~ && args = $~[2].split(";")
|
100
|
+
codes.uniq.each do |code|
|
101
|
+
_args = args.dup
|
102
|
+
begin
|
103
|
+
result = code.generate(*_args)
|
104
|
+
rescue TypeError => err
|
105
|
+
if err.message =~ /\(expected Proc\)/ && !_args.empty?
|
106
|
+
_args.pop
|
107
|
+
retry
|
108
|
+
end
|
109
|
+
next
|
110
|
+
end
|
111
|
+
|
112
|
+
if result == str
|
113
|
+
match ||= ANSI::Match.new(_args)
|
114
|
+
match << code
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
return match if match
|
119
|
+
raise "ANSI sequence not found: #{str.inspect}"
|
120
|
+
end
|
121
|
+
|
122
|
+
# Aliases a specific code with the given names. This way you don't need to redefine a new constant, so performance
|
123
|
+
# is improved a little bit. Note that the code is expected to be an actual instance of ANSI::Code, and not an
|
124
|
+
# arbitrary string.
|
125
|
+
def alias_code(code, *names, &block)
|
126
|
+
code.add_methods! *names
|
127
|
+
delegate_names_for(code, *names, &block)
|
128
|
+
end
|
129
|
+
|
130
|
+
def define(*names, &block)
|
131
|
+
# this just seems like a Really Bad Idea (TM). Let's just let the user create aliases the hard way.
|
132
|
+
# @cross ||= {}
|
133
|
+
# code = @cross[test_sequence(block.arity) { |*args| instance_exec(*args, &block) }] ||= ANSI::Code.new(&block)
|
134
|
+
code = ANSI::Code.new(&block)
|
135
|
+
code.add_methods!(*names)
|
136
|
+
|
137
|
+
#code = ANSI::Code.new(*names, &block)
|
138
|
+
codes << code
|
139
|
+
delegate_names_for(code, *names, &block)
|
140
|
+
code
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
def delegate_names_for(code, *names, &block) #:nodoc:
|
145
|
+
code_index = codes.index(code)
|
146
|
+
names.flatten.each do |name|
|
147
|
+
const_name = name.to_s.upcase
|
148
|
+
const_set(const_name, code) unless const_defined?(const_name)
|
149
|
+
|
150
|
+
arities[name] = code.arity
|
151
|
+
if method_defined?(name) && $DEBUG
|
152
|
+
warn "Warning: about to overwrite method #{name}..."
|
153
|
+
end
|
154
|
+
|
155
|
+
line = __LINE__ + 1
|
156
|
+
rbcode = <<-end_code
|
157
|
+
def #{name}(*args, &block) # def red(*args, &block)
|
158
|
+
args << block if block_given? # args << block if block_given?
|
159
|
+
ANSI.codes[#{code_index}].send(#{name.inspect}, *args) # ANSI.code[1].send('red', *args)
|
160
|
+
end # end
|
161
|
+
end_code
|
162
|
+
|
163
|
+
class_eval rbcode, __FILE__, line
|
164
|
+
ANSI.instance_eval rbcode
|
165
|
+
@dynamically_defined_methods << name
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
require 'sc-core-ext'
|
172
|
+
require File.join(File.dirname(__FILE__), 'ansi/code')
|
173
|
+
require File.join(File.dirname(__FILE__), "core_ext/object")
|
174
|
+
require File.join(File.dirname(__FILE__), "core_ext/string")
|
175
|
+
require File.join(File.dirname(__FILE__), "ansi/match")
|
176
|
+
|
177
|
+
ANSI.reset!
|
data/lib/ansi/code.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
module ANSI
|
2
|
+
# The object that calling ANSI.define(...) actually creates. This is managed internally and you should rarely
|
3
|
+
# have to interface with it directly.
|
4
|
+
class Code
|
5
|
+
attr_reader :method_name, :arity, :block
|
6
|
+
include ANSI
|
7
|
+
|
8
|
+
# The name of this code. This is assigned to the first non-nil method name that this object uses.
|
9
|
+
def name
|
10
|
+
@name || (@method_name.kind_of?(String) ? @name = @method_name : @method_name.to_s).upcase
|
11
|
+
end
|
12
|
+
|
13
|
+
alias to_s name
|
14
|
+
alias inspect name
|
15
|
+
|
16
|
+
# Returns true if the other object is a kind_of ANSI::Code, *or* if the other object is a kind_of
|
17
|
+
# ANSI::Match and this ANSI::Code is contained in that match. In other words:
|
18
|
+
#
|
19
|
+
# code = ANSI::Code.new("a_code") {}
|
20
|
+
# match = ANSI::Match.new
|
21
|
+
#
|
22
|
+
# code === match
|
23
|
+
# #=> false
|
24
|
+
#
|
25
|
+
# match << code
|
26
|
+
# code === match
|
27
|
+
# #=> true
|
28
|
+
#
|
29
|
+
def ===(other)
|
30
|
+
if other.kind_of?(ANSI::Code)
|
31
|
+
return true
|
32
|
+
elsif other.kind_of?(ANSI::Match) && other == self
|
33
|
+
return true
|
34
|
+
else
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Creates methods with the specified names which are aliases of #generate. These methods are singletons
|
40
|
+
# of this instance of ANSI::Code, so adding method names using this method is only useful within the
|
41
|
+
# context of this instance.
|
42
|
+
#
|
43
|
+
def add_methods!(*names) #:nodoc:
|
44
|
+
names = names.flatten
|
45
|
+
return if names.empty?
|
46
|
+
@method_name ||= names.first.to_s
|
47
|
+
|
48
|
+
names.each do |name|
|
49
|
+
eigen.instance_eval do
|
50
|
+
alias_method name, :generate
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Takes an optional list of method aliases, which are sent to #add_methods!, and a mandatory block argument
|
56
|
+
# which is bound to the #generate method.
|
57
|
+
def initialize(*names, &block)
|
58
|
+
@arity = block.arity || 0
|
59
|
+
@block = block
|
60
|
+
|
61
|
+
eigen.instance_eval do
|
62
|
+
if block.arity > 0
|
63
|
+
# we need a list of arguments to pass to it.
|
64
|
+
define_method "generate" do |*args|
|
65
|
+
# this is to get around the warnings in Ruby 1.8
|
66
|
+
if args.length > block.arity && block.arity == 1
|
67
|
+
raise ArgumentError, "too many arguments (#{args.length} for #{block.arity})", caller
|
68
|
+
end
|
69
|
+
|
70
|
+
# omitted args should be made nil. We do this explicitly to silence warnings in 1.8.
|
71
|
+
if (len = block.arity - args.length)
|
72
|
+
len.times { args << nil }
|
73
|
+
end
|
74
|
+
|
75
|
+
instance_exec(*args, &block)
|
76
|
+
end
|
77
|
+
else
|
78
|
+
define_method("generate", &block)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
add_methods! *names
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
# the singleton class of this instance.
|
87
|
+
def eigen #:nodoc:
|
88
|
+
(class << self; self; end)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/ansi/color.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
module ANSI
|
2
|
+
# Defines various ANSI escape sequences relating to terminal color manipulation.
|
3
|
+
#
|
4
|
+
# A few low-level methods are defined:
|
5
|
+
#
|
6
|
+
# * set_color(*values)
|
7
|
+
# * takes 1 or more numeric color/attribute codes and produces the appropriate escape sequence.
|
8
|
+
# * reset_color
|
9
|
+
# * takes no arguments and resets terminal color and attributes to normal.
|
10
|
+
#
|
11
|
+
# A number of higher-level methods are defined. None of them take any arguments, and they have the effect
|
12
|
+
# that their name implies:
|
13
|
+
#
|
14
|
+
# Attribute methods:
|
15
|
+
# regular (same as reset_color)
|
16
|
+
# bold
|
17
|
+
# underscore
|
18
|
+
# blink
|
19
|
+
# reverse_video
|
20
|
+
# concealed
|
21
|
+
#
|
22
|
+
# Foreground color methods:
|
23
|
+
# black / fg_black
|
24
|
+
# red / fg_red
|
25
|
+
# green / fg_green
|
26
|
+
# yellow / fg_yellow
|
27
|
+
# blue / fg_blue
|
28
|
+
# magenta / fg_magenta
|
29
|
+
# cyan / fg_cyan
|
30
|
+
# white / fg_white
|
31
|
+
#
|
32
|
+
# Background color methods:
|
33
|
+
# bg_black
|
34
|
+
# bg_red
|
35
|
+
# bg_green
|
36
|
+
# bg_yellow
|
37
|
+
# bg_blue
|
38
|
+
# bg_magenta
|
39
|
+
# bg_cyan
|
40
|
+
# bg_white
|
41
|
+
#
|
42
|
+
# Every combination of the above is also generated as a single method call, producing results including (but not
|
43
|
+
# limited to):
|
44
|
+
# regular_red
|
45
|
+
# bold_red
|
46
|
+
# underscore_red
|
47
|
+
# blink_red
|
48
|
+
# reverse_video_red
|
49
|
+
# concealed_red
|
50
|
+
# red_on_white / regular_red_on_white
|
51
|
+
# bold_red_on_white
|
52
|
+
# underscore_red_on_white
|
53
|
+
# blink_red_on_white
|
54
|
+
# . . .
|
55
|
+
#
|
56
|
+
module Color
|
57
|
+
class << ANSI
|
58
|
+
# Defines the escape sequence, and then delegates to it from within String. This makes it possible to do things
|
59
|
+
# like "this is red".red and so forth. Note that to keep a clean namespace, we'll undef and unalias all of this
|
60
|
+
# at the end of the Color module.
|
61
|
+
def define_with_extension(*names, &block) #:nodoc:
|
62
|
+
_define(*names, &block)
|
63
|
+
names.flatten.each do |name|
|
64
|
+
String.class_eval { define_method(name) { ANSI.send(name) { self } } }
|
65
|
+
Symbol.class_eval { define_method(name) { self.to_s.send(name) } }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
alias _define define #:nodoc:
|
70
|
+
alias define define_with_extension #:nodoc:
|
71
|
+
end
|
72
|
+
|
73
|
+
ANSI.define("set_color", "color") do |*values|
|
74
|
+
block = values.last.kind_of?(Proc) ? values.pop : nil
|
75
|
+
colr = "\e[#{values.join(";")}m"
|
76
|
+
if block
|
77
|
+
colr + block.call.to_s + reset_color
|
78
|
+
else
|
79
|
+
colr
|
80
|
+
end
|
81
|
+
end
|
82
|
+
ANSI.define("reset_color", "reset") { color(0) }
|
83
|
+
|
84
|
+
# Various combinations of colors and text attributes:
|
85
|
+
# bold, underscore, blink, reverse_video, concealed
|
86
|
+
# red, fg_red, bg_red, red_on_red, bold_red, bold_red_on_red
|
87
|
+
# etc.
|
88
|
+
colors = %w(black red green yellow blue magenta cyan white)
|
89
|
+
attrs = { "regular" => 0, "bold" => 1, "underscore" => 4, "blink" => 5, "reverse_video" => 7, "concealed" => 8 }
|
90
|
+
|
91
|
+
attrs.each do |attr_name, attr_value|
|
92
|
+
ANSI.define(attr_name) { |block| color(attr_value, &block) } # 0-8
|
93
|
+
end
|
94
|
+
|
95
|
+
colors.each_with_index do |fg_name, fg_value|
|
96
|
+
fg_value += 30
|
97
|
+
ANSI.define(fg_name, "fg_#{fg_name}") { |block| color(fg_value, &block) } # 30-37 (ie red, fg_red)
|
98
|
+
ANSI.define("bg_#{fg_name}") { |block| color(fg_value + 10, &block) } # 40-47 (ie bg_red)
|
99
|
+
|
100
|
+
attrs.each do |attr_name, attr_value|
|
101
|
+
if attr_name.length > 0
|
102
|
+
# (ie bold_red)
|
103
|
+
ANSI.define("#{attr_name}_#{fg_name}") { |block| color(attr_value, fg_value, &block) }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
colors.each_with_index do |bg_name, bg_value|
|
108
|
+
bg_value += 40
|
109
|
+
# (ie red_on_blue)
|
110
|
+
ANSI.define("#{fg_name}_on_#{bg_name}") { |block| color(fg_value, bg_value, &block) }
|
111
|
+
|
112
|
+
attrs.each do |attr_name, attr_value|
|
113
|
+
ANSI.define("#{attr_name}_#{fg_name}_#{bg_name}", "#{attr_name}_#{fg_name}_on_#{bg_name}") do |block|
|
114
|
+
color(attr_value, fg_value, bg_value, &block)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class << ANSI
|
121
|
+
# Cleaning up after ourselves...
|
122
|
+
alias define _define #:nodoc:
|
123
|
+
undef define_with_extension
|
124
|
+
undef _define
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|