lib/everyday-cli-utils/safe/format.rb
module EverydayCliUtils
module Format
def self.build_format_hash(first_chr)
{
:black => "#{first_chr}0",
:red => "#{first_chr}1",
:green => "#{first_chr}2",
:yellow => "#{first_chr}3",
:blue => "#{first_chr}4",
:purple => "#{first_chr}5",
:cyan => "#{first_chr}6",
:white => "#{first_chr}7",
:none => nil,
}
end
FORMAT_TO_CODE = {
:bold => '1',
:underline => '4',
}
FG_COLOR_TO_CODE = build_format_hash('3')
BG_COLOR_TO_CODE = build_format_hash('4')
def self::format(text, format_code)
(format_code.nil? || format_code == '') ? text : "\e[#{format_code}m#{text}\e[0m"
end
def self::build_string(bold, underline, fgcolor, bgcolor)
str = ''
hit = false
hit, str = handle_bold(bold, hit, str)
hit, str = handle_underline(hit, str, underline)
hit, str = handle_fg_color(fgcolor, hit, str)
handle_bg_color(bgcolor, hit, str)
end
def self.handle_bold(bold, hit, str)
if bold
hit = true
str = FORMAT_TO_CODE[:bold]
end
return hit, str
end
def self.handle_underline(hit, str, underline)
if underline
str += ';' if hit
hit = true
str += FORMAT_TO_CODE[:underline]
end
return hit, str
end
def self.handle_fg_color(fgcolor, hit, str)
unless fgcolor.nil? || FG_COLOR_TO_CODE[fgcolor].nil?
str += ';' if hit
hit = true
str += FG_COLOR_TO_CODE[fgcolor]
end
return hit, str
end
def self.handle_bg_color(bgcolor, hit, str)
unless bgcolor.nil? || BG_COLOR_TO_CODE[bgcolor].nil?
str += ';' if hit
str += BG_COLOR_TO_CODE[bgcolor]
end
str
end
def self::parse_format(str)
parts = str.split(';')
bold = false
underline = false
fgcolor = :none
bgcolor = :none
parts.each { |v|
if v == FORMAT_TO_CODE[:bold]
bold = true
elsif v == FORMAT_TO_CODE[:underline]
underline = true
elsif v[0] == '3'
fgcolor = FG_COLOR_TO_CODE.invert[v]
elsif v[0] == '4'
bgcolor = BG_COLOR_TO_CODE.invert[v]
end
}
return bold, underline, fgcolor, bgcolor
end
def self::colorize(text, fgcolor = nil, bgcolor = nil)
self::format(text, self::build_string(false, false, fgcolor, bgcolor))
end
def self::bold(text, fgcolor = nil, bgcolor = nil)
self::format(text, self::build_string(true, false, fgcolor, bgcolor))
end
def self::underline(text, fgcolor = nil, bgcolor = nil)
self::format(text, self::build_string(false, true, fgcolor, bgcolor))
end
def self::boldunderline(text, fgcolor = nil, bgcolor = nil)
self::format(text, self::build_string(true, true, fgcolor, bgcolor))
end
def self::format_all(text)
colors = 'bk|rd|gr|yw|bl|pu|cy|wh|no'
color_map = { 'bk' => :black, 'rd' => :red, 'gr' => :green, 'yw' => :yellow, 'bl' => :blue, 'pu' => :purple, 'cy' => :cyan, 'wh' => :white, 'no' => :none }
regex = /\{(.+?)\}\((bd)?(ul)?(?:f(#{colors}))?(?:b(#{colors}))?\)/
regex2 = /\{(.+?)\}\(:(.+?)\)/
text.gsub(regex) { |_|
txt = $1
bold = !$2.nil?
underline = !$3.nil?
fg = $4.nil? ? nil : color_map[$4]
bg = $5.nil? ? nil : color_map[$5]
format(txt, build_string(bold, underline, fg, bg))
}.gsub(regex2) { |_| format($1, color_profile_string($2.to_sym)) }
end
def self::remove_format(text)
colors = 'bk|rd|gr|yw|bl|pu|cy|wh|no'
regex = /\{(.+?)\}\((bd)?(ul)?(?:f(#{colors}))?(?:b(#{colors}))?\)/
regex2 = /\{(.+?)\}\(:(.+?)\)/
text.gsub(regex, '\1').gsub(regex2, '\1') {}
end
def self.mycenter(str, len, char = ' ')
tlen = str.gsub(%r{\e\[.*?m}, '').length
return str if tlen >= len
b = ((len - tlen) / 2.0).floor
a = len - tlen - b
"#{char * b}#{str}#{char * a}"
end
ColorProfile = Struct.new(:bold, :underline, :fgcolor, :bgcolor)
def self.color_profile(id, options = {})
@color_profiles ||= {}
@color_profiles[id] = ColorProfile.new(options[:bold], options[:underline], options[:fgcolor] || nil, options[:bgcolor] || nil)
end
def self.color_profile_string(id)
@color_profiles ||= {}
profile = @color_profiles[id]
profile.nil? ? nil : self::build_string(profile.bold, profile.underline, profile.fgcolor, profile.bgcolor)
end
end
end