CUIの世界は地味な世界です。真っ黒なターミナル画面に単一色の文字列。それが却って落ち着くという向きもありますが、今となってはその地味さは際立っています。

ターミナルで色を使う方法を学ぶことで、新しい世界が開けるかも知れません。

ようこそANSIカラーの世界へ!

エスケープシーケンス

ターミナルで色を使うためにはエスケープシーケンスというものを利用します。エスケープシーケンスはターミナル上で色を含む特定の制御を実現するための特殊な文字列です。

print "\e[31mhello\e[0m"

これによりターミナル上に赤文字で「hello」と出力されます。この”\e[31m” “\e[0m”の部分がエスケープシーケンスです。”\e[31m”はそれ以降を赤文字で出力する制御命令、”\e[0m”はそれ以降を初期状態へリセットする制御命令です。

シーケンス中の数字において、30~37は文字色、40~47は背景色、0~9は文字装飾に割り振られています。

Text attributes
0	All attributes off
1	Bold on
4	Underscore (on monochrome display adapter only)
5	Blink on
7	Reverse video on
8	Concealed on
Foreground colors
30	Black
31	Red
32	Green
33	Yellow
34	Blue
35	Magenta
36	Cyan
37	White
Background colors
40	Black
41	Red
42	Green
43	Yellow
44	Blue
45	Magenta
46	Cyan
47	White 

ASCII Table - ANSI Escape sequences

1つの文字列に複数のシーケンスを適用することもできます。

print "\e[31m\e[43m\e[5mhello\e[0m"

これで黄色の背景色上で赤いhelloが点滅します。セミコロンで区切って、複数のシーケンスコードを適用することもできます。これは上のシーケンスと等価です。

print "\e[31;43;5mhello\e[0m"

エスケープシーケンスは端末依存で、端末によって使えないものもあります。

ターミナルカラー・ライブラリ

Rubyでカラーシーケンスを使う場合、そのままでは扱いづらいので定数などへのマッピングが必要になるでしょう。また文字列終端での復帰にも対応しなければいけません。自作する手もありますが、Rubyには既に便利なライブラリがいくつかあります。

HighLine

HighLineはターミナルの入出力を支援するツール群です。その中にカラーシーケンスを扱うHighLine#colorがあります。gem install highlineでインストールして、以下のように使います。

require 'highline'
h = HighLine.new
puts h.color("hello", :green)

色属性として複数の引数を取ることもできます。

puts h.color("Ruby World", :red, :on_cyan, :underline)

TermColor

TermColorは文字列中のカラータグをエスケープシーケンスに変換するライブラリです。gem install termcolorでインストールして、以下のように使います。

require 'termcolor'
puts TermColor.parse("<green>hello</green>")
puts TermColor.parse("<red><on_white><blink>ruby is fun!</blink></on_white></red>")

色指定は1つしかできませんが以下のように使うこともできます。

puts TermColor.colorize("hello", :green)

またString#termcolorが用意されているので、以下のようにもできます。

puts "<red><bold>Ruby is red!</bold></red>".termcolor

TermColorはTermtterのjugyoさん作で、Termtterでのカラー表示に使われています。

Rainbow

RainbowはStringクラスにcolor(foreground), background,bright, blink, inverseなどのエスケープシーケンスに対応したメソッドを追加します。gem install rainbowでインストールして、以下のように使います。

require 'rainbow'
puts "hello".color(:red)
puts "hello".color(255, 0, 0)
puts "hello".color(:red).background(:green)
puts "hello".bright.background(:blue).blink

Term-ANSIColor

Term-ANSIColorは多様な使い方ができるライブラリで、エスケープシーケンスをモジュール関数化したり、Stringクラスのインスタンスメソッドにしたりできます。gem install term-ansicolorでインストールして、以下のように使います。

まずはクラスメソッドとして。

require 'term/ansicolor'
class Color
  extend Term::ANSIColor
end
print Color.red, Color.bold, "No Namespace cluttering:", Color.clear, "\n"
print Color.green + "green" + Color.clear, "\n"
print Color.on_red(Color.green("green")), "\n"
print Color.yellow { Color.on_black { "yellow on_black" } }, "\n\n"

次にTerm::ANSIColorのインスタンスメソッドとして。

c = Term::ANSIColor
print c.red, c.bold, "No Namespace cluttering (alternative):", c.clear, "\n"
print c.green + "green" + c.clear, "\n"
print c.on_red(c.green("green")), "\n"
print c.yellow { c.on_black { "yellow on_black" } }, "\n\n"

関数的に。

include Term::ANSIColor
print red, bold, "Usage as constants:", reset, "\n"
print red("red"),  on_red("on_red"), "\n"
print red { bold { "Usage as block forms:" } }, "\n"

Stringのメソッドとして。

class String
  include Term::ANSIColor
end
print "Usage as String Mixins:".red.bold, "\n"
print "Hello, World\n".blue.on_yellow.blink

Wirble

Wirbleはirb(Interactive Ruby)の支援ツールで、Rubyのシンタックスに合わせたカラーリングすなわち、Syntax Highlightingを実現します。ライブラリとして使う場合は以下のようにします。

require "wirble"
w = Wirble::Colorize
puts w.colorize_string("Hello, Ruby", :light_cyan)
puts w.colorize("hello, :hello, [1, 2, 3], {:a => 1, :b => 2}")

image

colorizeメソッドでRubyのオブジェクトに応じたカラーリングが実現できているのが分かります。

なおirbで使う場合は.irbrcで以下のように指定します。

require 'wirble'
  Wirble.init
  Wirble.colorize

Coderay

CodeRayは複数の言語に対応したSyntax Highlightingライブラリです。Rubyのコードをターミナルでカラーリングする場合は、以下のようにします。

require "coderay"
puts CodeRay.scan("5.times do\n puts 'hello, ruby'\nend", :ruby).term

image

ファイルから読込んでHTML出力するようなこともできます。

puts CodeRay.scan_file("code.rb").div(:line_numbers => :table)

image

素晴らしいですね!

Paint

Paintはライブラリでの使い勝手と拡張性を売りにした、非常にユニークな使い方ができるライブラリです。gem install paintでインストールして、以下のように使います。

まずはPaint.[]クラスメソッドを使う例です。

require 'paint'
 Paint['Ruby', :red] #=> "\e[31mRuby\e[0m"
 Paint['Ruby', :red, :bright, :underline] #=> "\e[31;1;4mRuby\e[0m"
 Paint['Ruby', :red, :blue] #=> "\e[31;44mRuby\e[0m"

第3引数以降に現れるカラーは背景色用です。

色の指定は多様な方法でできます。

Paint['Ruby', [100, 255, 5]] #=> "\e[38;5;118mRuby\e[0m"
 Paint['Ruby', "gold", "snow"] #=> "\e[38;5;226;48;5;231mRuby\e[0m"
 Paint['Ruby', "#123456"] #=> "\e[38;5;24mRuby\e[0m"
 Paint['Ruby', "fff"] #=> "\e[38;5;231mRuby\e[0m"

第2引数以下を省略すると色指定がランダムになり、:inverseをしていすると前景色と背景色を入れ替えます。

それが削除されたということを示すために Paint['Ruby'] #=> "\e[37mRuby\e[0m" 
 Paint['Ruby', :inverse] #=> "\e[7mRuby\e[0m"

image

PaintがユニークなのはPaint::SHORTCUTSを使ったユーザカラー定義です。

Paint::SHORTCUTS[:mycolor] = {
     :white => Paint.color(:black),
     :red   => Paint.color(:red, :bright),
     :title => Paint.color(:underline)
   } #=> {:white=>"\e[30m", :red=>"\e[31;1m", :title=>"\e[4m"}

上のように登録することでPaint::Mycolorの名前空間で、white red titleの各クラスメソッドが有効になります。

Paint::Mycolor.red "Ruby" #=> "\e[31;1mRuby\e[0m"
 Paint::Mycolor.white #=> "\e[30m"
 Paint::Mycolor.title "Ruby" #=> "\e[4mRuby\e[0m"
 include Paint::Mycolor #=> Object
 red "Ruby" #=> "\e[31;1mRuby\e[0m"
 white "Ruby" #=> "\e[30mRuby\e[0m"

それだけでなく、Paint::Mycolor::Stringモジュールをincludeすることにより、あらゆるオブジェクトをユーザ定義に従い、色つき文字列化することもできます。

include Paint::Mycolor::String #=> Object
 "Ruby".red #=> "\e[1;31mRuby\e[0m"
 "Ruby".title #=> "\e[4mRuby\e[0m"
 5.red #=> "\e[31;1m5\e[0m"
 [1, 2].red #=> "\e[31;1m[1, 2]\e[0m"

ちょっとやり過ぎな気もしますが..

グローバルな名前空間が汚染されることを避けたいなら、プレフィクスとして任意のメソッド名を指定することもできます。

include Paint::Mycolor::Prefix::C #=> Object
 "Ruby".c(:red) #=> "\e[31;1mRuby\e[0m"
 "Ruby".c(:title) #=> "\e[4mRuby\e[0m"
 [1, 2].c(:red) #=> "\e[31;1m[1, 2]\e[0m"

なんかスゴイですね!

ご想像のとおりPaintモジュールの内部はメタプログラミングばりばりです:)

Colcolor

Colcolorはカラム指向の拙作カラーライブラリです。この使い方については2014-7-14に別途記事にしていますが、その一部をここに転載します。

Yet Another Terminal Color for Ruby: Colcolorの紹介

colcolorが特徴的なのは、他のライブラリが行指向のものであるのに対して、列(カラム)指向である点です。つまり一行におけるホワイトスペースで区切られたカラムを認識し、それ毎に異なるカラーを適用できるのです。

"Charlie 21 programmer".colco(:red, :yellow, :cyan) # => "\e[31mCharlie\e[0m \e[33m21\e[0m \e[36mprogrammer\e[0m"

例えば、タブ区切りのリストにおいて、そのカラムごとに色を変えたい場合は、次のように簡単にできます。

require "colcolor"

list = <<-EOS
Charlie\t21\tprogrammer
Bill\t43\tdoctor
Liz\t18\tstudent
EOS

list.each_line do |line|
  puts line.colco(:green, :yellow, :blue)
end

出力です。

Alt title noshadow

背景色を作りたいときは、:bg_greenなどとします。

複数属性の適用

一つのカラムに対して、前景色と背景色など複数の属性を適用したい場合は、アンダースコア(_)で属性をつなぎます。

list.each_line do |line|
  puts line.colco(:green, :red_yellow, :blue_underline)
end

最初の色が前景色、2つ目以降が背景色になります。出力です。

Alt title noshadow

緑背景に赤文字を点滅させたいときは、:red_green_blinkなどとします。

カスタムカラムパターン

デフォルトではホワイトスペースをカラムの区切りと認識して各色を適用しますが、regexpオプションでこれをカスタマイズできます。

例えば、リストにスペースで区切られた名前と苗字が含まれていて、そこは連続した背景色にしたい場合、次のようにします。

list = <<-EOS
Charlie Brown\t21\tprogrammer
Bill Clinton\t43\tdoctor
Liz Taylor\t18\tstudent
EOS

# 不適切な例:

list.each_line do |line|
  puts line.colco(:bg_green, :bg_green, :yellow, :blue_underline)
end

puts

# regexpオプションを使った例:

re = /^.*?(?=\t)|\S+/ # 最初のタブの前、または空白以外にマッチ

list.each_line do |line|
  puts line.colco(:bg_green, :yellow, :blue_underline, regexp:re)
end

出力です。

Alt title noshadow

IRC(Interactive Colors)

最後に上のライブラリを使って、ターミナル上でインタラクティブにカラーチェックができるirc.rbという簡単なツールを作りました。Term-ANSIColorライブラリを使っています。

ruby irc.rbで立上げると、welcomeメッセージに続きirbのようにpromptモードになります。red on_greenなどの色属性をタイプすると、その属性に制御された文字列が表示されます。

image

文字列をリセットしたい場合は、’=’に続いて文字列をタイプします。入力できる属性はhelp(h, colors, attrs)で確認できます。終了はexit(q, quit, bye)です。

image

使ってくれる人がいたらうれしいです。

(追記:2010-11-8) rainbow commandを追加しました。GNU Readlineに対応しました。

image

(追記:2010-11-12) WirbleとCodeRayライブラリの記載を追加しました。 (追記:2011-7-20) Paintライブラリの記載を追加しました。 (追記:2014-7-23) Colcolrライブラリの記載を追加しました。

melborne/irc - GitHub



blog comments powered by Disqus
ruby_pack8

100円〜で好評発売中!
M'ELBORNE BOOKS