module Tryouts::Console

def att(name, str, io = $stdout)

def att(name, str, io = $stdout)
  str = [style(ATTRIBUTES[name], io: io), str, default_style(io)].join
  str.extend Console::InstanceMethods
  str
end

def bgcolor(col, str, io = $stdout)

def bgcolor(col, str, io = $stdout)
  str = [style(ATTRIBUTES[col], io: io), str, default_style(io)].join
  str.extend Console::InstanceMethods
  str
end

def bright(str, io = $stdout)

def bright(str, io = $stdout)
  str = [style(ATTRIBUTES[:bright], io: io), str, default_style(io)].join
  str.extend Console::InstanceMethods
  str
end

def color(col, str, io = $stdout)

def color(col, str, io = $stdout)
  str = [style(COLOURS[col], io: io), str, default_style(io)].join
  str.extend Console::InstanceMethods
  str
end

def default_style(io = $stdout)

def default_style(io = $stdout)
  style(ATTRIBUTES[:default], COLOURS[:default], BGCOLOURS[:default], io: io)
end

def pretty_path(file)


only the relevant parts of file paths instead of lengthy absolute paths.
directory. This simplifies logging and error reporting by showing
Converts an absolute file path to a path relative to the current working
def pretty_path(file)
  return nil if file.nil?
  file     = File.expand_path(file) # be absolutely sure
  basepath = Dir.pwd
  Pathname.new(file).relative_path_from(basepath).to_s
end

def reverse(str, io = $stdout)

def reverse(str, io = $stdout)
  str = [style(ATTRIBUTES[:reverse], io: io), str, default_style(io)].join
  str.extend Console::InstanceMethods
  str
end

def style(*att, io: nil)

def style(*att, io: nil)
  # Only output ANSI codes if colors are supported
  target_io = io || $stdout
  # Explicit color control via environment variables
  # FORCE_COLOR/CLICOLOR_FORCE override NO_COLOR
  return "\e[%sm" % att.join(';') if ENV['FORCE_COLOR'] || ENV['CLICOLOR_FORCE']
  return '' if ENV['NO_COLOR']
  # Check if we're outputting to a real TTY
  tty_output = (target_io.respond_to?(:tty?) && target_io.tty?) ||
               ($stdout.respond_to?(:tty?) && $stdout.tty?) ||
               ($stderr.respond_to?(:tty?) && $stderr.tty?)
  # If we have a real TTY, always use colors
  return "\e[%sm" % att.join(';') if tty_output
  # For environments like Claude Code where TTY detection fails but we want colors
  # Check if output appears to be redirected to a file/pipe
  if ENV['TERM'] && ENV['TERM'] != 'dumb'
    # Check if stdout/stderr look like they're redirected using file stats
    begin
      stdout_stat = $stdout.stat
      stderr_stat = $stderr.stat
      # If either stdout or stderr looks like a regular file or pipe, disable colors
      stdout_redirected = stdout_stat.file? || stdout_stat.pipe?
      stderr_redirected = stderr_stat.file? || stderr_stat.pipe?
      # Enable colors if neither appears redirected
      return "\e[%sm" % att.join(';') unless stdout_redirected || stderr_redirected
    rescue StandardError
      # If stat fails, fall back to enabling colors with TERM set
      return "\e[%sm" % att.join(';')
    end
  end
  # Default: no colors
  ''
end

def underline(str, io = $stdout)

def underline(str, io = $stdout)
  str = [style(ATTRIBUTES[:underline], io: io), str, default_style(io)].join
  str.extend Console::InstanceMethods
  str
end