Skip to content

Commit

Permalink
WIP color parser
Browse files Browse the repository at this point in the history
	Regex parser written

	NEXT:  do more doctests for default options and
		demonstrate other options
		Implement more colors then
		Implement escript
  • Loading branch information
RobertDober committed Oct 13, 2024
1 parent e6ef394 commit 6028ae7
Show file tree
Hide file tree
Showing 10 changed files with 955 additions and 53 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ ex_aequo_colors-*.tar

# Temporary files, for example, from tests.
/tmp/
tags
.local
xcol
6 changes: 1 addition & 5 deletions README.md.eex
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@

# ExAequoColors

- Use ANSI colors at will

- Install the `colorize` escript to colorize texts (like for help)

- And that's about it
Use ANSI colors at will

## Documentation

Expand Down
43 changes: 36 additions & 7 deletions lib/ex_aequo_colors.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,60 @@ defmodule ExAequoColors do

alias __MODULE__.Color

@moduledoc ~S"""
@moduledoc ~S"""
### Features
- ANSI Colors
- Extended ANSI Colors
- Extended ANSI Color, suffixs
- `colorize` CLI
"""

@doc ~S"""
add ANSI code for a color to a string
## ANSI code for a color to a string
We can use the 8 basic ANSI color codes
iex(0)> color("This is red", :red)
{:ok, "\e[31mThis is red"}
iex(1)> col("This is red", :red)
"\e[31mThis is red"
Or we can add a reset
iex(2)> col("This is red", :red, :reset)
"\e[31mThis is red\e[0m"
Which can also be achieved by means of the `colr` function
iex(3)> colr("This is red", :red)
"\e[31mThis is red\e[0m"
We can also add bold or dim
iex(4)> col("Bold and blue", :bold, :blue)
"\e[1m\e[34mBold and blue"
iex(5)> col("Green and dim", :green, :dim)
"\e[32m\e[2mGreen and dim"
"""

def color(subject, flags) do
Color.color(tostring(subject), flags)
def col(subject, flag) do
Color.color(to_string(subject), [flag])
end
def col(subject, flag1, flag2) do
Color.color(to_string(subject), [flag1, flag2])
end
def colr(subject, flag) do
Color.color_reset(to_string(subject), [flag])
end
def colr(subject, flag1, flag2) do
Color.color_reset(to_string(subject), [flag1, flag2])
end


def version, do: @version
end
Expand Down
130 changes: 130 additions & 0 deletions lib/ex_aequo_colors/cli.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
defmodule ExAequoColors.Cli do

import ExAequoBase.Map, only: [put_if: 3]
import ExAequoColors.Color, only: [color: 2]
import ExAequoColors.Colorizer, only: [colorize: 2]
import ExAequoBase.Io, only: [numbered_lines: 1]

@moduledoc false

@args """
usage:
colorize --help
colorize --version
colorize string from standard input
where options can be any of:
-a|--auto Reset color at the end of each line
-c|--closer String that ends a color code. Defaults to ">"
-d|--dollar Short for `--resetter $`
-n|--no-color Removes only the color codes but does not emit ANSI colors (can also be achieved by setting the environment variable NO_COLOR)
-r|--resetter a short for reset, defaults to nil, so you have to use e.g. `<reset>`, but can be set to any string, e.g. `$`, which then
needs to be doubled to be used verbatim
-t|--trigger String that triggers a color code, (first char of trigger needs to be doubled to get a verbatim trigger). Defaults to "<"
--html Short for --trigger <!-- and --closer -->
"""

@inner_dash ~r/(?<=[[:alnum:]])-/

def main(args) do
case parse_args(args) do
[x] ->
IO.puts(:stderr, color("ERROR:", [:bold, :red, :reset]) <> inspect(x))
IO.puts(:stderr, @args)
:help -> IO.puts(@args)
:version -> IO.puts("colorize v#{_version()}")
options -> options
|> _add_defaults()
|> _add_shortcuts()
|> colorize()
|> IO.puts
end
end

defp colorize(options) do
stream =
case Map.get(options, :file) do
nil -> IO.stream(:stdio, :line)
file -> File.stream!(file, :line)
end
run(stream, options)
end


defp run(stream, options) do
stream
|> numbered_lines()
|> Stream.map(&_colorize_line(&1, options))
|> Enum.join("\n")
end

defp _add_defaults(options) do
options
|> Map.put_new(:trigger, "<")
|> Map.put_new(:closer, ">")
end

defp _add_shortcuts(options) do
options
|> put_if(options.html, [trigger: "<!--", closer: "-->"])
|> put_if(options.dollar, [resetter: "$"])
end

defp _colorize_line({line, lnb}, options) do
case colorize(line, options) do
{:ok, result} -> result
{:error, message} -> raise "Error in line #{lnb}: #{message}"
end
end

defp parse_args(argv) do
switches = [
auto: :boolean,
closer: :string,
dollar: :boolean,
help: :boolean,
html: :boolean,
no_color: :boolean,
resetter: :string,
trigger: :string,
version: :boolean,
]

aliases = [
a: :auto,
c: :closer,
d: :dollar,
h: :help,
n: :no_color,
r: :resetter,
t: :trigger,
v: :version
]

case OptionParser.parse(argv, strict: switches, aliases: aliases) do
{_, _, [_ | _] = errors} -> errors
{[{:help, true}], _, _} -> :help
{[{:version, true}], _, _} -> :version
{options, [file], _} -> options |> Enum.into(%{}) |> Map.put(:file, file) |> Map.put(:no_color, System.get_env("NO_COLOR", Keyword.get(options, :no_color)))
{options, [], _} -> options |> Enum.into(%{}) |> Map.put(:no_color, System.get_env("NO_COLOR", Keyword.get(options, :no_color)))
end
end

# defp put_if(map, key, pairs) do
# if Map.get(map, key) do
# pairs
# |> Enum.inject(map, fn {k, v}, a -> Map.put(a, k, v) end)
# else
# map
# end
# end
@spec _version() :: binary()
defp _version do
with {:ok, version} <- :application.get_key(:ex_aequo_colors, :vsn),
do: to_string(version)
end
end
# SPDX-License-Identifier: AGPL-3.0-or-later
Loading

0 comments on commit 6028ae7

Please sign in to comment.