Skip to content

Commit

Permalink
Use Colorize::ColorRGB, show help and highlighted error when namespac…
Browse files Browse the repository at this point in the history
…e/command not found
  • Loading branch information
Ragmaanir committed Jan 30, 2024
1 parent 3dfae6f commit 6d80b99
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 52 deletions.
8 changes: 6 additions & 2 deletions spec/interaction_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,20 @@ describe Kommando::Interaction::Session do
def write(slice : Bytes) : Nil
# STDOUT.puts ".write(#{String.new(slice).inspect})"
raise "Expected :write, got #{current_action[0]}" if current_action[0] != :write
# raise "Invalid length: #{current_action[1].inspect} <=> #{String.new(slice).inspect}" if current_action[1].size != slice.size

slice.size.times { |i|
raise "Unexpected output: #{String.new(slice).inspect} != #{current_action[1].inspect}" if slice[i] != current_action[1].byte_at(@string_idx)
if slice[i] != current_action[1].byte_at(@string_idx)
raise "Unexpected output: #{String.new(slice).inspect} != #{current_action[1].inspect}"
end
@string_idx += 1
}
advance if current_action[1].size == @string_idx
end
end

def session(io, colorize = false)
Kommando::Interaction::Session.define(io, colorize) do |s|
Kommando::Interaction::Session.define(io, io, colorize) do |s|
with s yield(s)
end
end
Expand Down Expand Up @@ -146,6 +149,7 @@ describe Kommando::Interaction::Session do
test "confirm" do
io = CannedIO.build do
write "Want to exit?\n"
write "[y, yes, n, no]\n"
write "> "
read "n\n"
end
Expand Down
18 changes: 9 additions & 9 deletions spec/namespace_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ describe Kommando::Namespace do
assert run_and_capture(["help"]) == <<-STDOUT
Commands:
\e[94m info \e[0m\e[90mPrints information\e[0m
\e[38;2;90;90;250m info \e[0m\e[38;2;100;100;100mPrints information\e[0m
Namespaces:
\e[94mdb\e[0m
\e[38;2;90;90;250mdb\e[0m
\n
STDOUT
end
Expand All @@ -104,24 +104,24 @@ describe Kommando::Namespace do
assert run_and_capture(["db", "help"]) == <<-STDOUT
Commands:
\e[94m create \e[0m\e[90mCreate the database\e[0m
\e[94m migrate \e[0m\e[90mRun pending migrations\e[0m
\e[38;2;90;90;250m create \e[0m\e[38;2;100;100;100mCreate the database\e[0m
\e[38;2;90;90;250m migrate \e[0m\e[38;2;100;100;100mRun pending migrations\e[0m
\n
STDOUT
end

test "command help" do
assert run_and_capture(["help", "info"]) == <<-STDOUT
\e[33minfo\e[0m: \e[90mPrints information\e[0m
\e[38;2;220;220;0minfo\e[0m: \e[38;2;100;100;100mPrints information\e[0m
Usage: \e[33minfo\e[0m \e[94mversion\e[0m \e[90m-option=value\e[0m
Usage: \e[38;2;220;220;0minfo\e[0m \e[38;2;90;90;250mversion\e[0m \e[38;2;100;100;100m-option=value\e[0m
Positional:
\e[94m version \e[0m : \e[35mInt32 \e[0m
\e[38;2;90;90;250m version \e[0m : \e[38;2;205;0;205mInt32 \e[0m
Options:
\e[94m dry \e[0m\e[36m-d\e[0m : \e[35mBool \e[0m \e[90mSimulate migration\e[0m
\e[94m verbose \e[0m\e[36m-v\e[0m : \e[35mBool \e[0m \e[90mMore detailed output\e[0m
\e[38;2;90;90;250m dry \e[0m\e[38;2;0;205;205m-d\e[0m : \e[38;2;205;0;205mBool \e[0m \e[38;2;100;100;100mSimulate migration\e[0m
\e[38;2;90;90;250m verbose \e[0m\e[38;2;0;205;205m-v\e[0m : \e[38;2;205;0;205mBool \e[0m \e[38;2;100;100;100mMore detailed output\e[0m
\n
STDOUT
end
Expand Down
6 changes: 4 additions & 2 deletions src/example.cr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class Example

option(:income, Int32, "", default: 0, validate: ->(v : Int32) { v >= 0 && v <= 1_000_000 })
option(:ssid, String, "", format: /\A[0-9]{10}\z/)
option(:force, Bool, "Description", default: false)
option(:force, Bool, "Force the change", default: false)

arg(:name, String)
arg(:age, Int32, validate: ->(v : Int32) { (13..150).includes?(v) })
Expand All @@ -15,7 +15,9 @@ class Example
end

cli = Kommando::Namespace.root do
command Example
namespace("examples") do
command Example
end
end

cli.exec(ARGV)
1 change: 1 addition & 0 deletions src/kommando.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "colorize"
require "./kommando/version"
require "./kommando/colors"
require "./kommando/errors"
require "./kommando/parser"
require "./kommando/docker"
Expand Down
14 changes: 14 additions & 0 deletions src/kommando/colors.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module Kommando
alias RGB = Colorize::ColorRGB

GREEN = RGB.new(0, 220, 0)
RED = RGB.new(220, 0, 0)
YELLOW = RGB.new(220, 220, 0)
WHITE = RGB.new(255, 255, 255)
DARK_GRAY = RGB.new(100, 100, 100)
LIGHT_GRAY = RGB.new(200, 200, 200)
MAGENTA = RGB.new(205, 0, 205)
LIGHT_MAGENTA = RGB.new(220, 0, 220)
CYAN = RGB.new(0, 205, 205)
LIGHT_BLUE = RGB.new(90, 90, 250)
end
26 changes: 14 additions & 12 deletions src/kommando/command.cr
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ module Kommando
Tuple.new(
{% for var in @type.instance_vars %}
{% if ann = var.annotation(Kommando::Argument) %}
{ pos: {{i}}, {{**ann.named_args}} },
{ pos: {{i}}, {{ann.named_args.double_splat}} },
{% i += 1 %}
{% end %}
{% end %}
Expand All @@ -124,9 +124,9 @@ module Kommando
end

def self.describe(io : IO)
io << command_name.colorize(:yellow)
io << command_name.colorize(Kommando::YELLOW)
io << ": "
io.puts description.colorize(:dark_gray)
io.puts description.colorize(Kommando::DARK_GRAY)
io.puts

io << "Usage: "
Expand All @@ -144,37 +144,39 @@ module Kommando
end

def self.describe_usage(io : IO)
io << command_name.colorize(:yellow)
io << command_name.colorize(Kommando::YELLOW)
io << " "

positionals.each { |a| io << a[:name].colorize(:light_blue) }
positionals.join(io, " ") { |a, io|
io << a[:name].colorize(Kommando::LIGHT_BLUE)
}

io << " "
io << "-option=value".colorize(:dark_gray)
io << "-option=value".colorize(Kommando::DARK_GRAY)
end

def self.describe_positionals(io : IO)
positionals.each { |a|
io << (" %-10s" % a[:name]).colorize(:light_blue)
io << (" %-10s" % a[:name]).colorize(Kommando::LIGHT_BLUE)
io << " : "
io << ("%-8s" % a[:type]).colorize(:magenta)
io << ("%-8s" % a[:type]).colorize(Kommando::MAGENTA)
io.puts
}
end

def self.describe_options(io : IO)
options.each { |name, o|
io << (" %-10s " % name).colorize(:light_blue)
io << (" %-10s " % name).colorize(Kommando::LIGHT_BLUE)

shortcut = ""
shortcut = ("-" + o[:short].to_s) if o[:short]

io << "%-2s" % shortcut.colorize(:cyan)
io << "%-2s" % shortcut.colorize(Kommando::CYAN)

io << " : "
io << ("%-8s" % o[:type]).colorize(:magenta)
io << ("%-8s" % o[:type]).colorize(Kommando::MAGENTA)
io << " "
io << o[:desc].colorize(:dark_gray)
io << o[:desc].colorize(Kommando::DARK_GRAY)
io.puts
}
end
Expand Down
4 changes: 2 additions & 2 deletions src/kommando/docker.cr
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ module Kommando
)

# if status.success?
# print "✓ ".colorize(:green)
# print "✓ ".colorize(GREEN)

# # puts "#{name} [#{Docker.images(stdio.to_s).last}]"
# # puts stdio.to_s.split("\n")[-3]
# else
# print "× ".colorize(:red)
# print "× ".colorize(RED)
# puts "#{name}"

# puts stdio.to_s
Expand Down
73 changes: 52 additions & 21 deletions src/kommando/interaction.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,28 @@ require "colorize"
module Kommando
module Interaction
class Session
CONFIRM = %w{Y y Yes yes}
DENY = %w{N n No no}
CONFIRM = %w{y yes}
DENY = %w{n no}

@io : IO
delegate gets, to: @io
@outp : IO
@inp : IO

getter? colorize : Bool

def self.define(io : IO, colorize : Bool = true)
s = new(io, colorize)
def self.define(outp : IO = STDOUT, inp : IO = STDIN, colorize : Bool = true)
s = new(outp, inp, colorize)
with s yield(s)
end

def initialize(@io, @colorize = true)
def initialize(@outp, @inp, @colorize = true)
end

private def print_question(q : String)
wl(q, fg: CYAN)
end

private def print_input_marker
w("> ", fg: YELLOW)
end

def read_until(&block : String -> T?) : T forall T
Expand Down Expand Up @@ -53,12 +61,12 @@ module Kommando
print_question(text)

options.each_with_index { |(key, desc), i|
w("%2d" % (i + 1), fg: :cyan)
w("%2d" % (i + 1), fg: CYAN)
w(" : ")
w(("%8s" % key), fg: :cyan)
w(("%8s" % key), fg: CYAN)
if desc
w(" : ")
w(desc, fg: :dark_gray)
w(desc, fg: DARK_GRAY)
end
br
}
Expand All @@ -81,16 +89,31 @@ module Kommando
end

def confirm(text : String, confirm : Array(String) = CONFIRM, deny : Array(String) = DENY)
ask(text) { |answer|
case answer
options = "[#{(CONFIRM + DENY).join(", ")}]"

wl(text)
wl(options, fg: LIGHT_GRAY)

read_until { |answer|
case answer.downcase
when .in?(CONFIRM) then true
when .in?(DENY) then false
else wl("Invalid input", fg: RED)
end
}
# print_question(text + "[#{(CONFIRM + DENY).join(", ")}]")

# read_until { |a|
# case a
# when .in?(CONFIRM) then true
# when .in?(DENY) then false
# else print_question(text)
# end
# }
end

def read_string_once
gets || ""
@inp.gets || ""
end

def read_once(type : Int32.class | Float32.class)
Expand All @@ -102,38 +125,46 @@ module Kommando
end
end

def print_question(q : String)
w(q, "\n", fg: :blue)
def cancel(s : String = "Cancelled")
wl(s, fg: YELLOW)
exit 0
end

def print_input_marker
w("> ", fg: :yellow)
def abort(s : String)
wl(s, fg: RED)
exit 1
end

def br
w("\n")
end

def colorized_io(fg : Symbol? = nil, bg : Symbol? = nil, m : Colorize::Mode? = nil)
def colorized_io(fg : RGB? = nil, bg : RGB? = nil, m : Colorize::Mode? = nil)
if colorize?
c = Colorize.with
c = c.fore(fg) if fg
c = c.mode(m) if m
c = c.back(bg) if bg

c.surround(@io) do |cio|
c.surround(@outp) do |cio|
yield cio
end
else
yield @io
yield @outp
end
end

def w(*strs : String | Int32 | Nil, fg : Symbol? = nil, bg : Symbol? = nil, m : Colorize::Mode? = nil)
def w(*strs : String | Int32 | Nil, fg : RGB? = nil, bg : RGB? = nil, m : Colorize::Mode? = nil)
colorized_io(fg, bg, m) do |cio|
strs.each { |s| cio << s }
end
end

def wl(*strs : String | Int32 | Nil, **options)
# w(*strs + {"\n"}, **options)
w(*strs, **options)
br
end
end
end
end
11 changes: 7 additions & 4 deletions src/kommando/namespace.cr
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ module Kommando
elsif ns = @namespaces[arg]?
ns.run(args, io)
else
raise "Unrecognized command or namespace: #{arg.inspect}"
io.puts "Unrecognized command or namespace: #{arg.inspect}".colorize(RED)
io.puts
help([] of String, io)
exit 1
end
end

Expand All @@ -77,9 +80,9 @@ module Kommando
io.puts

@commands.each do |name, cmd|
io << (" %-16s" % name).colorize(:light_blue)
io << (" %-16s" % name).colorize(LIGHT_BLUE)

io << cmd.description.colorize(:dark_gray)
io << cmd.description.colorize(DARK_GRAY)

io.puts
end
Expand All @@ -93,7 +96,7 @@ module Kommando

@namespaces.each do |name, _ns|
io << " "
io << name.colorize(:light_blue)
io << name.colorize(LIGHT_BLUE)
io.puts
end

Expand Down

0 comments on commit 6d80b99

Please sign in to comment.