rich-gradient-cli 0.1.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. rich_gradient_cli-0.3.0/PKG-INFO +153 -0
  2. rich_gradient_cli-0.1.0/PKG-INFO → rich_gradient_cli-0.3.0/README.md +47 -22
  3. rich_gradient_cli-0.3.0/pyproject.toml +59 -0
  4. rich_gradient_cli-0.3.0/pyproject.toml.orig +53 -0
  5. {rich_gradient_cli-0.1.0 → rich_gradient_cli-0.3.0}/src/rich_gradient_cli/__init__.py +55 -9
  6. rich_gradient_cli-0.3.0/src/rich_gradient_cli/common.py +189 -0
  7. rich_gradient_cli-0.3.0/src/rich_gradient_cli/gradient_command.py +139 -0
  8. {rich_gradient_cli-0.1.0 → rich_gradient_cli-0.3.0}/src/rich_gradient_cli/help.py +12 -1
  9. {rich_gradient_cli-0.1.0 → rich_gradient_cli-0.3.0}/src/rich_gradient_cli/markdown_command.py +49 -4
  10. {rich_gradient_cli-0.1.0 → rich_gradient_cli-0.3.0}/src/rich_gradient_cli/panel_command.py +52 -11
  11. rich_gradient_cli-0.3.0/src/rich_gradient_cli/renderable_commands.py +443 -0
  12. {rich_gradient_cli-0.1.0 → rich_gradient_cli-0.3.0}/src/rich_gradient_cli/rule_command.py +62 -0
  13. rich_gradient_cli-0.3.0/src/rich_gradient_cli/spectrum_command.py +82 -0
  14. {rich_gradient_cli-0.1.0 → rich_gradient_cli-0.3.0}/src/rich_gradient_cli/text_command.py +62 -1
  15. rich_gradient_cli-0.3.0/src/rich_gradient_cli/view_command.py +590 -0
  16. rich_gradient_cli-0.1.0/README.md +0 -88
  17. rich_gradient_cli-0.1.0/pyproject.toml +0 -31
  18. rich_gradient_cli-0.1.0/src/rich_gradient_cli/common.py +0 -87
  19. {rich_gradient_cli-0.1.0 → rich_gradient_cli-0.3.0}/src/rich_gradient_cli/__main__.py +0 -0
  20. {rich_gradient_cli-0.1.0 → rich_gradient_cli-0.3.0}/src/rich_gradient_cli/py.typed +0 -0
@@ -0,0 +1,153 @@
1
+ Metadata-Version: 2.3
2
+ Name: rich-gradient-cli
3
+ Version: 0.3.0
4
+ Summary: CLI for printing text in gradient color using the rich-gradient library.
5
+ Author: Maxwell Ludden
6
+ Author-email: Maxwell Ludden <maxludden@me.com>
7
+ Requires-Dist: typer>=0.21.1
8
+ Requires-Dist: rich>=14.3.2
9
+ Requires-Dist: rich-color-ext>=0.1.9
10
+ Requires-Dist: rich-gradient>=0.3.9
11
+ Requires-Dist: mypy>=1.18.2 ; extra == 'dev'
12
+ Requires-Dist: pytest>=8.4.2 ; extra == 'dev'
13
+ Requires-Dist: ruff>=0.15.0 ; extra == 'dev'
14
+ Requires-Dist: mkdocstrings>=1.0.8 ; python_full_version >= '3.11' and extra == 'docs'
15
+ Requires-Dist: mkdocstrings-python>=2.0.2 ; python_full_version >= '3.11' and extra == 'docs'
16
+ Requires-Dist: zensical>=0.0.68 ; python_full_version >= '3.11' and extra == 'docs'
17
+ Requires-Python: >=3.10
18
+ Provides-Extra: dev
19
+ Provides-Extra: docs
20
+ Description-Content-Type: text/markdown
21
+
22
+ # rich-gradient-cli
23
+
24
+ `rich-gradient-cli` is a CLI for [`rich-gradient`](https://github.com/maxludden/rich-gradient). The tool allows you to create colorful gradients in your terminal output, making it easier to visualize data or simply add some flair to your command-line applications.
25
+
26
+ ## Installation
27
+
28
+ You can install rich-gradient-cli from PyPI
29
+
30
+ ### uv (recommended)
31
+
32
+ ```shell
33
+ uv add rich-gradient-cli
34
+ ```
35
+
36
+ ### pip
37
+
38
+ ```shell
39
+ pip install rich-gradient-cli
40
+ ```
41
+
42
+ ## Usage
43
+
44
+ <video
45
+ src="docs/img/rich-gradient-cli-help.mp4"
46
+ controls
47
+ muted
48
+ loop>
49
+ </video>
50
+
51
+ ### Print
52
+
53
+ To use the `rich-gradient-cli`, you can run the following command in your terminal:
54
+
55
+ ```bash
56
+ gradient print --colors 'red,#ff9900,#ffff00' "This is gradient text that starts red, transitions through orange, and ends in yellow\!"
57
+ ```
58
+
59
+ ![Gradient Text Example](print-example.svg)
60
+
61
+ ### Gradient
62
+
63
+ Use `gradient` for the generic `rich-gradient` renderable, including highlight rules and animation:
64
+
65
+ ```bash
66
+ gradient gradient --colors 'magenta,cyan' --highlight-word error='bold white on red' "Highlight error text"
67
+ ```
68
+
69
+ ### Spectrum
70
+
71
+ Inspect generated spectrum colors as a rich table, hex values, names, or CSV:
72
+
73
+ ```bash
74
+ gradient spectrum --hues 7 --seed 42
75
+ gradient spectrum --hues 7 --output hex
76
+ ```
77
+
78
+ ### Rich renderables
79
+
80
+ Wrap common Rich renderables in gradients without writing Python:
81
+
82
+ ```bash
83
+ gradient columns alpha beta gamma --colors 'red,blue'
84
+ gradient tree project src/app.py docs/index.md --colors 'lime,cyan'
85
+ gradient syntax pyproject.toml --lexer toml --line-numbers --colors 'yellow,magenta'
86
+ cat data.csv | gradient table - --colors 'cyan,magenta'
87
+ ```
88
+
89
+ ### Rule
90
+
91
+ You can also create gradient rules using the `rule` command:
92
+
93
+ ```bash
94
+ gradient rule --colors 'blue,#00ff00,cyan' "Blue to Green to Cyan Rule"
95
+ ```
96
+
97
+ ![Gradient Rule Example](rule-example.svg)
98
+
99
+ ### Panel
100
+
101
+ To create a gradient panel, you can use the `panel` command:
102
+
103
+ ```bash
104
+ gradient panel --colors "red,#ff9999" -t "Error" --title-style "bold #ffffff" --title-align left 'This is an error message with a red to pink gradient background.'
105
+ ```
106
+
107
+ ![Gradient Panel Example](panel-example.svg)
108
+
109
+ ### Markdown
110
+
111
+ You can also render Markdown with gradients:
112
+
113
+ ```bash
114
+ echo "# Hello\n\n- This is **bold**.\n- This is *italic*." | gradient markdown -
115
+ ```
116
+
117
+ ![Gradient Markdown Example](markdown-example.svg)
118
+
119
+ ### Rich-style viewing
120
+
121
+ Use `view` for `rich-cli`-style file rendering. It auto-detects Markdown, JSON, CSV/TSV, and syntax-highlighted source files; it also accepts `-` for stdin and `http://` or `https://` URLs.
122
+
123
+ ```bash
124
+ gradient view README.md
125
+ gradient view pyproject.toml --lexer toml --line-numbers --guides
126
+ cat data.json | gradient view - --json --force-terminal
127
+ gradient view README.md --export-html readme.html
128
+ ```
129
+
130
+ ## Docs
131
+
132
+ Build and preview the documentation locally with Zensical (requires Python 3.11+; the `docs` extra is skipped on 3.10):
133
+
134
+ ```bash
135
+ uv pip install -e ".[docs]"
136
+ zensical serve
137
+ ```
138
+
139
+
140
+
141
+ <div align="center">
142
+ <a href="https://github.com/maxludden/maxludden" style="text-decoration:none; color:inherit;">
143
+ <p>Designed by Max Ludden</p>
144
+ </a>
145
+ <br />
146
+ <a href="https://github.com/maxludden/maxludden" style="text-decoration:none; color:inherit;">
147
+ <img
148
+ src="docs/img/MaxLogo.svg"
149
+ alt="Max Ludden's Logo"
150
+ width="20%"
151
+ />
152
+ </a>
153
+ </div>
@@ -1,22 +1,3 @@
1
- Metadata-Version: 2.3
2
- Name: rich-gradient-cli
3
- Version: 0.1.0
4
- Summary: CLI for printing text in gradient color using the rich-gradient library.
5
- Author: Maxwell Ludden
6
- Author-email: Maxwell Ludden <maxludden@me.com>
7
- Requires-Dist: typer>=0.21.1
8
- Requires-Dist: rich>=14.3.2
9
- Requires-Dist: rich-color-ext>=0.1.9
10
- Requires-Dist: rich-gradient>=0.3.9
11
- Requires-Dist: ruff>=0.15.0
12
- Requires-Dist: mkdocs>=1.6.0 ; extra == 'docs'
13
- Requires-Dist: mkdocs-material>=9.5.0 ; extra == 'docs'
14
- Requires-Dist: mkdocstrings>=0.25.0 ; extra == 'docs'
15
- Requires-Dist: mkdocstrings-python>=1.10.0 ; extra == 'docs'
16
- Requires-Python: >=3.14
17
- Provides-Extra: docs
18
- Description-Content-Type: text/markdown
19
-
20
1
  # rich-gradient-cli
21
2
 
22
3
  `rich-gradient-cli` is a CLI for [`rich-gradient`](https://github.com/maxludden/rich-gradient). The tool allows you to create colorful gradients in your terminal output, making it easier to visualize data or simply add some flair to your command-line applications.
@@ -39,6 +20,12 @@ pip install rich-gradient-cli
39
20
 
40
21
  ## Usage
41
22
 
23
+ <video
24
+ src="docs/img/rich-gradient-cli-help.mp4"
25
+ controls
26
+ muted
27
+ loop>
28
+ </video>
42
29
 
43
30
  ### Print
44
31
 
@@ -50,6 +37,33 @@ gradient print --colors 'red,#ff9900,#ffff00' "This is gradient text that starts
50
37
 
51
38
  ![Gradient Text Example](print-example.svg)
52
39
 
40
+ ### Gradient
41
+
42
+ Use `gradient` for the generic `rich-gradient` renderable, including highlight rules and animation:
43
+
44
+ ```bash
45
+ gradient gradient --colors 'magenta,cyan' --highlight-word error='bold white on red' "Highlight error text"
46
+ ```
47
+
48
+ ### Spectrum
49
+
50
+ Inspect generated spectrum colors as a rich table, hex values, names, or CSV:
51
+
52
+ ```bash
53
+ gradient spectrum --hues 7 --seed 42
54
+ gradient spectrum --hues 7 --output hex
55
+ ```
56
+
57
+ ### Rich renderables
58
+
59
+ Wrap common Rich renderables in gradients without writing Python:
60
+
61
+ ```bash
62
+ gradient columns alpha beta gamma --colors 'red,blue'
63
+ gradient tree project src/app.py docs/index.md --colors 'lime,cyan'
64
+ gradient syntax pyproject.toml --lexer toml --line-numbers --colors 'yellow,magenta'
65
+ cat data.csv | gradient table - --colors 'cyan,magenta'
66
+ ```
53
67
 
54
68
  ### Rule
55
69
 
@@ -81,13 +95,24 @@ echo "# Hello\n\n- This is **bold**.\n- This is *italic*." | gradient markdown -
81
95
 
82
96
  ![Gradient Markdown Example](markdown-example.svg)
83
97
 
98
+ ### Rich-style viewing
99
+
100
+ Use `view` for `rich-cli`-style file rendering. It auto-detects Markdown, JSON, CSV/TSV, and syntax-highlighted source files; it also accepts `-` for stdin and `http://` or `https://` URLs.
101
+
102
+ ```bash
103
+ gradient view README.md
104
+ gradient view pyproject.toml --lexer toml --line-numbers --guides
105
+ cat data.json | gradient view - --json --force-terminal
106
+ gradient view README.md --export-html readme.html
107
+ ```
108
+
84
109
  ## Docs
85
110
 
86
- Build and preview the documentation locally with MkDocs:
111
+ Build and preview the documentation locally with Zensical (requires Python 3.11+; the `docs` extra is skipped on 3.10):
87
112
 
88
113
  ```bash
89
114
  uv pip install -e ".[docs]"
90
- mkdocs serve
115
+ zensical serve
91
116
  ```
92
117
 
93
118
 
@@ -99,7 +124,7 @@ mkdocs serve
99
124
  <br />
100
125
  <a href="https://github.com/maxludden/maxludden" style="text-decoration:none; color:inherit;">
101
126
  <img
102
- src="https://github.com/maxludden/maxludden/blob/f3913ecf11f90c97435e2b55d2e43dadd51c1fe4/Images/MaxLogo-animated.svg"
127
+ src="docs/img/MaxLogo.svg"
103
128
  alt="Max Ludden's Logo"
104
129
  width="20%"
105
130
  />
@@ -0,0 +1,59 @@
1
+ [project]
2
+ name = "rich-gradient-cli"
3
+ version = "0.3.0"
4
+ description = "CLI for printing text in gradient color using the rich-gradient library."
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ dependencies = [
8
+ "typer>=0.21.1",
9
+ "rich>=14.3.2",
10
+ "rich-color-ext>=0.1.9",
11
+ "rich-gradient>=0.3.9",
12
+ ]
13
+
14
+ [[project.authors]]
15
+ name = "Maxwell Ludden"
16
+ email = "maxludden@me.com"
17
+
18
+ [project.optional-dependencies]
19
+ dev = [
20
+ "mypy>=1.18.2",
21
+ "pytest>=8.4.2",
22
+ "ruff>=0.15.0",
23
+ ]
24
+ docs = [
25
+ "mkdocstrings>=1.0.8; python_version >= '3.11'",
26
+ "mkdocstrings-python>=2.0.2; python_version >= '3.11'",
27
+ "zensical>=0.0.68; python_version >= '3.11'",
28
+ ]
29
+
30
+ [project.scripts]
31
+ gradient = "rich_gradient_cli:entrypoint"
32
+
33
+ [build-system]
34
+ requires = ["uv_build>=0.10.0,<0.11.0"]
35
+ build-backend = "uv_build"
36
+
37
+ [tool.mypy]
38
+ python_version = "3.10"
39
+ mypy_path = "typings"
40
+ files = [
41
+ "src",
42
+ "typings",
43
+ ]
44
+ ignore_missing_imports = true
45
+ check_untyped_defs = true
46
+
47
+ [tool.ruff]
48
+ target-version = "py310"
49
+ src = [
50
+ "src",
51
+ "typings",
52
+ ]
53
+
54
+ [tool.pylint.messages_control]
55
+ disable = [
56
+ "import-error",
57
+ "unused-argument",
58
+ "W0613",
59
+ ]
@@ -0,0 +1,53 @@
1
+ [project]
2
+ name = "rich-gradient-cli"
3
+ version = "0.3.0"
4
+ description = "CLI for printing text in gradient color using the rich-gradient library."
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Maxwell Ludden", email = "maxludden@me.com" }
8
+ ]
9
+ requires-python = ">=3.10"
10
+ dependencies = [
11
+ "typer>=0.21.1",
12
+ "rich>=14.3.2",
13
+ "rich-color-ext>=0.1.9",
14
+ "rich-gradient>=0.3.9",
15
+ ]
16
+
17
+ [project.optional-dependencies]
18
+ dev = [
19
+ "mypy>=1.18.2",
20
+ "pytest>=8.4.2",
21
+ "ruff>=0.15.0",
22
+ ]
23
+ # Docs tooling (mkdocstrings>=1.0.8, zensical) requires Python >= 3.11; on 3.10 this extra installs nothing.
24
+ docs = [
25
+ "mkdocstrings>=1.0.8; python_version >= '3.11'",
26
+ "mkdocstrings-python>=2.0.2; python_version >= '3.11'",
27
+ "zensical>=0.0.68; python_version >= '3.11'",
28
+ ]
29
+
30
+ [project.scripts]
31
+ gradient = "rich_gradient_cli:entrypoint"
32
+
33
+ [build-system]
34
+ requires = ["uv_build>=0.10.0,<0.11.0"]
35
+ build-backend = "uv_build"
36
+
37
+ [tool.mypy]
38
+ python_version = "3.10"
39
+ mypy_path = "typings"
40
+ files = ["src", "typings"]
41
+ ignore_missing_imports = true
42
+ check_untyped_defs = true
43
+
44
+ [tool.ruff]
45
+ target-version = "py310"
46
+ src = ["src", "typings"]
47
+
48
+ [tool.pylint.messages_control]
49
+ disable = [
50
+ "import-error",
51
+ "unused-argument",
52
+ "W0613"
53
+ ]
@@ -3,17 +3,45 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import sys
6
+ from pathlib import Path
6
7
  from typing import Any, Sequence
7
8
 
8
9
  import click
9
10
  import typer
10
11
 
11
- from .common import VERSION
12
- from .help import RichTyperCommand, RichTyperGroup
13
- from .markdown_command import markdown_command
14
- from .panel_command import panel_command
15
- from .rule_command import rule_command
16
- from .text_command import print_command
12
+ if __package__ in {None, ""}:
13
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
14
+ from rich_gradient_cli.common import VERSION
15
+ from rich_gradient_cli.gradient_command import gradient_command
16
+ from rich_gradient_cli.help import RichTyperCommand, RichTyperGroup
17
+ from rich_gradient_cli.markdown_command import markdown_command
18
+ from rich_gradient_cli.panel_command import panel_command
19
+ from rich_gradient_cli.renderable_commands import (
20
+ columns_command,
21
+ syntax_command,
22
+ table_command,
23
+ tree_command,
24
+ )
25
+ from rich_gradient_cli.rule_command import rule_command
26
+ from rich_gradient_cli.spectrum_command import spectrum_command
27
+ from rich_gradient_cli.text_command import print_command
28
+ from rich_gradient_cli.view_command import view_command
29
+ else:
30
+ from .common import VERSION
31
+ from .gradient_command import gradient_command
32
+ from .help import RichTyperCommand, RichTyperGroup
33
+ from .markdown_command import markdown_command
34
+ from .panel_command import panel_command
35
+ from .renderable_commands import (
36
+ columns_command,
37
+ syntax_command,
38
+ table_command,
39
+ tree_command,
40
+ )
41
+ from .rule_command import rule_command
42
+ from .spectrum_command import spectrum_command
43
+ from .text_command import print_command
44
+ from .view_command import view_command
17
45
 
18
46
 
19
47
  class DefaultTyperGroup(RichTyperGroup):
@@ -32,6 +60,7 @@ class DefaultTyperGroup(RichTyperGroup):
32
60
  default_cmd_name: str = "print",
33
61
  **kwargs: Any,
34
62
  ) -> None:
63
+ """Initialize the group with a default command name fallback."""
35
64
  super().__init__(
36
65
  name=name,
37
66
  commands=commands,
@@ -42,11 +71,12 @@ class DefaultTyperGroup(RichTyperGroup):
42
71
  result_callback=result_callback,
43
72
  **kwargs,
44
73
  )
45
- self.default_cmd_name = default_cmd_name
74
+ self.default_cmd_name: str = default_cmd_name
46
75
 
47
76
  def resolve_command(
48
77
  self, ctx: click.Context, args: list[str]
49
78
  ) -> tuple[str | None, click.Command | None, list[str]]:
79
+ """Resolve the command, routing unknown input to the default command."""
50
80
  if args:
51
81
  cmd = self.get_command(ctx, args[0])
52
82
  if cmd is None or args[0].startswith("-"):
@@ -60,7 +90,7 @@ app = typer.Typer(
60
90
  add_completion=False,
61
91
  help="Create gradient-rich text, panels, and markdown.",
62
92
  rich_markup_mode="rich",
63
- context_settings={"help_option_names": ["-h", "--help"], "color": True},
93
+ context_settings={"help_option_names": ["--help"], "color": True},
64
94
  )
65
95
 
66
96
 
@@ -86,11 +116,27 @@ def main(
86
116
 
87
117
 
88
118
  app.command("print", cls=RichTyperCommand)(print_command)
119
+ app.command("gradient", cls=RichTyperCommand)(gradient_command)
120
+ app.command("columns", cls=RichTyperCommand)(columns_command)
89
121
  app.command("panel", cls=RichTyperCommand)(panel_command)
90
122
  app.command("rule", cls=RichTyperCommand)(rule_command)
91
123
  app.command("markdown", cls=RichTyperCommand)(markdown_command)
124
+ app.command("spectrum", cls=RichTyperCommand)(spectrum_command)
125
+ app.command("syntax", cls=RichTyperCommand)(syntax_command)
126
+ app.command("table", cls=RichTyperCommand)(table_command)
127
+ app.command("tree", cls=RichTyperCommand)(tree_command)
128
+ app.command("view", cls=RichTyperCommand)(view_command)
92
129
 
93
130
 
94
131
  cli = app
95
132
 
96
- __all__ = ["app", "cli"]
133
+
134
+ def entrypoint() -> None:
135
+ """Run the Typer CLI application."""
136
+ app()
137
+
138
+ __all__ = ["app", "cli", "entrypoint"]
139
+
140
+
141
+ if __name__ == "__main__":
142
+ entrypoint()
@@ -0,0 +1,189 @@
1
+ """Shared helpers and configuration for the rich-gradient CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from importlib.metadata import PackageNotFoundError, version
6
+ from pathlib import Path
7
+ from typing import Any, List, Mapping, Optional, Sequence, cast
8
+
9
+ from rich.console import Console, RenderableType
10
+ from rich.padding import Padding
11
+ from rich.style import Style
12
+ from rich_gradient.animated_gradient import AnimatedGradient
13
+ from rich_gradient.gradient import Gradient
14
+ from rich_gradient.theme import GRADIENT_TERMINAL_THEME
15
+
16
+ console = Console()
17
+ try:
18
+ VERSION = version("rich-gradient-cli")
19
+ except PackageNotFoundError:
20
+ VERSION = "0.0.0"
21
+
22
+ HEADER_TEXT = (
23
+ "[#ff5500]r[/][#ff6f00]i[/][#ff8300]c[/]"
24
+ "[#ff9500]h[/][#ffa600]-[/][#ffb600]g[/][#ffc500]r[/]"
25
+ "[#ffd400]a[/][#ffe500]d[/][#fff400]i[/][#f9ff00]e[/]"
26
+ "[#e2ff00]n[/][#c8ff00]t[/][#a9ff00] [/][bold #fff]CLI[/]"
27
+ )
28
+
29
+ FOOTER_TEXT = (
30
+ "[#ff5500]\U0001f308[/][#ff7400] [/][#ff8c00]h[/]"
31
+ "[#ffa100]t[/][#ffb500]t[/][#ffc700]p[/][#ffdc00]s[/]"
32
+ "[#ffef00]:[/][#fbff00]/[/][#dfff00]/[/][#bdff00]m[/]"
33
+ "[#9aff00]a[/][#73ff00]x[/][#2aff00]l[/][#00ff5c]u[/]"
34
+ "[#00ff83]d[/][#00ffa6]d[/][#00ffd1]e[/][#00fff3]n[/]"
35
+ "[#00f4ff].[/][#00e1ff]g[/][#00ccff]i[/][#00baff]t[/]"
36
+ "[#00a6ff]h[/][#2192ff]u[/][#3b81ff]b[/][#4c6cff].[/]"
37
+ "[#6061ff]i[/][#725bff]o[/][#8253ff]/[/][#9648ff]r[/]"
38
+ "[#a83bff]i[/][#c22eff]c[/][#e122ff]h[/][#fb0cff]-[/]"
39
+ "[#ff00e6]g[/][#ff00c6]r[/][#ff00a4]a[/][#ff0089]d[/]"
40
+ "[#ff0066]i[/][#ff004b]e[/][#ff0036]n[/][#ff0000]t[/]"
41
+ )
42
+
43
+
44
+ USAGE_PREFIX = "[bold #00ff00]Usage:[/]"
45
+ USAGE_PROG_STYLE = "#af00ff"
46
+ USAGE_CMD_STYLE = "#0099ff"
47
+ USAGE_BRACKET_STYLE = "#ffffff"
48
+
49
+
50
+ def parse_colors(colors: Optional[str]) -> Optional[List[str]]:
51
+ """Parse comma-separated color tokens into a list."""
52
+ if colors is None:
53
+ return None
54
+ return [c.strip() for c in colors.split(",") if c.strip()]
55
+
56
+
57
+ def parse_style(style: Optional[str]) -> Style:
58
+ """Parse a Rich style string or return a null style."""
59
+ if style is None:
60
+ return Style.null()
61
+ return Style.parse(style)
62
+
63
+
64
+ def parse_mapping_options(values: Optional[Sequence[str]]) -> Optional[Mapping[str, str]]:
65
+ """Parse repeated KEY=VALUE CLI options into a mapping."""
66
+ if not values:
67
+ return None
68
+
69
+ parsed: dict[str, str] = {}
70
+ for value in values:
71
+ key, separator, item_value = value.partition("=")
72
+ key = key.strip()
73
+ item_value = item_value.strip()
74
+ if not separator or not key or not item_value:
75
+ raise ValueError(f"Expected KEY=VALUE, got {value!r}.")
76
+ parsed[key] = item_value
77
+ return parsed
78
+
79
+
80
+ def parse_padding(padding: Optional[str]) -> int | tuple[int, ...] | None:
81
+ """Parse Rich padding shorthand from a CLI string."""
82
+ if padding is None:
83
+ return None
84
+
85
+ parts = tuple(int(part) for part in padding.split(",") if part.strip())
86
+ if len(parts) not in {1, 2, 4}:
87
+ raise ValueError("Padding must contain 1, 2, or 4 comma-separated integers.")
88
+ if len(parts) == 1:
89
+ return parts[0]
90
+ return parts
91
+
92
+
93
+ def export_svg(
94
+ renderable: RenderableType, svg_path: str, *, end: str = "\n", no_wrap: bool = False
95
+ ) -> None:
96
+ """Render a Rich renderable to an SVG file."""
97
+ svg_console = Console(record=True, force_terminal=True, color_system="truecolor")
98
+ padded = Padding(renderable, (1, 4))
99
+ svg_console.print(padded, end=end, no_wrap=no_wrap)
100
+
101
+ Path(svg_path).write_text(
102
+ svg_console.export_svg(
103
+ title="rich-gradient",
104
+ theme=GRADIENT_TERMINAL_THEME,
105
+ ),
106
+ encoding="utf-8",
107
+ )
108
+
109
+
110
+ def render_gradient_output(
111
+ renderable: RenderableType,
112
+ *,
113
+ colors: Optional[str] = None,
114
+ bgcolors: Optional[str] = None,
115
+ rainbow: bool = False,
116
+ hues: int = 5,
117
+ expand: bool = True,
118
+ justify: str = "left",
119
+ vertical_justify: str = "middle",
120
+ repeat_scale: float = 2.0,
121
+ highlight_words: Optional[Sequence[str]] = None,
122
+ highlight_regex: Optional[Sequence[str]] = None,
123
+ end: str = "\n",
124
+ animate: bool = False,
125
+ duration: Optional[float] = None,
126
+ svg: Optional[str] = None,
127
+ ) -> None:
128
+ """Render any Rich renderable through rich-gradient's Gradient wrapper."""
129
+ fg_list = parse_colors(colors)
130
+ bg_list = parse_colors(bgcolors)
131
+ highlight_word_map = parse_mapping_options(highlight_words)
132
+ highlight_regex_map = parse_mapping_options(highlight_regex)
133
+
134
+ if animate and svg:
135
+ raise ValueError("--svg is not supported with --animate.")
136
+ if animate and console.is_terminal is True:
137
+ animated = AnimatedGradient(
138
+ cast(Any, renderable),
139
+ colors=cast(Any, fg_list),
140
+ bg_colors=cast(Any, bg_list),
141
+ hues=hues,
142
+ rainbow=rainbow,
143
+ expand=expand,
144
+ justify=cast(Any, justify),
145
+ vertical_justify=cast(Any, vertical_justify),
146
+ repeat_scale=repeat_scale,
147
+ highlight_words=highlight_word_map,
148
+ highlight_regex=highlight_regex_map,
149
+ animate=True,
150
+ duration=duration,
151
+ )
152
+ animated.run()
153
+ return
154
+
155
+ gradient = Gradient(
156
+ cast(Any, renderable),
157
+ colors=cast(Any, fg_list),
158
+ bg_colors=cast(Any, bg_list),
159
+ hues=hues,
160
+ rainbow=rainbow,
161
+ expand=expand,
162
+ justify=cast(Any, justify),
163
+ vertical_justify=cast(Any, vertical_justify),
164
+ repeat_scale=repeat_scale,
165
+ highlight_words=highlight_word_map,
166
+ highlight_regex=highlight_regex_map,
167
+ )
168
+ if svg:
169
+ export_svg(gradient, svg, end=end)
170
+ return
171
+ console.print(gradient, end=end)
172
+
173
+
174
+ __all__ = [
175
+ "VERSION",
176
+ "console",
177
+ "parse_colors",
178
+ "parse_mapping_options",
179
+ "parse_padding",
180
+ "parse_style",
181
+ "render_gradient_output",
182
+ "HEADER_TEXT",
183
+ "FOOTER_TEXT",
184
+ "USAGE_PREFIX",
185
+ "USAGE_PROG_STYLE",
186
+ "USAGE_CMD_STYLE",
187
+ "USAGE_BRACKET_STYLE",
188
+ "export_svg",
189
+ ]