Skip to main content

Uma biblioteca leve e moderna para dar cores a textos no terminal usando sintaxe simplificada e suporte a True Color (Hexadecimal).

Project description

ColorMax 🎨

ColorMax is an ultra-lightweight, performance-optimized Python library with zero external dependencies designed for terminal text styling using ANSI escape codes.

Unlike other libraries that bloat the terminal's rendering buffer and break character spacing (especially in mobile emulators like Pydroid 3), ColorMax utilizes an isolated scope injection architecture, ensuring perfect cross-platform compatibility and a 100% clean layout.


✨ Core Features

  • 🏷️ Tag-Based Parser: Format complex strings using an intuitive syntax similar to BBCode/HTML ([bold #FF5500]Text[/]).
  • 🔒 Closure-Based API: Access styles via dictionary mapping for strict scope isolation (colormax["bold red"]("Text")).
  • 🧮 Native Hexadecimal Converter: Full support for Hexadecimal colors (#RRGGBB) translated in real-time to the ANSI-256 extended palette.
  • 📦 Zero Dependencies: Built purely on Python's native re standard library.
  • 🛡️ Cross-Platform Optimization: Native protection against "ghost spaces" and buffer clipping in Android (Pydroid 3/Termux), Linux, and Windows environments.

🚀 Internal Engineering

1. Encoding and ANSI Standard (latin-1)

The source file uses the # coding: latin-1 declaration to ensure maximum compatibility with both legacy and modern terminals, extending character support without generating byte-decoding conflicts in the standard output (sys.stdout).

The library directly manipulates ANSI Escape Sequences (Select Graphic Rendition). When a tag is processed, ColorMax translates it into the standard format:

\033[<STYLE>;<COLOR>m

To ensure that the user's terminal does not "leak" color into the system's subsequent lines, the interpreter automatically injects the total reset token \033[0m at the end of every execution block.

2. Hexadecimal to ANSI-256 Conversion Algorithm

To provide custom color support without relying on third-party packages, ColorMax implements a two-stage RGB matrix compression algorithm:

  1. Base-16 Extraction: The Hexadecimal string (e.g., #FFAA00) is cleaned and sliced into three 8-bit integer channels (Red, Green, and Blue) ranging from $0$ to $255$.
  2. Scope Mapping: * If all three channels are identical ($R = G = B$), the engine identifies a pure grayscale tone and maps the value directly onto the ANSI grayscale ramp (channels $232$ to $255$).
    • If there is chromatic variation, the engine projects the channels into the ANSI standard $6 \times 6 \times 6$ color cube using the following mathematical formula:

$$\text{ANSI_ID} = 16 + (36 \times R_6) + (6 \times G_6) + B_6$$

Where each component $X_6$ represents the scaled down channel: $X_6 = \lfloor \frac{X}{256} \times 6 \rfloor$.

3. Buffer Optimization (Anti-Spacing Bug Fix)

Many libraries on the market process strings by applying ANSI codes character by character. While this goes unnoticed on heavy desktop terminals, on ARM processors and emulators like Pydroid 3, the graphics engine attempts to recalculate the line width for every invisible character, creating "ghost micro-spaces" and eating up letters on the screen.

ColorMax resolves this by applying processing strictly at the boundaries of the found tokens. The text inside a tag remains intact as a pure string, and the delimiters are injected all at once, reducing string manipulation overhead by up to 90%.


📦 Core Implementation (core.py)

Here is the complete, self-contained source code for the library:

# coding: latin-1
import re

class ColorMax:
    _STANDARD_COLORS = {
        "black": "30",
        "red": "31",
        "green": "32",
        "yellow": "33",
        "blue": "34",
        "magenta": "35",
        "cyan": "36",
        "white": "37"
    }

    _STYLES = {
        "bold": "1",
        "dim": "2",
        "light": "2",
        "medium": "0",
        "italic": "3",
        "underline": "4",
        "blink": "5"
    }

    def __init__(self):
        self._tag_regex = re.compile(r"\[([^\]]+)\]")

    def _hex_to_rgb(self, hex_str: str):
        hex_clean = hex_str.lstrip('#').strip()
        if len(hex_clean) == 6:
            try:
                r = int(hex_clean[0:2], 16)
                g = int(hex_clean[2:4], 16)
                b = int(hex_clean[4:6], 16)
                return r, g, b
            except ValueError:
                return None
        return None

    def _rgb_to_ansi_256(self, r: int, g: int, b: int) -> str:
        if r == g == b:
            if r < 8: return "16"
            if r > 248: return "231"
            return str(round(((r - 8) / 247) * 23) + 232)
        
        ansi_r = int(r / 256 * 6)
        ansi_g = int(g / 256 * 6)
        ansi_b = int(b / 256 * 6)
        return str(16 + (36 * ansi_r) + (6 * ansi_g) + ansi_b)

    def _parse_styles(self, style_string: str) -> str:
        style_string = style_string.strip().lower()
        
        if style_string == "/":
            return "\033[0m"

        ansi_parts = []
        tokens = style_string.split()

        for token in tokens:
            if token in self._STYLES:
                ansi_parts.append(self._STYLES[token])
            elif token in self._STANDARD_COLORS:
                ansi_parts.append(self._STANDARD_COLORS[token])
            else:
                rgb = self._hex_to_rgb(token)
                if rgb is not None:
                    r, g, b = rgb
                    color_id = self._rgb_to_ansi_256(r, g, b)
                    ansi_parts.append(f"38;5;{color_id}")

        if ansi_parts:
            return f"\033[{';'.join(ansi_parts)}m"
        return ""

    def format(self, text: str) -> str:
        result = []
        last_idx = 0

        for match in self._tag_regex.finditer(text):
            result.append(text[last_idx:match.start()])
            tag_content = match.group(1)
            ansi_code = self._parse_styles(tag_content)
            result.append(ansi_code)
            last_idx = match.end()

        result.append(text[last_idx:])
        return "".join(result) + "\033[0m"

    def __call__(self, text: str) -> str:
        return self.format(text)

    def __getitem__(self, style_key: str):
        ansi_code = self._parse_styles(style_key)
        reset_code = "\033[0m"
        return lambda text: f"{ansi_code}{text}{reset_code}"

colormax = ColorMax()

🛠️ Usage Modes & Examples

Mode 1: Dynamic Tag Syntax

Ideal for quick logging, Command Line Interfaces (CLIs), and mixed inline formatting strings.

from src.colormax import colormax

# Simple usage combining styles and standard colors
print(colormax("Status: [bold green]ONLINE[/] - Database: [#00FFCC]Connected[/]"))

# Multiple modifiers inside a single tag
print(colormax("Alert: [bold underline #FF3333]PROX-Z BLOCK INTRUSION DETECTED[/]"))

Mode 2: Dictionary Syntax (Closures)

Ideal for UI component design, highly structured layouts, and processing large volumes of data streams, as it stores the pre-compiled ANSI codes directly in memory.

from src.colormax import colormax

# Generating reusable interface style tokens
critical_error = colormax["bold #FF0055"]
light_warning  = colormax["light #FFFF00"]
smooth_info    = colormax["italic white"]

# Applying the components safely
print(critical_error("CRITICAL_ERROR: Core data matrix mapping failure."))
print(light_warning("WARN: CPU temperature scaling above baseline metrics."))
print(smooth_info("Info: Execution pipeline finished with zero faults."))

📊 Supported Tokens Table

You can seamlessly combine one style modifier, one standard color, and/or one custom Hexadecimal code inside the exact same tag block, separated by a single space character.

Style Token Visual Effect Color Token Representative Palette
bold Bold / High Intensity black Standard Terminal Black
light / dim Faint / Lower Intensity red Standard Terminal Red
italic Italicized Text green Standard Terminal Green
underline Underlined Text yellow Standard Terminal Yellow
blink Blinking Text (If supported) blue Standard Terminal Blue
medium Normal Text Weight / Reset magenta Standard Terminal Magenta
/#HEX True Color Custom Hex (e.g. #FF5500) cyan / white Standard Terminal Cyan / White

🌍 Cross-Platform Compliance

  • Linux / macOS: 100% native out-of-the-box support across any modern terminal engine (Bash, Zsh, Fish).
  • Android (Pydroid 3 / Termux): Rigorously optimized. Layout boundaries do not warp or clip text sequences, guaranteeing aligned matrix tables and UI borders right on your smartphone.
  • Windows: Requires VT100 virtual terminal processing mode activation (handled natively by modern Windows 10/11 environments when initializing Python scripts, or via an internal call to the standard os.system('') module setup).

📄 License

This project is licensed under the MIT License. Feel free to use, modify, and distribute it however you see fit!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

colormax-0.1.0.tar.gz (6.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

colormax-0.1.0-py3-none-any.whl (7.6 kB view details)

Uploaded Python 3

File details

Details for the file colormax-0.1.0.tar.gz.

File metadata

  • Download URL: colormax-0.1.0.tar.gz
  • Upload date:
  • Size: 6.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for colormax-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ce389c50b84a5b76cf253e60fc91e4f4e0609534c18c2a75916def86dca26f6c
MD5 c10ff4ca3747eff28b52b17ce4500e01
BLAKE2b-256 7e560f6385306d81d043496d03e10a81f0405012076cd0906f4bafe09a5b1ae1

See more details on using hashes here.

File details

Details for the file colormax-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: colormax-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 7.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for colormax-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 adb92d43301294dcec9acc8e4d13d38fe5886a54ecbd0561b708bd0dc2bc227c
MD5 4bae20c8c974196051b55beac05a858c
BLAKE2b-256 901db13eab072e1b329c898405b9ec90c504ab1507f1ec4b3f755607cdf3e69a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page