Working with Colors in BCUtils

The BCUtils.ColorFuncs module provides a comprehensive set of functions for working with terminal colors and text effects using ANSI escape codes. This guide covers all the capabilities and features of the module.

Table of Contents

Overview

The BCUtils.ColorFuncs module offers:

  • 73 named colors from basic ANSI to extended 256-color palette
  • 9 text effects (bold, italic, underline, etc.)
  • True color support (24-bit RGB)
  • Hex color support for web-style colors
  • Auto-generated color combinations for all foreground/background pairs
  • Utility functions for easy color manipulation

Basic Usage

Simple Foreground Colors

# Basic usage
ColorFuncs.fg(:red) <> "Red text" <> ColorFuncs.reset()

# With effects
ColorFuncs.fg(:blue, [:bold]) <> "Bold blue text" <> ColorFuncs.reset()

# Multiple effects
ColorFuncs.fg(:green, [:bold, :underline]) <> "Bold underlined green" <> ColorFuncs.reset()

Background Colors

# Simple background
ColorFuncs.bg(:yellow) <> "Text on yellow background" <> ColorFuncs.reset()

# Foreground + background
ColorFuncs.fg(:white) <> ColorFuncs.bg(:black) <> "White on black" <> ColorFuncs.reset()

Convenience Functions

# Wrap text with automatic reset
ColorFuncs.wrap("Hello World", :purple, [:bold])

# Apply effects only
ColorFuncs.effect(:italic) <> "Italic text" <> ColorFuncs.reset()

Color Palette

The module includes 73 carefully selected colors organized into categories:

Standard ANSI Colors (16)

  • Basic: black, red, green, yellow, blue, magenta, cyan, white
  • Bright: bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white

Extended Colors (20)

Popular colors for enhanced aesthetics:

  • orange, purple, pink, lime, navy, maroon, olive, teal
  • silver, gold, coral, salmon, khaki, violet, indigo, crimson
  • forest, sky, rose, mint

Vibrant Colors (20)

Rich, saturated colors:

  • turquoise, aqua, brown, tan, beige, ivory
  • lavender, plum, orchid, peach, apricot, lemon
  • chartreuse, emerald, jade, sapphire, ruby, amber, bronze, copper

Nature-Inspired Colors (10)

Earth and nature tones:

  • grass, leaf, ocean, sand, stone, clay, earth, bark, moss, fern

Modern/Tech Colors (10)

Cyberpunk and tech aesthetics:

  • neon_green, neon_blue, neon_pink, electric, plasma
  • laser, matrix, cyber, terminal, hacker

Grayscale (12)

Fine-grained grayscale options:

  • gray1 through gray12 (from darkest to lightest)

Text Effects

The module supports 9 text effects that can be combined:

effects = [
  :bold,           # Bold/bright text
  :dim,            # Dimmed text
  :italic,         # Italic text (not universally supported)
  :underline,      # Underlined text
  :blink,          # Slow blink
  :rapid_blink,    # Rapid blink
  :reverse,        # Reverse video (swap fg/bg colors)
  :hidden,         # Hidden text
  :strikethrough   # Strikethrough text
]

# Single effect
ColorFuncs.fg(:red, [:bold])

# Multiple effects
ColorFuncs.fg(:blue, [:bold, :underline, :italic])

# Effect only (no color change)
ColorFuncs.effect(:bold)

Advanced Functions

The tui Function

The main function for creating complex color combinations:

# Basic syntax: tui(foreground, background, effects)
ColorFuncs.tui(:white, :blue, [:bold])
ColorFuncs.tui(:yellow, :red, [:bold, :underline])
ColorFuncs.tui(:green, :black, [])

Utility Functions

# List all available colors
ColorFuncs.available_colors()

# List all available effects  
ColorFuncs.available_effects()

# Reset all formatting
ColorFuncs.reset()

True Color Support

RGB Colors

Use any RGB color combination:

# RGB foreground (values 0-255)
ColorFuncs.rgb_fg(255, 128, 0)    # Orange
ColorFuncs.rgb_fg(64, 224, 208)   # Turquoise
ColorFuncs.rgb_fg(255, 20, 147)   # Deep pink

# RGB background
ColorFuncs.rgb_bg(25, 25, 112)    # Midnight blue
ColorFuncs.rgb_bg(0, 0, 0)        # True black

# Combined usage
text = ColorFuncs.rgb_fg(255, 255, 255) <> 
       ColorFuncs.rgb_bg(0, 0, 0) <> 
       "White on true black" <> 
       ColorFuncs.reset()

Hex Colors

Use web-style hex colors:

# Hex foreground
ColorFuncs.hex_fg("#FF8000")      # Orange
ColorFuncs.hex_fg("#7aa2f7")      # Nice blue
ColorFuncs.hex_fg("#9ece6a")      # Green

# Hex background  
ColorFuncs.hex_bg("#1a1b26")      # Dark background
ColorFuncs.hex_bg("#ff0000")      # Red background

# Both formats supported
ColorFuncs.hex_fg("FF8000")       # Without #
ColorFuncs.hex_fg("#FF8000")      # With #

Auto-Generated Combinations

The module automatically generates functions for all foreground/background color combinations:

# Pattern: {foreground}_on_{background}
ColorFuncs.red_on_white()
ColorFuncs.blue_on_yellow()
ColorFuncs.white_on_black()
ColorFuncs.green_on_gray5()
ColorFuncs.neon_green_on_black()
ColorFuncs.purple_on_bright_white()

# Usage example
header = ColorFuncs.white_on_blue() <> " HEADER " <> ColorFuncs.reset()
error = ColorFuncs.white_on_red() <> " ERROR " <> ColorFuncs.reset()
success = ColorFuncs.black_on_green() <> " SUCCESS " <> ColorFuncs.reset()

This generates 5,329 functions (73 × 73) for instant access to any color combination!

Practical Examples

Creating a Status Bar

defmodule StatusBar do
  alias BCUtils.ColorFuncs, as: CF

  def render(status, message) do
    case status do
      :success -> 
        CF.wrap(" ✓ ", :black, [], :bright_green) <> 
        CF.wrap(" #{message} ", :bright_green)
        
      :error -> 
        CF.wrap(" ✗ ", :white, [], :red) <> 
        CF.wrap(" #{message} ", :red)
        
      :warning -> 
        CF.wrap(" ⚠ ", :black, [], :yellow) <> 
        CF.wrap(" #{message} ", :yellow)
        
      :info -> 
        CF.wrap(" ℹ ", :white, [], :blue) <> 
        CF.wrap(" #{message} ", :blue)
    end
  end
end

# Usage
IO.puts(StatusBar.render(:success, "Database connected"))
IO.puts(StatusBar.render(:error, "Connection failed"))

Syntax Highlighting

defmodule SyntaxHighlight do
  alias BCUtils.ColorFuncs, as: CF

  def keyword(text), do: CF.wrap(text, :purple, [:bold])
  def string(text), do: CF.wrap(text, :green)
  def number(text), do: CF.wrap(text, :cyan)
  def comment(text), do: CF.wrap(text, :gray7, [:italic])
  def function_name(text), do: CF.wrap(text, :blue, [:bold])

  def highlight_elixir(code) do
    code
    |> String.replace(~r/\bdef\b/, keyword("def"))
    |> String.replace(~r/"[^"]*"/, &string/1)
    |> String.replace(~r/\d+/, &number/1)
    |> String.replace(~r/#.*$/, &comment/1)
  end
end

Progress Indicators

defmodule Progress do
  alias BCUtils.ColorFuncs, as: CF

  def bar(percentage, width \\ 50) do
    filled = round(percentage * width / 100)
    empty = width - filled
    
    filled_bar = CF.wrap(String.duplicate("█", filled), :bright_green)
    empty_bar = CF.wrap(String.duplicate("░", empty), :gray3)
    percentage_text = CF.wrap(" #{percentage}% ", :bright_white, [:bold])
    
    "[#{filled_bar}#{empty_bar}]#{percentage_text}"
  end
  
  def spinner(frame) do
    frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
    current = Enum.at(frames, rem(frame, length(frames)))
    CF.wrap(current, :cyan) <> " Loading..."
  end
end

# Usage
IO.puts(Progress.bar(75))
IO.puts(Progress.spinner(3))

Log Level Formatting

defmodule LogFormatter do
  alias BCUtils.ColorFuncs, as: CF

  def format_level(:debug), do: CF.wrap("DEBUG", :gray8)
  def format_level(:info),  do: CF.wrap("INFO ", :bright_cyan)
  def format_level(:warn),  do: CF.wrap("WARN ", :yellow, [:bold])
  def format_level(:error), do: CF.wrap("ERROR", :red, [:bold])
  def format_level(:fatal), do: CF.wrap("FATAL", :white, [:bold], :red)

  def format_log(level, module, message) do
    timestamp = CF.wrap(DateTime.utc_now() |> to_string(), :gray6)
    level_text = format_level(level)
    module_text = CF.wrap("[#{module}]", :blue)
    
    "#{timestamp} #{level_text} #{module_text} #{message}"
  end
end

Terminal UI Components

defmodule TerminalUI do
  alias BCUtils.ColorFuncs, as: CF

  def header(title) do
    width = 60
    padding = div(width - String.length(title) - 2, 2)
    
    top = CF.wrap(String.duplicate("═", width), :bright_blue)
    middle = CF.wrap("║", :bright_blue) <> 
             String.duplicate(" ", padding) <>
             CF.wrap(title, :bright_white, [:bold]) <>
             String.duplicate(" ", padding) <>
             CF.wrap("║", :bright_blue)
    bottom = CF.wrap(String.duplicate("═", width), :bright_blue)
    
    [top, middle, bottom] |> Enum.join("\n")
  end

  def menu_item(text, selected \\ false) do
    if selected do
      CF.wrap(" ▶ #{text} ", :black, [:bold], :bright_cyan)
    else
      CF.wrap("   #{text} ", :bright_white)
    end
  end

  def table_row(cells, colors \\ []) do
    cells
    |> Enum.with_index()
    |> Enum.map(fn {cell, idx} ->
      color = Enum.at(colors, idx, :white)
      CF.wrap(String.pad_trailing(cell, 15), color)
    end)
    |> Enum.join(" │ ")
  end
end

Best Practices

1. Always Reset

Always use ColorFuncs.reset() or the wrap/3 function to avoid color bleeding:

# Good
text = ColorFuncs.fg(:red) <> "Error message" <> ColorFuncs.reset()

# Better
text = ColorFuncs.wrap("Error message", :red)

2. Check Terminal Capabilities

Not all terminals support all features:

# Some terminals don't support italic
text = if terminal_supports_italic?() do
  ColorFuncs.wrap("Italic text", :blue, [:italic])
else
  ColorFuncs.wrap("Bold text", :blue, [:bold])
end

3. Use Semantic Color Functions

Create semantic wrappers for better maintainability:

defmodule Colors do
  alias BCUtils.ColorFuncs, as: CF
  
  def error(text), do: CF.wrap(text, :red, [:bold])
  def success(text), do: CF.wrap(text, :green, [:bold])
  def warning(text), do: CF.wrap(text, :yellow, [:bold])
  def info(text), do: CF.wrap(text, :blue)
  def debug(text), do: CF.wrap(text, :gray8)
end

4. Consider Accessibility

Choose colors that work well together and are accessible:

# Good contrast
ColorFuncs.wrap("Important", :bright_white, [:bold], :red)

# Poor contrast (avoid)
ColorFuncs.wrap("Hard to read", :yellow, [], :white)

5. Use Soft Colors for Large Text Blocks

For readability, prefer softer colors over bright ones:

# Better for large text
ColorFuncs.wrap(long_text, :teal)

# Too harsh for large text
ColorFuncs.wrap(long_text, :bright_cyan)

6. Consistent Color Schemes

Define a consistent color scheme for your application:

defmodule AppTheme do
  alias BCUtils.ColorFuncs, as: CF
  
  # Primary colors
  def primary(text), do: CF.wrap(text, :blue, [:bold])
  def secondary(text), do: CF.wrap(text, :teal)
  
  # Status colors
  def success(text), do: CF.wrap(text, :emerald, [:bold])
  def danger(text), do: CF.wrap(text, :crimson, [:bold])
  def warning(text), do: CF.wrap(text, :amber, [:bold])
  
  # Text hierarchy
  def heading(text), do: CF.wrap(text, :bright_white, [:bold])
  def subheading(text), do: CF.wrap(text, :bright_white)
  def body(text), do: CF.wrap(text, :white)
  def muted(text), do: CF.wrap(text, :gray8)
end

Color Reference

Quick Reference Table

CategoryColors
Basicblack, red, green, yellow, blue, magenta, cyan, white
Brightbright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white
Extendedorange, purple, pink, lime, navy, maroon, olive, teal, silver, gold, coral, salmon, khaki, violet, indigo, crimson, forest, sky, rose, mint
Vibrantturquoise, aqua, brown, tan, beige, ivory, lavender, plum, orchid, peach, apricot, lemon, chartreuse, emerald, jade, sapphire, ruby, amber, bronze, copper
Naturegrass, leaf, ocean, sand, stone, clay, earth, bark, moss, fern
Techneon_green, neon_blue, neon_pink, electric, plasma, laser, matrix, cyber, terminal, hacker
Grayscalegray1, gray2, gray3, gray4, gray5, gray6, gray7, gray8, gray9, gray10, gray11, gray12

Effects Reference

EffectDescriptionSupport
:boldBold/bright textUniversal
:dimDimmed textMost terminals
:italicItalic textLimited
:underlineUnderlined textMost terminals
:blinkSlow blinkLimited
:rapid_blinkRapid blinkVery limited
:reverseReverse videoMost terminals
:hiddenHidden textMost terminals
:strikethroughStrikethroughModern terminals

Function Reference

FunctionDescriptionExample
fg(color, effects)Foreground color with effectsfg(:red, [:bold])
bg(color)Background colorbg(:blue)
tui(fg, bg, effects)Complete formattingtui(:white, :red, [:bold])
wrap(text, color, effects)Wrap with auto-resetwrap("Hello", :green)
rgb_fg(r, g, b)RGB foregroundrgb_fg(255, 128, 0)
rgb_bg(r, g, b)RGB backgroundrgb_bg(0, 0, 255)
hex_fg(hex)Hex foregroundhex_fg("#FF8000")
hex_bg(hex)Hex backgroundhex_bg("#0080FF")
effect(name)Apply effect onlyeffect(:bold)
reset()Reset all formattingreset()
available_colors()List all colorsavailable_colors()
available_effects()List all effectsavailable_effects()

This guide covers the complete functionality of the BCUtils.ColorFuncs module. For more examples and updates, check the module documentation and tests.