feat: v2.0.0

This is too code-base breaking to break into usable commits:

- OOP-ify everything
- Pass Procs and simplify the colorizing methods instead of using Macros
- Improve -i and -w by not moving to the next color if it's whitespace
- Test option parse (spec)
- Create a global typesafe config instead of using a Hash
This commit is contained in:
Evangelos Paterakis 2022-12-25 00:22:24 +02:00
parent 15d87db730
commit 7487701dc4
No known key found for this signature in database
GPG key ID: FE5185F095BFC8C9
18 changed files with 595 additions and 438 deletions

1
.gitignore vendored
View file

@ -4,3 +4,4 @@
/.shards/ /.shards/
*.dwarf *.dwarf
logo-full.svg logo-full.svg
/blahaj

View file

@ -7,7 +7,7 @@
<br /> <br />
<a href="https://github.com/GeopJr/BLAHAJ/blob/main/CODE_OF_CONDUCT.md"><img src="https://img.shields.io/badge/Contributor%20Covenant-v2.1-ffffff.svg?style=for-the-badge&labelColor=5992a4" alt="Code Of Conduct" /></a> <a href="https://github.com/GeopJr/BLAHAJ/blob/main/CODE_OF_CONDUCT.md"><img src="https://img.shields.io/badge/Contributor%20Covenant-v2.1-ffffff.svg?style=for-the-badge&labelColor=5992a4" alt="Code Of Conduct" /></a>
<a href="https://github.com/GeopJr/BLAHAJ/blob/main/LICENSE"><img src="https://img.shields.io/badge/LICENSE-BSD--2--Clause-ffffff.svg?style=for-the-badge&labelColor=5992a4" alt="BSD-2-Clause" /></a> <a href="https://github.com/GeopJr/BLAHAJ/blob/main/LICENSE"><img src="https://img.shields.io/badge/LICENSE-BSD--2--Clause-ffffff.svg?style=for-the-badge&labelColor=5992a4" alt="BSD-2-Clause" /></a>
<a href="https://github.com/GeopJr/BLAHAJ/actions"><img src="https://img.shields.io/github/workflow/status/GeopJr/BLAHAJ/Specs%20&%20Lint/main?labelColor=5992a4&style=for-the-badge" alt="ci action status" /></a> <a href="https://github.com/GeopJr/BLAHAJ/actions"><img src=" https://img.shields.io/github/actions/workflow/status/GeopJr/BLAHAJ/ci.yml?branch=main&labelColor=5992a4&style=for-the-badge" alt="ci action status" /></a>
</p> </p>
# #
@ -32,13 +32,20 @@ They are built & published by our lovely [actions](https://github.com/GeopJr/BLA
#### Dependencies #### Dependencies
- `crystal` - `1.4.1` - `crystal` - `1.6.2`
#### Makefile #### Makefile
- `$ make` (or `$ make static` on Alpine Linux for a static build) - `$ make` (or `$ make static` on Alpine Linux for a static build)
- `# make install` - `# make install`
##### Multithreading
Releases are already in mt mode. It makes BLÅHAJ a *lot* faster:
- `$ make build_mt` (or `$ make static_mt` on Alpine Linux for a static build)
- `# make install`
# #
## FAQ ## FAQ
@ -73,7 +80,7 @@ Great! Follow the [Contributing section](#contributing) and modify [data/colors.
``` ```
$ blahaj -h $ blahaj -h
BLÅHAJ v1.0.0 BLÅHAJ v2.0.0
Usage: Usage:
blahaj [arguments] blahaj [arguments]
@ -85,12 +92,12 @@ Examples:
blahaj -s -b blahaj -s -b
neofetch | blahaj -c gay neofetch | blahaj -c gay
blahaj -f -c lesbian -m 4 blahaj -f -c lesbian -m 4
blahaj -- -w /etc/os-release blahaj -w /etc/os-release
Arguments: Arguments:
-b, --background Color the background -b, --background Color the background
-f, --flag Return a flag
-s, --shark Shork -s, --shark Shork
-f, --flag Return a flag
-i, --individual Color individual characters -i, --individual Color individual characters
-w, --words Color individual words -w, --words Color individual words
-m MULTIPLIER, --multiplier=MULTIPLIER -m MULTIPLIER, --multiplier=MULTIPLIER

View file

@ -1,156 +0,0 @@
{
"trans": [
"5BCEFA",
"F5A9B8",
"FFFFFF",
"F5A9B8",
"5BCEFA"
],
"agender": [
"000000",
"B9B9B9",
"FFFFFF",
"B8F483",
"FFFFFF",
"B9B9B9",
"000000"
],
"gay": [
"118C70",
"2DCDA9",
"97E7C0",
"EFEFFF",
"7AACE1",
"504BCB",
"3F2077"
],
"ace": [
"000000",
"A3A3A3",
"FFFFFF",
"800080"
],
"aro": [
"3DA542",
"A7D379",
"FFFFFF",
"A9A9A9",
"000000"
],
"bi": [
"D60270",
"9B4F96",
"0038A8"
],
"genderfluid": [
"FF75A2",
"FFFFFF",
"BE18D6",
"000000",
"333EBD"
],
"genderqueer": [
"b57EDC",
"FFFFFF",
"4A8123"
],
"nb": [
"FFF430",
"FFFFFF",
"9C59D1",
"000000"
],
"pan": [
"FF218C",
"FFD800",
"21B1FF"
],
"pride": [
"E40303",
"FF8C00",
"FFED00",
"008026",
"004DFF",
"750787"
],
"philadelphia": [
"000000",
"784F17",
"E40303",
"FF8C00",
"FFED00",
"008026",
"004DFF",
"750787"
],
"progress": [
"FFFFFF",
"F5A9B8",
"5BCEFA",
"784F17",
"000000",
"E40303",
"FF8C00",
"FFED00",
"008026",
"004DFF",
"750787"
],
"lesbian": [
"D52D00",
"EF7627",
"FF9A56",
"FFFFFF",
"D162A4",
"B55690",
"A30262"
],
"demiboy": [
"7F7F7F",
"C3C3C3",
"9AD9EA",
"FFFFFF",
"9AD9EA",
"C3C3C3",
"7F7F7F"
],
"demigirl": [
"7F7F7F",
"C3C3C3",
"FEAEC9",
"FFFFFF",
"FEAEC9",
"C3C3C3",
"7F7F7F"
],
"abrosexual": [
"75CA92",
"B4E4C9",
"FFFFFF",
"E795B6",
"D9446E"
],
"bear": [
"623804",
"D56300",
"FEDD63",
"FEE6B8",
"FFFFFF",
"555555"
],
"transgender": "trans",
"nwlnw": "gay",
"asexual": "ace",
"aromantic": "aro",
"bisexual": "bi",
"nonbinary": "nb",
"enby": "nb",
"lgbt": "pride",
"lgbtq": "pride",
"pansexual": "pan",
"philly": "philadelphia",
"nmlnm": "lesbian",
"abro": "abrosexual",
"bears": "bear",
"bearpride": "bear"
}

162
data/colors.yaml Normal file
View file

@ -0,0 +1,162 @@
trans:
color:
- 5BCEFA
- F5A9B8
- FFFFFF
- F5A9B8
- 5BCEFA
alias:
- transgender
agender:
color:
- "000000"
- B9B9B9
- FFFFFF
- B8F483
- FFFFFF
- B9B9B9
- "000000"
gay:
color:
- 118C70
- 2DCDA9
- 97E7C0
- EFEFFF
- 7AACE1
- 504BCB
- 3F2077
ace:
color:
- "000000"
- A3A3A3
- FFFFFF
- "800080"
alias:
- asexual
aro:
color:
- 3DA542
- A7D379
- FFFFFF
- A9A9A9
- "000000"
alias:
- aromantic
bi:
color:
- D60270
- 9B4F96
- 0038A8
alias:
- bisexual
genderfluid:
color:
- FF75A2
- FFFFFF
- BE18D6
- "000000"
- 333EBD
genderqueer:
color:
- b57EDC
- FFFFFF
- 4A8123
nb:
color:
- FFF430
- FFFFFF
- 9C59D1
- "000000"
alias:
- nonbinary
- enby
pan:
color:
- FF218C
- FFD800
- 21B1FF
alias:
- pansexual
pride:
color:
- E40303
- FF8C00
- FFED00
- "008026"
- 004DFF
- "750787"
alias:
- lgbt
- lgbtq
philadelphia:
color:
- "000000"
- 784F17
- E40303
- FF8C00
- FFED00
- "008026"
- 004DFF
- "750787"
alias:
- philly
progress:
color:
- FFFFFF
- F5A9B8
- 5BCEFA
- 784F17
- "000000"
- E40303
- FF8C00
- FFED00
- "008026"
- 004DFF
- "750787"
lesbian:
color:
- D52D00
- EF7627
- FF9A56
- FFFFFF
- D162A4
- B55690
- A30262
demiboy:
color:
- 7F7F7F
- C3C3C3
- 9AD9EA
- FFFFFF
- 9AD9EA
- C3C3C3
- 7F7F7F
demigirl:
color:
- 7F7F7F
- C3C3C3
- FEAEC9
- FFFFFF
- FEAEC9
- C3C3C3
- 7F7F7F
abrosexual:
color:
- 75CA92
- B4E4C9
- FFFFFF
- E795B6
- D9446E
alias:
- abro
bear:
color:
- "623804"
- D56300
- FEDD63
- FEE6B8
- FFFFFF
- "555555"
alias:
- bears
- bearpride

2
shard.lock Normal file
View file

@ -0,0 +1,2 @@
version: 2.0
shards: {}

View file

@ -1,5 +1,5 @@
name: blahaj name: blahaj
version: 1.0.1 version: 2.0.0
authors: authors:
- Evangelos "GeopJr" Paterakis <evan@geopjr.dev> - Evangelos "GeopJr" Paterakis <evan@geopjr.dev>
@ -8,6 +8,6 @@ targets:
blahaj: blahaj:
main: src/blahaj.cr main: src/blahaj.cr
crystal: 1.4.1 crystal: 1.6.2
license: BSD-2-Clauses license: BSD-2-Clauses

View file

@ -1,52 +0,0 @@
require "./spec_helper"
describe Blahaj do
it "outputs a trans flag" do
output = {{ run("#{__DIR__}/../src/blahaj", "-f").stringify }}
result = {{ read_file("#{__DIR__}/results/flag.txt") }}
output.should eq result
end
it "outputs a trans flag with 3x multiplier" do
output = {{ run("#{__DIR__}/../src/blahaj", "-f", "-m", "3").stringify }}
result = {{ read_file("#{__DIR__}/results/flag_3x.txt") }}
output.should eq result
end
it "outputs an agender shark" do
output = {{ run("#{__DIR__}/../src/blahaj", "-s", "-c", "agender").stringify }}
result = {{ read_file("#{__DIR__}/results/shark.txt") }}
output.should eq result
end
it "reads from ARGF and outputs a lesbian cowsay" do
output = {{ run("#{__DIR__}/../src/blahaj", "-c", "lesbian", "#{__DIR__}/results/cowsay.txt").stringify }}
result = {{ read_file("#{__DIR__}/results/cowsay_colored.txt") }}
output.should eq result
end
it "outputs an ace shark with each character colorized individually" do
output = {{ run("#{__DIR__}/../src/blahaj", "-s", "-c", "ace", "-i").stringify }}
result = {{ read_file("#{__DIR__}/results/shark_individual.txt") }}
output.should eq result
end
it "outputs an aro shark with each word colorized individually" do
output = {{ run("#{__DIR__}/../src/blahaj", "-s", "-c", "aro", "-w").stringify }}
result = {{ read_file("#{__DIR__}/results/shark_words.txt") }}
output.should eq result
end
it "outputs a gay shark with its background colorized" do
output = {{ run("#{__DIR__}/../src/blahaj", "-s", "-c", "nwlnw", "-b").stringify }}
result = {{ read_file("#{__DIR__}/results/shark_background.txt") }}
output.should eq result
end
end

66
spec/cli_spec.cr Normal file
View file

@ -0,0 +1,66 @@
require "./spec_helper"
def to_cli_args(arr)
arr.map do |k, v|
next if v == false
prefix = "-"
joiner = ""
if k.to_s.size > 1
prefix += prefix
joiner = "="
end
flag = "#{prefix}#{k}"
if v.is_a?(Bool)
flag
else
"#{flag}#{joiner}#{v}"
end
end.compact
end
describe Blahaj::CLI do
r = Random.new
it "sets the config" do
args = {
b: r.next_bool,
s: r.next_bool,
f: r.next_bool,
i: r.next_bool,
w: r.next_bool,
m: r.rand(100) + 1,
c: Blahaj::COLORS.keys.sample,
}
cli = Blahaj::CLI.new(to_cli_args(args))
cli.config.background.should eq args[:b]
cli.config.shark.should eq args[:s]
cli.config.flag.should eq args[:f]
cli.config.individual.should eq args[:i]
cli.config.words.should eq args[:w]
cli.config.multiplier.should eq args[:m]
cli.config.color.should eq args[:c]
end
it "gets the flag from alias" do
original_flag = Blahaj::COLORS.reject { |k, v| v.aliases.size == 0 }.sample
args = {
c: original_flag[1].aliases.sample,
}
cli = Blahaj::CLI.new(to_cli_args(args))
cli.config.color.should eq original_flag[0]
end
it "handles multiplier limits" do
args = {
m: 0,
}
cli = Blahaj::CLI.new(to_cli_args(args))
cli.config.multiplier.should_not eq args[:m]
end
end

83
spec/colorizer_spec.cr Normal file
View file

@ -0,0 +1,83 @@
require "./spec_helper"
describe Blahaj::Colorizer do
it "outputs a trans flag" do
config = Blahaj::Config.new
config.flag = true
io = IO::Memory.new
colorizer = Blahaj::Colorizer.new(config, io)
io.to_s.should eq {{ read_file("#{__DIR__}/results/flag.txt") }}
end
it "outputs a trans flag with 3x multiplier" do
config = Blahaj::Config.new
config.flag = true
config.multiplier = 3
io = IO::Memory.new
colorizer = Blahaj::Colorizer.new(config, io)
io.to_s.should eq {{ read_file("#{__DIR__}/results/flag_3x.txt") }}
end
it "outputs an agender shark" do
config = Blahaj::Config.new
config.shark = true
config.color = "agender"
io = IO::Memory.new
colorizer = Blahaj::Colorizer.new(config, io)
io.to_s.should eq {{ read_file("#{__DIR__}/results/shark.txt") }}
end
it "reads from ARGF and outputs a lesbian cowsay" do
ARGV << "#{__DIR__}/results/cowsay.txt"
config = Blahaj::Config.new
config.color = "lesbian"
io = IO::Memory.new
colorizer = Blahaj::Colorizer.new(config, io)
io.to_s.should eq {{ read_file("#{__DIR__}/results/cowsay_colored.txt") }}
end
it "outputs an ace shark with each character colorized individually" do
config = Blahaj::Config.new
config.shark = true
config.individual = true
config.color = "ace"
io = IO::Memory.new
colorizer = Blahaj::Colorizer.new(config, io)
io.to_s.should eq {{ read_file("#{__DIR__}/results/shark_individual.txt") }}
end
it "outputs an aro shark with each word colorized individually" do
config = Blahaj::Config.new
config.shark = true
config.words = true
config.color = "aro"
io = IO::Memory.new
colorizer = Blahaj::Colorizer.new(config, io)
io.to_s.should eq {{ read_file("#{__DIR__}/results/shark_words.txt") }}
end
it "outputs a gay shark with its background colorized" do
config = Blahaj::Config.new
config.shark = true
config.background = true
config.color = "gay"
io = IO::Memory.new
colorizer = Blahaj::Colorizer.new(config, io)
io.to_s.should eq {{ read_file("#{__DIR__}/results/shark_background.txt") }}
end
end

View file

@ -1,17 +1,17 @@
                                          ,(((/                                  ,(((/
                                        /(((((                                   /(((((
                                       ((((#((                              (//  ((((#(( (//
                                      (((((((.                           *(((/   (((((((. *(((/
                                    /(######/                          *((((/    /(######/ *((((/
                                 *//%#####((/                         ((#((/     *//%#####((/ ((#((/
               ,*/********/////////////////(//*           (%*      ,((##((       ,*/********/////////////////(//* (%* ,((##((
      ,*/((///(//////////((/(///////(/////(////*,(*#((/(/((//////###(###(/(      ,*/((///(//////////((/(///////(/////(////*,(*#((/(/((//////###(###(/(
   /(((((((//((///((////((((((/(((((((((((((((((/(((##((#%(##(/((///*(&#(##/     /(((((((//((///((////((((((/(((((((((((((((((/(((##((#%(##(/((///*(&#(##/
  /#((%(#(((((//#((((((((((((((((((((((((#(((((((((((/##(((((//((//*    ####(/   /#((%(#(((((//#((((((((((((((((((((((((#(((((((((((/##(((((//((//* ####(/
   (((###(###(#(#####(###############((#((((((((/((//(((#/(/////            ,,   (((###(###(#(#####(###############((#((((((((/((//(((#/(///// ,,
     ,(###%####%&%#############(#(#(####(((((((/(((/////*//,                     ,(###%####%&%#############(#(#(####(((((((/(((/////*//,
         . .....*#(#######(((###(#(##(##(((/(/(/////,                            . .....*#(#######(((###(#(##(##(((/(/(/////,
          .. ....,..........,..*#%#######/(                                      .. ....,..........,..*#%#######/(
               ..  .............,*%%%%#%((((/                                    .. .............,*%%%%#%((((/
                       **,,,****//*(##((###(#(((                                 **,,,****//*(##((###(#(((
                                        &#(#/#((((((((#                          &#(#/#((((((((#

View file

@ -1,15 +1,3 @@
require "spec" require "spec"
require "file_utils" require "file_utils"
require "../src/blahaj" require "../src/blahaj"
module Blahaj
CLI = {
"background" => false,
"color" => "trans",
"flag" => false,
"shark" => false,
"individual" => false,
"multiplier" => 1,
"words" => false,
}
end

View file

@ -1,117 +1,24 @@
require "json" require "yaml"
require "./blahaj/data_parser.cr"
module Blahaj module Blahaj
# Shork
ASCII = {{read_file("#{__DIR__}/../data/ascii.txt")}}
# Hash of all colors from data/colors.json # Hash of all colors from data/colors.json
COLORS = Hash(String, String | Array(Blahaj::Color)).from_json({{read_file("#{__DIR__}/../data/colors.json")}}) COLORS = Flags.new({{read_file("#{__DIR__}/../data/colors.yaml")}}).flags
# Chars that are to be ignored during -i or -w # Chars that are to be ignored during -i or -w
NO_COLOR = {'\n', '\t', ' '} NO_COLOR = {'\n', '\t', '\r', ' '}
end end
# Need to be required after the above have been declared # Need to be required after the above have been declared
require "./blahaj/*" require "./blahaj/*"
# [MACRO] Skip on spec
{% skip_file if @top_level.has_constant? "Spec" %}
module Blahaj module Blahaj
# Shork Blahaj::CLI.new(ARGV)
ascii = {{read_file("#{__DIR__}/../data/ascii.txt")}} Blahaj::Colorizer.new
# Selected color
scheme = COLORS[Blahaj::CLI["color"]].as(Array(Blahaj::Color))
multiplied_cols = 4 * scheme.size * Blahaj::CLI["multiplier"].as(Int32)
i = 0
# [MACRO]: Instead of checking the CLI options and colorizing accordingly, pre-generate all available
# colorizers(?) using macros
macro handle_input(background, flag, ascii, individual, words)
{%
input = if flag
"scheme.each".id
elsif ascii
"ascii.each_line".id
else
"ARGF.each_line".id
end
%}
{{input}} do |x|
current_color = scheme[i % scheme.size]
{% if flag %} # When -f is present
tmp_i = 0
# Attempt to scale the flag based on the multiplied (-m)
while tmp_i < Blahaj::CLI["multiplier"].as(Int32)
STDOUT.puts (" " * multiplied_cols).colorize.back(current_color.color)
tmp_i += 1
end
{% elsif individual || words %} # When -w or -i are present
# individual: x.chars.map
# words: x.split(' ').map
{%
word_char_splitting = "x."
word_char_joiner = ""
if words
word_char_splitting += "split(' ')"
word_char_joiner = " "
else
word_char_splitting += "chars"
end
word_char_splitting = word_char_splitting.id
%}
STDOUT.puts {{word_char_splitting}}.map { |y|
next y if NO_COLOR.includes?(y)
tmp_color = current_color
i += 1
current_color = scheme[i % scheme.size]
{% if background %}
y.colorize.back(tmp_color.color).fore(tmp_color.foreground)
{% else %}
y.colorize(tmp_color.color)
{% end %}
}.join({{word_char_joiner}})
i -= 1
{% elsif background %} # When -b is present
STDOUT.puts x.colorize.back(current_color.color).fore(current_color.foreground)
{% else %}
STDOUT.puts x.colorize(current_color.color)
{% end %}
i += 1
end
exit
end
# [MACRO]: Skip some repetitive if statements.
macro i_w_none(background = false, flag = false, ascii = false)
if Blahaj::CLI["individual"]
handle_input(background: {{background}}, flag: {{flag}}, ascii: {{ascii}}, individual: true, words: false)
elsif Blahaj::CLI["words"]
handle_input(background: {{background}}, flag: {{flag}}, ascii: {{ascii}}, individual: false, words: true)
else
handle_input(background: {{background}}, flag: {{flag}}, ascii: {{ascii}}, individual: false, words: false)
end
end
# [MACRO]: Skip on spec
{% unless @top_level.has_constant? "Spec" %}
# This is repetitive but they are macros. It saves runtime checks.
if Blahaj::CLI["shark"]
if Blahaj::CLI["background"]
i_w_none(background: true, flag: false, ascii: true)
else
i_w_none(background: false, flag: false, ascii: true)
end
elsif Blahaj::CLI["flag"]
handle_input(background: false, flag: true, ascii: false, individual: false, words: false)
elsif Blahaj::CLI["background"]
i_w_none(background: true, flag: false, ascii: false)
elsif Blahaj::CLI["individual"]
handle_input(background: false, flag: false, ascii: false, individual: true, words: false)
elsif Blahaj::CLI["words"]
handle_input(background: false, flag: false, ascii: false, individual: false, words: true)
else
handle_input(background: false, flag: false, ascii: false, individual: false, words: false)
end
{% end %}
end end

View file

@ -7,11 +7,12 @@ def clean_hex(hex : String) : String
clean_hex = hex.lstrip('#') clean_hex = hex.lstrip('#')
if clean_hex.size == 3 if clean_hex.size == 3
tmp_hex = "" clean_hex = String.build do |str|
clean_hex.each_char do |char| clean_hex.each_char do |char|
tmp_hex += "#{char}#{char}" str << char
str << char
end
end end
clean_hex = tmp_hex
end end
clean_hex.upcase clean_hex.upcase
@ -24,9 +25,8 @@ end
# Converts hex to rgb. # Converts hex to rgb.
def hex2rgb(hex : String) : NamedTuple(r: UInt8, g: UInt8, b: UInt8) def hex2rgb(hex : String) : NamedTuple(r: UInt8, g: UInt8, b: UInt8)
clean_hex = clean_hex(hex) chars = clean_hex(hex).chars.each
chars = clean_hex.chars.each
{ {
r: "#{chars.next}#{chars.next}".to_u8(16), r: "#{chars.next}#{chars.next}".to_u8(16),
g: "#{chars.next}#{chars.next}".to_u8(16), g: "#{chars.next}#{chars.next}".to_u8(16),
@ -36,6 +36,9 @@ end
module Blahaj module Blahaj
class Color class Color
getter r, g, b : UInt8
getter color : Colorize::ColorRGB
# Initialize `Blahaj::Color` using UInt8 RGB values # Initialize `Blahaj::Color` using UInt8 RGB values
def initialize(r : UInt8, g : UInt8, b : UInt8) def initialize(r : UInt8, g : UInt8, b : UInt8)
@r = r @r = r
@ -69,19 +72,13 @@ module Blahaj
initialize(json.read_string) initialize(json.read_string)
end end
# Red value # :nodoc:
def r : UInt8 def initialize(ctx : YAML::ParseContext, node : YAML::Nodes::Node)
@r unless node.is_a?(YAML::Nodes::Scalar)
node.raise "Expected scalar, not #{node.kind}"
end end
# Green value initialize(node.value)
def g : UInt8
@g
end
# Blue value
def b : UInt8
@b
end end
# Hex string # Hex string
@ -89,11 +86,6 @@ module Blahaj
@hex.upcase @hex.upcase
end end
# Color as `Colorize::ColorRGB`
def color : Colorize::ColorRGB
@color
end
# Returns the foreground color based on whether the color is dark or light # Returns the foreground color based on whether the color is dark or light
def foreground : Colorize::ColorRGB def foreground : Colorize::ColorRGB
((0.299 * @r + 0.587 * @g + 0.114 * @b)/255) > 0.5 ? Colorize::ColorRGB.new(0, 0, 0) : Colorize::ColorRGB.new(255, 255, 255) ((0.299 * @r + 0.587 * @g + 0.114 * @b)/255) > 0.5 ? Colorize::ColorRGB.new(0, 0, 0) : Colorize::ColorRGB.new(255, 255, 255)

100
src/blahaj/colorizer.cr Normal file
View file

@ -0,0 +1,100 @@
module Blahaj
class Colorizer
@io : IO
@config : Blahaj::Config
@scheme : Array(Blahaj::Color)
@multiplied_cols : Int32 = 1
@iter : IO::ARGF | String
@proc : Proc(String | Char, Blahaj::Color, Colorize::Object(Char) | Colorize::Object(String))
def initialize(config : Blahaj::Config = Blahaj.config, io : IO = STDOUT)
@io = io
@config = config
@scheme = COLORS[config.color].color
if config.flag
@multiplied_cols = 4 * @scheme.size * config.multiplier
return print_flag
end
@proc = proc_bg_fw
@iter = config.shark ? ASCII : ARGF
if config.individual
print_individual
elsif config.words
print_words
elsif config.background
print_background
else
print_color
end
end
private def print_flag
row = " " * @multiplied_cols
@scheme.each do |x|
@config.multiplier.times do
@io.puts row.colorize.back(x.color)
end
end
end
private def print_background
@iter.each_line.with_index do |x, i|
@io.puts @proc.call(x, current_color(i))
end
end
private def print_individual
i = 0
@iter.each_char do |x|
next @io.print x if NO_COLOR.includes?(x)
c_color = current_color(i)
i = i.succ
@io.print @proc.call(x, c_color)
end
end
private def print_words
c_color = current_color(0)
dont_change = false
i = 0
@iter.each_char do |x|
if NO_COLOR.includes?(x)
unless dont_change
c_color = current_color(i)
i = i.succ
end
dont_change = true
next @io.print x
end
dont_change = false
@io.print @proc.call(x, c_color)
end
end
private def print_color
@iter.each_line.with_index do |x, i|
@io.puts @proc.call(x, current_color(i))
end
end
private def proc_bg_fw(flag : Bool = false) : Proc(String | Char, Blahaj::Color, Colorize::Object(Char) | Colorize::Object(String))
if @config.background
->(x : String | Char, c_color : Blahaj::Color) { x.colorize.back(c_color.color).fore(c_color.foreground) }
else
->(x : String | Char, c_color : Blahaj::Color) { x.colorize(c_color.color) }
end
end
private def current_color(index : Int32) : Blahaj::Color
@scheme[index % @scheme.size]
end
end
end

24
src/blahaj/config.cr Normal file
View file

@ -0,0 +1,24 @@
module Blahaj
class Config
INSTANCE = Config.new
property background : Bool = false
property flag : Bool = false
property shark : Bool = false
property individual : Bool = false
property words : Bool = false
property multiplier : Int32 = 1
property color : String = "trans"
def initialize
end
end
def self.config
yield Config::INSTANCE
end
def self.config
Config::INSTANCE
end
end

18
src/blahaj/data_parser.cr Normal file
View file

@ -0,0 +1,18 @@
module Blahaj
class Flags
getter flags : Hash(String, Flag)
class Flag
include YAML::Serializable
property color : Array(Blahaj::Color)
@[YAML::Field(key: "alias")] # alias is reserved
property aliases : Array(String) = [] of String
end
def initialize(yaml_data : String)
@flags = Hash(String, Flag).from_yaml(yaml_data)
end
end
end

View file

@ -1,23 +1,22 @@
# [MACRO] Skip on spec
{% skip_file if @top_level.has_constant? "Spec" %}
require "option_parser" require "option_parser"
module Blahaj module Blahaj
Version = {{read_file("#{__DIR__}/../../shard.yml").split("version: ")[1].split("\n")[0]}} # [MACRO] Get blahaj version Version = {{read_file("#{__DIR__}/../../shard.yml").split("version: ")[1].split("\n")[0]}} # [MACRO] Get blahaj version
# CLI options / defaults class CLI
CLI = { # [MACRO] Only expose in spec.
"background" => false, {% if @top_level.has_constant? "Spec" %}
"color" => "trans", getter config : Blahaj::Config
"flag" => false, {% end %}
"shark" => false,
"individual" => false,
"multiplier" => 1,
"words" => false,
}
OptionParser.parse do |parser| def initialize(args : Array(String)?)
@config = Blahaj.config
parse args unless args.nil?
end
private def parse(args : Array(String))
OptionParser.parse args do |parser|
parser.banner = <<-BANNER parser.banner = <<-BANNER
#{"BLÅHAJ".colorize(:blue).bold} v#{Version} #{"BLÅHAJ".colorize(:blue).bold} v#{Version}
@ -36,33 +35,40 @@ module Blahaj
#{"Arguments:".colorize(:light_blue)} #{"Arguments:".colorize(:light_blue)}
BANNER BANNER
parser.on("-b", "--background", "Color the background") { CLI["background"] = true } parser.on("-b", "--background", "Color the background") { @config.background = true }
parser.on("-s", "--shark", "Shork") { CLI["shark"] = true } parser.on("-s", "--shark", "Shork") { @config.shark = true }
parser.on("-f", "--flag", "Return a flag") { CLI["flag"] = true } parser.on("-f", "--flag", "Return a flag") { @config.flag = true }
parser.on("-i", "--individual", "Color individual characters") { CLI["individual"] = true } parser.on("-i", "--individual", "Color individual characters") { @config.individual = true }
parser.on("-w", "--words", "Color individual words") { CLI["words"] = true } parser.on("-w", "--words", "Color individual words") { @config.words = true }
parser.on("-m MULTIPLIER", "--multiplier=MULTIPLIER", "Multiplier for the flag size (-f)") do |multiplier| parser.on("-m MULTIPLIER", "--multiplier=MULTIPLIER", "Multiplier for the flag size (-f)") do |multiplier|
int = multiplier.to_i? int = multiplier.to_i?
CLI["multiplier"] = int unless int.nil? || int <= 0
@config.multiplier = int unless int.nil? || int <= 0
end end
parser.on("-c FLAG", "--colors=FLAG", "Color scheme to use (Default: trans)") do |flag| parser.on("-c FLAG", "--colors=FLAG", "Color scheme to use (Default: trans)") do |flag|
down_flag = flag.downcase down_flag = flag.downcase
unless COLORS.has_key?(down_flag) unless COLORS.has_key?(down_flag)
down_flag = COLORS.find { |k, v| v.aliases.includes?(down_flag) }.try &.[0]
end
unless !down_flag.nil? && COLORS.has_key?(down_flag)
puts "Unknown flag/color \"#{down_flag}\".\nPlease pass \"--flags\" for a list of all available flags/colors.".colorize(:red) puts "Unknown flag/color \"#{down_flag}\".\nPlease pass \"--flags\" for a list of all available flags/colors.".colorize(:red)
exit(1) exit(1)
end end
down_flag = COLORS[down_flag].as(String).downcase if COLORS[down_flag].is_a?(String)
CLI["color"] = down_flag @config.color = down_flag
end end
parser.on("--flags", "List all available flags") do parser.on("--flags", "List all available flags") do
puts "Available flags/colors:\n".colorize(:light_blue) puts "Available flags/colors:\n".colorize(:light_blue)
# Skip symlink flags (eg. transgender => trans) puts COLORS.keys.sort.map { |x|
puts COLORS.reject { |_, v| v.is_a?(String) }.keys.sort.map { |x| colors = COLORS[x].color.map { |y| " ".colorize.back(y.color) }.join
colors = COLORS[x].as(Array(Blahaj::Color)).map { |y| " ".colorize.back(y.color) }.join
"#{x.capitalize} #{colors}" "#{x.capitalize} #{colors}"
}.join("\n") }.join("\n")
exit exit
end end
parser.on("-h", "--help", "Show this help") do parser.on("-h", "--help", "Show this help") do
puts parser puts parser
exit exit
@ -74,3 +80,12 @@ module Blahaj
end end
end end
end end
# [MACRO] Only expose in spec.
{% if @top_level.has_constant? "Spec" %}
def parse(args : Array(String))
previous_def
end
{% end %}
end
end