Terminal output with ALL the colors
I’ve always relied on 2-bit coloring for terminal output, sticking to eight foreground and eight background colors. It’s nice because it conforms to any user’s terminal theme. But there’s a whole world of colors out there (in most modern terminals) and I figured it was about time I started expanding my horizons.
I write most of my command line tools and scripts in Ruby. Call me old fashioned, but it really is a beautiful, readable language with plenty of room for elegant solutions. So this little snippet is in Ruby, but the core of it is simple enough that I can’t imagine it would take much work to port.
Like all terminal color output, it relies on ANSI escape codes. 2-bit escape codes look like \033[0;30;41m
, which would be regular black text on a red background. But you can use RGB values in most modern terminals with an escape code like \033[38;2;RRR;GGG;BBBm
(for a foreground color). So all you have to do is get RGB values for a specific color and insert them into that code.
The following Ruby snippet (gist here) will take a CSS hex color, e.g. #FA380E
, and turn it into an ANSI escape sequence for you. It splits the hex value and uses the #hex
method in Ruby to convert a 2-digit hex into a value between 1 and 256. With it you can run something like print "text to color".color256('#FA380E')
and get some bright red text. The snippet itself is designed to be included in a script. If you run it directly you can test by using ./256color.rb "TEXT TO COLOR" "FG" "BG"
where FG and BG are 3 or 6-digit hex codes. The octothorp (#
) is always optional.
#!/usr/bin/env ruby
# frozen_string_literal: true
# 256-color hex interpretation for terminal colorization
#
# Usage
# "text".color256(foreground, background)
#
# print "Colorize this".color256('#f7921e', '#666')
# String category
module Color256
def fg(fgc)
"\x1b[38;2;#{fgc.rgb}m"
end
def bg(bgc)
"\x1b[48;2;#{bgc.rgb}m"
end
def reset
"\x1b[0m"
end
def rgb
hex_string = sub(/^#?/, '')
hex_string = hex_string.split(//).map { |a| a * 2 }.join('') if hex_string =~ /^#?[a-f0-9]{3}$/i
parts = hex_string.match(/#?(?<r>..)(?<g>..)(?<b>..)/)
t = []
%w[r g b].each do |e|
t << parts[e].hex
end
t.join(';')
end
def color256(fgc, bgc = nil)
out = ''
out += fg(fgc)
out += bg(bgc) if bgc
out += self
out + reset
end
end
class ::String
include Color256
end
def test
256.times do |r|
256.times do |g|
256.times do |b|
c = ''
[r, g, b].each { |comp| c += format('%02x', comp) }
print ' '.color256('000', c)
end
end
end
end
if __FILE__ == $0
print ARGV[0].color256(ARGV[1], ARGV[2])
end
Hope that’s of use to somebody!
By the way, this is incorporated into the latest version of Doing such that you can use %#RRGGBB
instead of a color name to set colors in a template. And use %b#RRGGBB
to set a background color. Customize away!