Metadata-Version: 2.3
Name: nyxcore
Version: 0.3.0
Summary: nyx's utility library
Author: verticalsync
Author-email: verticalsync <nightly@riseup.net>
Requires-Python: >=3.14
Project-URL: Homepage, https://github.com/verticalsync/nyxcore
Project-URL: Source, https://github.com/verticalsync/nyxcore
Description-Content-Type: text/markdown

# nyxcore

personal utility library

## modules

| module | description |
|---|---|
| [`nyxcore.color`](#nyxcorecolor) | ANSI color support — named colors, 256-color, true color, Windows compat, auto-strip |
| [`nyxcore.logger`](#nyxcorelogger) | Configurable logger with colored console output, file logging, custom formats |
| [`nyxcore.prompt`](#nyxcoreprompt) | Interactive CLI prompts — confirm, ask, select, checkbox, password |

---

## `nyxcore.color`

ANSI escape code helpers. Zero dependencies.

### colors

| code | `fg` | `bg` |
|---|---|---|
| 30/40 | `fg.black` | `bg.black` |
| 31/41 | `fg.red` | `bg.red` |
| 32/42 | `fg.green` | `bg.green` |
| 33/43 | `fg.yellow` | `bg.yellow` |
| 34/44 | `fg.blue` | `bg.blue` |
| 35/45 | `fg.magenta` | `bg.magenta` |
| 36/46 | `fg.cyan` | `bg.cyan` |
| 37/47 | `fg.white` | `bg.white` |
| 90/100 | `fg.gray` | `bg.gray` |
| 91/101 | `fg.bright_red` | `bg.bright_red` |
| 92/102 | `fg.bright_green` | `bg.bright_green` |
| 93/103 | `fg.bright_yellow` | `bg.bright_yellow` |
| 94/104 | `fg.bright_blue` | `bg.bright_blue` |
| 95/105 | `fg.bright_magenta` | `bg.bright_magenta` |
| 96/106 | `fg.bright_cyan` | `bg.bright_cyan` |
| 97/107 | `fg.bright_white` | `bg.bright_white` |
| 39/49 | `fg.reset` | `bg.reset` |

```python
print(f"{fg.cyan}hello{fg.reset}")
```

### `attr` — text styles

`bold`, `dim`, `italic`, `underline`, `blink`, `reverse`, `hidden`, `strikethrough`

Full list: `bold` (1), `dim` (2), `italic` (3), `underline` (4), `blink` (5), `reverse` (7), `hidden` (8), `strikethrough` (9), `reset` (0), `reset_bold` (22), `reset_italic` (23), `reset_underline` (24), `reset_blink` (25), `reset_reverse` (27).

```python
print(f"{attr.bold}{fg.red}bold red{attr.reset}")
```

### extended colors

| function | description |
|---|---|
| `fg256(code)` | 256-color foreground (0–255) |
| `bg256(code)` | 256-color background |
| `fgrgb(r, g, b)` | 24-bit true color foreground |
| `bgrgb(r, g, b)` | 24-bit true color background |

```python
print(f"{fg256(196)}bright red{fg.reset}")
print(f"{fgrgb(255, 100, 50)}orange{fg.reset}")
```

### `strip(text)`

Remove all ANSI escape sequences.

```python
clean = strip("\x1b[31mhello\x1b[0m")  # "hello"
```

### `init(strip_auto=True)`

Enable Windows console ANSI support. Call once at startup.

On Windows: enables virtual terminal processing via Win32 API.  
When `strip_auto=True`: non-TTY streams (piped/redirected) are wrapped to strip ANSI codes automatically.

```python
from nyxcore.color import init
init()
```

---

## `nyxcore.logger`

Configurable logger on top of stdlib `logging`. Supports colored console output, file output, custom formats.

### `Logger(name, level, *, colorize, fmt, file)`

| param | type | default | description |
|---|---|---|---|
| `name` | `str` | `"nyxcore"` | logger name |
| `level` | `str` or `int` | `"INFO"` | `DEBUG`/`INFO`/`WARNING`/`ERROR`/`CRITICAL` or a `logging` constant |
| `colorize` | `bool` or `None` | auto | `True` = colors on, `False` = plain, `None` = TTY-detect |
| `fmt` | `str` or `None` | default | see format below |
| `file` | `str` or `Path` | `None` | path to a log file (appends) |

```python
from nyxcore.logger import Logger

log = Logger("myapp")
log.info("hello")
log.warning("careful")
log.error("oops")
```

### `set_level(level)`

Change minimum log level at runtime.

```python
log.set_level("DEBUG")
log.debug("now visible")
```

### `add_file(path, level=None)`

Add a file handler after construction. File output is never colorized.

```python
log.add_file("app.log")
log.add_file("errors.log", level="ERROR")
```

### format

Python format specifiers work (`{level:>8}` right-aligns in 8 chars, `{line:04d}` zero-pads).

| placeholder | logging attr | example |
|---|---|---|
| `{time}` | `asctime` | `2026-07-21 18:42:29,755` |
| `{level}` | `levelname` | `INFO` |
| `{levelno}` | `levelno` | `20` |
| `{name}` | `name` | `myapp` |
| `{message}` | `message` | `hello` |
| `{path}` | `pathname` | `/app/src/main.py` |
| `{file}` | `filename` | `main.py` |
| `{module}` | `module` | `main` |
| `{func}` | `funcName` | `connect_db` |
| `{line}` | `lineno` | `42` |
| `{created}` | `created` | `1721590349.755` |
| `{msec}` | `msecs` | `755` |
| `{thread}` | `thread` | `140735248279360` |
| `{thread_name}` | `threadName` | `MainThread` |
| `{process}` | `process` | `12345` |

Default:

```
[{time}] {level:>8} | {name} | {message}
```

Custom:

```python
log = Logger("app", fmt="{level} | {message}")
```

### color map

| level | color |
|---|---|
| `DEBUG` | gray (244) |
| `INFO` | blue (39) |
| `WARNING` | yellow (220) |
| `ERROR` | red (196) |
| `CRITICAL` | bold red |

### examples

```python
# Log to file only
log = Logger("app", colorize=False, file="app.log")

# Log errors separately
log = Logger("app")
log.add_file("app.log", level="DEBUG")
log.add_file("errors.log", level="ERROR")
```

---

## `nyxcore.prompt`

Interactive CLI prompts with customizable colors and formatting.

```python
from nyxcore.prompt import ask, confirm, select, checkbox, password

name = ask("Name", default="user")
ok = confirm("Continue", default=True)
opt = select("Pick color", ["red", "green", "blue"])
tags = checkbox("Select tags", ["urgent", "bug", "feature"], defaults=["bug"])
secret = password("Passphrase")
```

### `Prompt` customization

Create a ``Prompt`` instance to customize appearance.

```python
from nyxcore.color import fg
from nyxcore.prompt import Prompt

p = Prompt(
    prefix=f"{fg.cyan}?{fg.reset} ",
    suffix=" > ",
    default_fmt="({value})",
)
```

| param | type | default | description |
|---|---|---|---|
| `prefix` | `str` | `"? "` | Prompt prefix |
| `error_prefix` | `str` | `"✗ "` | Error message prefix |
| `yes_label` | `str` | `"y"` | Affirmative label in confirm |
| `no_label` | `str` | `"n"` | Negative label in confirm |
| `selected_marker` | `str` | `"● "` | Marker for checked checkbox items |
| `unselected_marker` | `str` | `"○ "` | Marker for unchecked checkbox items |
| `mask` | `str` | `"•"` | Password mask character |
| `hint_style` | `str` | gray | ANSI style for hints/defaults |
| `error_style` | `str` | red | ANSI style for errors |
| `default_fmt` | `str` | `"({value})"` | Format for showing defaults |
| `suffix` | `str` | `" "` | Text after prompt message |

### `confirm(message, *, default)`

Ask a yes/no question.

| param | type | default | description |
|---|---|---|---|
| `message` | `str` | — | Prompt text |
| `default` | `bool` or `None` | `None` | Default answer (`True` = `[Y/n]`, `False` = `[y/N]`) |

```python
ok = p.confirm("Delete?", default=False)
```

### `ask(message, *, default, validate)`

Free-text input.

| param | type | default | description |
|---|---|---|---|
| `message` | `str` | — | Prompt text |
| `default` | `Any` | `None` | Value returned on empty input |
| `validate` | `Callable` | `None` | Receives raw input; return converted value or raise |

```python
age = p.ask("Age", default=18, validate=int)
```

### `select(message, options, *, default)`

Pick one option from a list.

| param | type | default | description |
|---|---|---|---|
| `message` | `str` | — | Prompt text |
| `options` | `list[str]` or `dict[str,str]` | — | Choices (dict maps keys to descriptions) |
| `default` | `str` | `None` | Pre-selected option key |

```python
p.select("Color", ["red", "green"])
p.select("Letter", {"a": "Alpha", "b": "Beta"})
```

### `checkbox(message, options, *, defaults, min_select, max_select)`

Pick multiple options.

| param | type | default | description |
|---|---|---|---|
| `message` | `str` | — | Prompt text |
| `options` | `list[str]` or `dict[str,str]` | — | Choices |
| `defaults` | `list[str]` | `None` | Pre-selected keys |
| `min_select` | `int` | `0` | Minimum required selections |
| `max_select` | `int` or `None` | `None` | Maximum allowed selections |

```python
p.checkbox("Tags", ["urgent", "bug"], min_select=1, max_select=2)
```

### `password(message, *, mask)`

Hidden text input.

| param | type | default | description |
|---|---|---|---|
| `message` | `str` | — | Prompt text |
| `mask` | `str`, `bool`, or `None` | `None` | Mask character; `False` hides all output |

```python
p.password("Passphrase", mask="*")
p.password("Pin", mask=False)  # no echo
```

Standalone functions `confirm()`, `ask()`, `select()`, `checkbox()`, `password()` use a default ``Prompt()`` instance with the same signatures.
