Metadata-Version: 2.4
Name: pyansistring
Version: 0.5.0
Summary: A powerful Python library for terminal string styling, advanced ANSI color manipulation, and SVG terminal rendering.
Project-URL: Repository, https://github.com/l1asis/pyansistring.git
Project-URL: Issues, https://github.com/l1asis/pyansistring/issues
Author: Volodymyr Horshenin
License-Expression: MIT
License-File: LICENSE
Keywords: ansi,ansi-colors,ansi-escape-codes,cli,colorize,colormap,console,data-visualization,debugging,gradients,logging,rich-text,string-styling,svg,terminal,terminal-colors,terminal-graphics,text-formatting,tui
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Logging
Classifier: Topic :: Terminals
Classifier: Topic :: Text Processing
Requires-Python: >=3.11
Requires-Dist: emoji>=2.1.0
Provides-Extra: all
Requires-Dist: fonttools; extra == 'all'
Provides-Extra: svg
Requires-Dist: fonttools; extra == 'svg'
Description-Content-Type: text/markdown

# pyansistring

![pyansistring Banner](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/banner.svg)

[![CI/CD Pipeline](https://github.com/l1asis/pyansistring/actions/workflows/ci-cd.yml/badge.svg)](https://github.com/l1asis/pyansistring/actions)
![Coverage](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fl1asis%2F9f30f8200703cf6886ab323e86b9f0a1%2Fraw%2Fb11b5516d18e6cf01332906bb9bcf3a4ebf14389%2Fpyansistring_coverage.json)
[![PyPI Version](https://img.shields.io/pypi/v/pyansistring.svg)](https://pypi.org/project/pyansistring/)
[![PyPI Python version](https://img.shields.io/pypi/pyversions/pyansistring.svg)](https://pypi.org/project/pyansistring/)
![PyPI downloads](https://img.shields.io/pypi/dm/pyansistring)
[![License](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)

`pyansistring` gives you a string type that keeps styling securely attached while you use familiar, native Python string operations. Whether you are building a simple CLI tool, visualizing data in a complex terminal dashboard, or exporting styled output to the web, `pyansistring` handles the math and formatting for you.

## Features

- **ANSIString class** that subclasses Python `str`.
- **Style-preserving operations** for concatenation, slicing, splitting, joining, replacing, stripping, case transforms, and formatting (f-strings, `.format()`).
- **SGR styling and attributes:** bold, dim, italic, underline, strikethrough, invert, and advanced underline modes (single, double, curly, dotted, dashed).
- **Color channels:** 4-bit ANSI, 8-bit palette, and 24-bit RGB for foreground, background, and underlines.
- **Targeting modes:** apply to full strings, slice ranges, or word matches (case-sensitive or insensitive).
- **Gradient engine:** RGB or HSL interpolation, coordinate-based gradients for multiline text, and out-of-bounds handling.
- **SVG export:** render text or path modes with per-character coloring and optional custom fonts.
- **ANSI parsing:** convert raw ANSI-encoded strings back into `ANSIString` instances with styles intact.
- **Large constants base:** extensive predefined color constants and palettes, plus SGR/regex helpers for easy access.

## Requirements

- Python 3.11+

## Installation

Install the base package:

```bash
pip install pyansistring
```

Install extras when needed:

```bash
pip install pyansistring[svg]            # For SVG export
pip install pyansistring[all]            # Install all optional dependencies
```

## Quick Start

```python
from pyansistring import ANSIString, Foreground, Background, SGR

text = (
    ANSIString("Hello, World!")
    .fg(Foreground.YELLOW)
    .bg(Background.BLUE)
    .style(SGR.BOLD)
)

print(text)
```

## Usage Examples

The examples below are generated by [examples/generate_usage_svg.py](https://github.com/l1asis/pyansistring/blob/main/examples/generate_usage_svg.py).

### Unstyled text

```python
from pyansistring import ANSIString

print(ANSIString("Hello, World!"))
```

![unstyled](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/unstyled.svg)

### Whole string styling

```python
from pyansistring import ANSIString, Foreground, Background, SGR

print(
    ANSIString("Hello, World!")
    .fg(Foreground.YELLOW)
    .bg(Background.BLUE)
    .style(SGR.BOLD)
)
```

![whole](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/whole.svg)

### Target Selectors: Slices

```python
from pyansistring import ANSIString, Foreground, Background, SGR

print(
    ANSIString("Hello, World!")
    .fg(Foreground.YELLOW, (0, 5), (7, 12))
    .bg(Background.BLUE, (7, 12))
    .style(SGR.BOLD, (7, 12))
)
```

![slice](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/slice.svg)

### Target Selectors: Words

```python
from pyansistring import ANSIString, Foreground, Background, SGR, Words

print(
    ANSIString("Hello, World!")
    .fg(Foreground.YELLOW, Words(("Hello", "World")))
    .bg(Background.BLUE, Words(("World",)))
    .style(SGR.BOLD, Words(("Hello", "World")))
)
```

![words](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/words.svg)

### Target Selectors: Chars

```python
from pyansistring import ANSIString, Chars

print(
    ANSIString("Hello, World!")
    .bg((200, 50, 50), Chars(skip_whitespace=True))
    .fg(0)
)
```

![chars](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/chars.svg)

### Target Selectors: Regex Patterns

```python
from pyansistring import ANSIString, NamedColors, Pattern, SGR

print(
    ANSIString("Error 404: Not Found!")
    .fg(NamedColors.RED, Pattern(r"\d+"))
    .style(SGR.BOLD, Pattern(r"\d+"))
)
```

![pattern](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/pattern.svg)

### Advanced Regex (Log Parsing)

```python
from pyansistring import ANSIString, Foreground, Pattern, SGR

print(
    ANSIString("Login: [WARN] User 'admin' failed from 192.168.1.50")
    .fg(Foreground.YELLOW, Pattern(r"\[WARN\]"))
    .fg(Foreground.CYAN, Pattern(r"'.*?'"))
    .style(SGR.UNDERLINE, Pattern(r"\b\d{1,3}(?:\.\d{1,3}){3}\b"))
)
```

![pattern_advanced](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/pattern_advanced.svg)

### SGR attributes

```python
from pyansistring import ANSIString, SGR

print(ANSIString("Hello, World!").style(SGR.BOLD).style(SGR.UNDERLINE))
```

![sgr](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/sgr.svg)

### 4-bit, 8-bit, and 24-bit colors

```python
from pyansistring import ANSIString, Foreground, Background, NamedColors

# 4-bit (Enums)
print(ANSIString("Hello, World!").fg(Foreground.YELLOW).bg(Background.BLUE))
# 8-bit (Integers)
print(ANSIString("Hello, World!").fg(11).bg(4).ul(74))
# 24-bit (Tuples)
print(ANSIString("Hello, World!").fg((255, 255, 0)).bg((0, 0, 238)).ul((135, 175, 215)))
# Web Colors (Named Colors Namespace)
print(ANSIString("Hello, World!").fg(NamedColors.GOLD).bg(NamedColors.MIDNIGHT_BLUE))
```

![4bit](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/4bit.svg)
![8bit](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/8bit.svg)
![rgb](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/rgb.svg)
![named_colors](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/named_colors.svg)

### Underline modes

```python
from pyansistring import ANSIString, UnderlineMode

print(
    ANSIString("Hello, World!")
    .bg((255, 255, 255))
    .ul((255, 0, 0))
    .style(UnderlineMode.DOUBLE)
)
```

![underline](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/underline.svg)

### Rainbow Effect

```python
from pyansistring import ANSIString

print(ANSIString("Hello, World! This is rainbow text!").rainbow())
```

![rainbow](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/rainbow.svg)

### Gradient APIs

```python
from pyansistring import ANSIString, Words, Coords

print(
    ANSIString("Hello, World! This is gradient text!")
    .gradient([(84, 161, 255), (233, 200, 216)])
)

print(
    ANSIString("Hello, colorful gradient world!")
    .gradient([(255, 99, 71), (255, 215, 0)], Words(("Hello", "world"), ignore_case=True))
)

print(
    ANSIString("HELLO\nworld")
    .gradient(
        [(255, 0, 120), (0, 200, 255)],
        Coords(((1, 1), (2, 1), (3, 1), (4, 1), (5, 1)), index_base=1)
    )
)
```

![gradient](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/gradient.svg)  
![gradient_words](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/gradient_words.svg)  
![gradient_coordinates](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/gradient_coordinates.svg)

### Data-Driven Colormaps

```python
from pyansistring import ANSIString, Pattern, NamedColors, Channel
from pyansistring.color import SegmentedColorMap, ColorMap, ColorScale

ramp_text = "".join(f"{n:<5}" for n in range(0, 101, 10))

# Segmented Map (Threshold Snapping)
cmap_seg = SegmentedColorMap({
    0: NamedColors.LIME, 
    60: NamedColors.YELLOW, 
    90: NamedColors.RED
})

print(ANSIString(ramp_text).colormap(cmap_seg, Pattern(r"\d+\s*"), channel=Channel.BG).fg(0))

# Continuous Map (Smooth Interpolation)
scale = ColorScale([(0, 255, 255), (255, 255, 0), (255, 0, 0)], space="hsl")
cmap_cont = ColorMap(scale, vmin=0, vmax=100)

print(ANSIString(ramp_text).colormap(cmap_cont, Pattern(r"\d+\s*"), channel=Channel.BG).fg(0))
```

![colormap_segmented](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/colormap_segmented.svg)  
![colormap_continuous](https://raw.githubusercontent.com/l1asis/pyansistring/refs/heads/main/images/usage/colormap_continuous.svg)  

### Parse ANSI text back into ANSIString

```python
from pyansistring import ANSIString

raw = "\x1b[31mError\x1b[0m: file not found"
parsed = ANSIString.from_ansi(raw)

print(parsed.plain_text)
print(parsed)
```

### Export ANSIString to SVG

```python
from fontTools.ttLib import TTFont
from pyansistring import ANSIString, SGR

font = TTFont("path/to/font.ttf")
styled = ANSIString("SVG output").style(SGR.BOLD).fg((90, 170, 255))

svg_code = styled.to_svg(
    font=font,
    font_size_px=16,
    convert_text_to_path=False,
)
```

For a complete terminal tour, run [examples/showcase.py](https://github.com/l1asis/pyansistring/blob/main/examples/showcase.py).  

## Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.

1. Fork the Project
2. Create your Feature Branch (`git checkout -b feat/amazing-feature`)
3. Commit your Changes (`git commit -m 'feat: ✨ add some amazing-feature'`)
4. Push to the Branch (`git push origin feat/amazing-feature`)
5. Open a Pull Request

> [!IMPORTANT]
> If linting or tests fail, make sure to fix those and push the changes.

## License

Distributed under the MIT License. See `LICENSE` for more information.
