Skip to content

Commit

Permalink
Add simplest TTY detection for Colorize (#4075)
Browse files Browse the repository at this point in the history
* Add TTY detection for Colorize
It renames `@on` to `@enabled` because `Colorize::Object` has `#on`
method also, but `@on` is not related and its name does not make a sense.
* Add document comment for Colorize.enabled?
* Allocate TTY to colorize output
  • Loading branch information
makenowjust authored and bcardiff committed Apr 10, 2017
1 parent 9713e42 commit cf207b0
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 64 deletions.
2 changes: 1 addition & 1 deletion bin/ci
Expand Up @@ -160,7 +160,7 @@ with_build_env() {

on_linux verify_linux_environment
on_linux docker run \
--rm \
--rm -t \
-u $(id -u) \
-v $(pwd):/mnt \
-w /mnt \
Expand Down
126 changes: 67 additions & 59 deletions spec/std/colorize_spec.cr
@@ -1,123 +1,131 @@
require "spec"
require "colorize"

private def colorize(obj, *args)
obj.colorize(*args).toggle(true)
end

private def with_color_wrap(*args)
with_color(*args).toggle(true)
end

describe "colorize" do
it "colorizes without change" do
"hello".colorize.to_s.should eq("hello")
colorize("hello").to_s.should eq("hello")
end

it "colorizes foreground" do
"hello".colorize.black.to_s.should eq("\e[30mhello\e[0m")
"hello".colorize.red.to_s.should eq("\e[31mhello\e[0m")
"hello".colorize.green.to_s.should eq("\e[32mhello\e[0m")
"hello".colorize.yellow.to_s.should eq("\e[33mhello\e[0m")
"hello".colorize.blue.to_s.should eq("\e[34mhello\e[0m")
"hello".colorize.magenta.to_s.should eq("\e[35mhello\e[0m")
"hello".colorize.cyan.to_s.should eq("\e[36mhello\e[0m")
"hello".colorize.light_gray.to_s.should eq("\e[37mhello\e[0m")
"hello".colorize.dark_gray.to_s.should eq("\e[90mhello\e[0m")
"hello".colorize.light_red.to_s.should eq("\e[91mhello\e[0m")
"hello".colorize.light_green.to_s.should eq("\e[92mhello\e[0m")
"hello".colorize.light_yellow.to_s.should eq("\e[93mhello\e[0m")
"hello".colorize.light_blue.to_s.should eq("\e[94mhello\e[0m")
"hello".colorize.light_magenta.to_s.should eq("\e[95mhello\e[0m")
"hello".colorize.light_cyan.to_s.should eq("\e[96mhello\e[0m")
"hello".colorize.white.to_s.should eq("\e[97mhello\e[0m")
colorize("hello").black.to_s.should eq("\e[30mhello\e[0m")
colorize("hello").red.to_s.should eq("\e[31mhello\e[0m")
colorize("hello").green.to_s.should eq("\e[32mhello\e[0m")
colorize("hello").yellow.to_s.should eq("\e[33mhello\e[0m")
colorize("hello").blue.to_s.should eq("\e[34mhello\e[0m")
colorize("hello").magenta.to_s.should eq("\e[35mhello\e[0m")
colorize("hello").cyan.to_s.should eq("\e[36mhello\e[0m")
colorize("hello").light_gray.to_s.should eq("\e[37mhello\e[0m")
colorize("hello").dark_gray.to_s.should eq("\e[90mhello\e[0m")
colorize("hello").light_red.to_s.should eq("\e[91mhello\e[0m")
colorize("hello").light_green.to_s.should eq("\e[92mhello\e[0m")
colorize("hello").light_yellow.to_s.should eq("\e[93mhello\e[0m")
colorize("hello").light_blue.to_s.should eq("\e[94mhello\e[0m")
colorize("hello").light_magenta.to_s.should eq("\e[95mhello\e[0m")
colorize("hello").light_cyan.to_s.should eq("\e[96mhello\e[0m")
colorize("hello").white.to_s.should eq("\e[97mhello\e[0m")
end

it "colorizes background" do
"hello".colorize.on_black.to_s.should eq("\e[40mhello\e[0m")
"hello".colorize.on_red.to_s.should eq("\e[41mhello\e[0m")
"hello".colorize.on_green.to_s.should eq("\e[42mhello\e[0m")
"hello".colorize.on_yellow.to_s.should eq("\e[43mhello\e[0m")
"hello".colorize.on_blue.to_s.should eq("\e[44mhello\e[0m")
"hello".colorize.on_magenta.to_s.should eq("\e[45mhello\e[0m")
"hello".colorize.on_cyan.to_s.should eq("\e[46mhello\e[0m")
"hello".colorize.on_light_gray.to_s.should eq("\e[47mhello\e[0m")
"hello".colorize.on_dark_gray.to_s.should eq("\e[100mhello\e[0m")
"hello".colorize.on_light_red.to_s.should eq("\e[101mhello\e[0m")
"hello".colorize.on_light_green.to_s.should eq("\e[102mhello\e[0m")
"hello".colorize.on_light_yellow.to_s.should eq("\e[103mhello\e[0m")
"hello".colorize.on_light_blue.to_s.should eq("\e[104mhello\e[0m")
"hello".colorize.on_light_magenta.to_s.should eq("\e[105mhello\e[0m")
"hello".colorize.on_light_cyan.to_s.should eq("\e[106mhello\e[0m")
"hello".colorize.on_white.to_s.should eq("\e[107mhello\e[0m")
colorize("hello").on_black.to_s.should eq("\e[40mhello\e[0m")
colorize("hello").on_red.to_s.should eq("\e[41mhello\e[0m")
colorize("hello").on_green.to_s.should eq("\e[42mhello\e[0m")
colorize("hello").on_yellow.to_s.should eq("\e[43mhello\e[0m")
colorize("hello").on_blue.to_s.should eq("\e[44mhello\e[0m")
colorize("hello").on_magenta.to_s.should eq("\e[45mhello\e[0m")
colorize("hello").on_cyan.to_s.should eq("\e[46mhello\e[0m")
colorize("hello").on_light_gray.to_s.should eq("\e[47mhello\e[0m")
colorize("hello").on_dark_gray.to_s.should eq("\e[100mhello\e[0m")
colorize("hello").on_light_red.to_s.should eq("\e[101mhello\e[0m")
colorize("hello").on_light_green.to_s.should eq("\e[102mhello\e[0m")
colorize("hello").on_light_yellow.to_s.should eq("\e[103mhello\e[0m")
colorize("hello").on_light_blue.to_s.should eq("\e[104mhello\e[0m")
colorize("hello").on_light_magenta.to_s.should eq("\e[105mhello\e[0m")
colorize("hello").on_light_cyan.to_s.should eq("\e[106mhello\e[0m")
colorize("hello").on_white.to_s.should eq("\e[107mhello\e[0m")
end

it "colorizes mode" do
"hello".colorize.bold.to_s.should eq("\e[1mhello\e[0m")
"hello".colorize.bright.to_s.should eq("\e[1mhello\e[0m")
"hello".colorize.dim.to_s.should eq("\e[2mhello\e[0m")
"hello".colorize.underline.to_s.should eq("\e[4mhello\e[0m")
"hello".colorize.blink.to_s.should eq("\e[5mhello\e[0m")
"hello".colorize.reverse.to_s.should eq("\e[7mhello\e[0m")
"hello".colorize.hidden.to_s.should eq("\e[8mhello\e[0m")
colorize("hello").bold.to_s.should eq("\e[1mhello\e[0m")
colorize("hello").bright.to_s.should eq("\e[1mhello\e[0m")
colorize("hello").dim.to_s.should eq("\e[2mhello\e[0m")
colorize("hello").underline.to_s.should eq("\e[4mhello\e[0m")
colorize("hello").blink.to_s.should eq("\e[5mhello\e[0m")
colorize("hello").reverse.to_s.should eq("\e[7mhello\e[0m")
colorize("hello").hidden.to_s.should eq("\e[8mhello\e[0m")
end

it "colorizes mode combination" do
"hello".colorize.bold.dim.underline.blink.reverse.hidden.to_s.should eq("\e[1;2;4;5;7;8mhello\e[0m")
colorize("hello").bold.dim.underline.blink.reverse.hidden.to_s.should eq("\e[1;2;4;5;7;8mhello\e[0m")
end

it "colorizes foreground with background" do
"hello".colorize.blue.on_green.to_s.should eq("\e[34;42mhello\e[0m")
colorize("hello").blue.on_green.to_s.should eq("\e[34;42mhello\e[0m")
end

it "colorizes foreground with background with mode" do
"hello".colorize.blue.on_green.bold.to_s.should eq("\e[34;42;1mhello\e[0m")
colorize("hello").blue.on_green.bold.to_s.should eq("\e[34;42;1mhello\e[0m")
end

it "colorizes foreground with symbol" do
"hello".colorize(:red).to_s.should eq("\e[31mhello\e[0m")
"hello".colorize.fore(:red).to_s.should eq("\e[31mhello\e[0m")
colorize("hello", :red).to_s.should eq("\e[31mhello\e[0m")
colorize("hello").fore(:red).to_s.should eq("\e[31mhello\e[0m")
end

it "colorizes mode with symbol" do
"hello".colorize.mode(:bold).to_s.should eq("\e[1mhello\e[0m")
colorize("hello").mode(:bold).to_s.should eq("\e[1mhello\e[0m")
end

it "raises on unknown foreground color" do
expect_raises ArgumentError, "Unknown color: brown" do
"hello".colorize(:brown)
colorize("hello", :brown)
end
end

it "raises on unknown background color" do
expect_raises ArgumentError, "Unknown color: brown" do
"hello".colorize.back(:brown)
colorize("hello").back(:brown)
end
end

it "raises on unknown mode" do
expect_raises ArgumentError, "Unknown mode: bad" do
"hello".colorize.mode(:bad)
colorize("hello").mode(:bad)
end
end

it "inspects" do
"hello".colorize(:red).inspect.should eq("\e[31m\"hello\"\e[0m")
colorize("hello", :red).inspect.should eq("\e[31m\"hello\"\e[0m")
end

it "colorizes io with method" do
io = IO::Memory.new
with_color.red.surround(io) do
with_color_wrap.red.surround(io) do
io << "hello"
end
io.to_s.should eq("\e[31mhello\e[0m")
end

it "colorizes io with symbol" do
io = IO::Memory.new
with_color(:red).surround(io) do
with_color_wrap(:red).surround(io) do
io << "hello"
end
io.to_s.should eq("\e[31mhello\e[0m")
end

it "colorizes with push and pop" do
io = IO::Memory.new
with_color.red.push(io) do
with_color_wrap.red.push(io) do
io << "hello"
with_color.green.push(io) do
with_color_wrap.green.push(io) do
io << "world"
end
io << "bye"
Expand All @@ -127,9 +135,9 @@ describe "colorize" do

it "colorizes with push and pop resets" do
io = IO::Memory.new
with_color.red.push(io) do
with_color_wrap.red.push(io) do
io << "hello"
with_color.green.bold.push(io) do
with_color_wrap.green.bold.push(io) do
io << "world"
end
io << "bye"
Expand All @@ -138,11 +146,11 @@ describe "colorize" do
end

it "toggles off" do
"hello".colorize.black.toggle(false).to_s.should eq("hello")
"hello".colorize.toggle(false).black.to_s.should eq("hello")
colorize("hello").black.toggle(false).to_s.should eq("hello")
colorize("hello").toggle(false).black.to_s.should eq("hello")
end

it "toggles off and on" do
"hello".colorize.toggle(false).black.toggle(true).to_s.should eq("\e[30mhello\e[0m")
colorize("hello").toggle(false).black.toggle(true).to_s.should eq("\e[30mhello\e[0m")
end
end
21 changes: 17 additions & 4 deletions src/colorize.cr
Expand Up @@ -77,6 +77,19 @@
# :hidden
# ```
module Colorize
# If this value is `true`, `Colorize::Object` is enabled by default.
# But if this value is `false`, `Colorize::Object` is disabled.
#
# This defaule value is `true` only if both of `STDOUT.tty?` and `STDERR.tty?` are `true`.
#
# ```
# Colorize.enabled = true
# "hello".colorize.red.to_s # => "\e[31mhello\e[0m"
#
# Colorize.enabled = false
# "hello".colorize.red.to_s # => "hello"
# ```
class_property? enabled : Bool = STDOUT.tty? && STDERR.tty?
end

def with_color
Expand Down Expand Up @@ -162,7 +175,7 @@ struct Colorize::Object(T)
@fore = FORE_DEFAULT
@back = BACK_DEFAULT
@mode = 0
@on = true
@enabled = Colorize.enabled?
end

{% for name in COLORS %}
Expand Down Expand Up @@ -221,8 +234,8 @@ struct Colorize::Object(T)
back color
end

def toggle(on)
@on = !!on
def toggle(flag)
@enabled = !!flag
self
end

Expand Down Expand Up @@ -263,7 +276,7 @@ struct Colorize::Object(T)
end

protected def append_start(io, reset = false)
return false unless @on
return false unless @enabled

fore_is_default = @fore == FORE_DEFAULT
back_is_default = @back == BACK_DEFAULT
Expand Down

0 comments on commit cf207b0

Please sign in to comment.