scheme: add --json flag to list-presets, --accent flag, drop :accent from preset spec
- list-presets --json outputs structured JSON with variants, modes, accents, and default_accent for accent-aware schemes - --accent flag replaces :accent shorthand in preset string - Validate --accent against variant's available accents - resolve_preset returns tuple[str, str] (scheme + variant only) - Update tests for new signature
This commit is contained in:
@@ -21,8 +21,26 @@ app = typer.Typer()
|
||||
|
||||
|
||||
@app.command()
|
||||
def list_presets():
|
||||
def list_presets(
|
||||
json_format: bool = typer.Option(False, "--json", help="Output in JSON format"),
|
||||
):
|
||||
schemes = list_schemes()
|
||||
if json_format:
|
||||
out = {}
|
||||
for sid, meta in sorted(schemes.items()):
|
||||
variants = {}
|
||||
for v in meta.variants:
|
||||
entry = {"modes": sorted(v.modes)}
|
||||
if v.accents:
|
||||
entry["accents"] = sorted(v.accents)
|
||||
entry["default_accent"] = sorted(v.accents)[0]
|
||||
variants[v.id] = entry
|
||||
out[meta.name] = {
|
||||
"id": sid,
|
||||
"variants": variants,
|
||||
}
|
||||
print(json.dumps({"presets": out}, indent=2))
|
||||
else:
|
||||
for sid, meta in sorted(schemes.items()):
|
||||
var_list = []
|
||||
for v in meta.variants:
|
||||
@@ -41,10 +59,9 @@ def generate(
|
||||
scheme: Optional[str] = typer.Option(
|
||||
None, help="Color scheme algorithm to use for image mode. Ignored in preset mode."
|
||||
),
|
||||
preset: Optional[str] = typer.Option(
|
||||
None, help="Name of a premade scheme in this format: <scheme>:<variant>[:<accent>]"
|
||||
),
|
||||
preset: Optional[str] = typer.Option(None, help="Name of a premade scheme in this format: <scheme>:<variant>"),
|
||||
mode: Optional[str] = typer.Option(None, help="Mode of the preset scheme (dark or light)."),
|
||||
accent: Optional[str] = typer.Option(None, help="Accent for schemes that support it (e.g. mauve)."),
|
||||
):
|
||||
|
||||
HOME = str(os.getenv("HOME"))
|
||||
@@ -473,8 +490,17 @@ def generate(
|
||||
scheme_class = get_scheme_class(scheme)
|
||||
|
||||
if preset:
|
||||
p_scheme, p_variant, p_accent = resolve_preset(preset)
|
||||
palette_obj = get_palette(p_scheme, p_variant, mode or config_mode, accent=p_accent)
|
||||
p_scheme, p_variant = resolve_preset(preset)
|
||||
schemes = list_schemes()
|
||||
if accent and p_scheme in schemes:
|
||||
meta = schemes[p_scheme]
|
||||
var_accents = next((v.accents for v in meta.variants if v.id == p_variant), ())
|
||||
if accent not in var_accents:
|
||||
available = ", ".join(var_accents) if var_accents else "none"
|
||||
raise typer.BadParameter(
|
||||
f"Accent '{accent}' not available for '{p_scheme}:{p_variant}'. Available accents: {available}"
|
||||
)
|
||||
palette_obj = get_palette(p_scheme, p_variant, mode or config_mode, accent=accent)
|
||||
colors = palette_obj.colors
|
||||
effective_mode = palette_obj.mode
|
||||
name = palette_obj.scheme
|
||||
|
||||
@@ -132,12 +132,10 @@ def list_schemes() -> dict[str, SchemeMeta]:
|
||||
return dict(SCHEMES)
|
||||
|
||||
|
||||
def resolve_preset(spec: str) -> tuple[str, str, str | None]:
|
||||
def resolve_preset(spec: str) -> tuple[str, str]:
|
||||
parts = spec.split(":")
|
||||
if len(parts) == 3:
|
||||
return parts[0], parts[1], parts[2]
|
||||
if len(parts) == 2:
|
||||
return parts[0], parts[1], None
|
||||
return parts[0], parts[1]
|
||||
if len(parts) == 1:
|
||||
return parts[0], "default", None
|
||||
raise ValueError(f"Invalid preset spec '{spec}'. Use <scheme>:<variant>[:<accent>]")
|
||||
return parts[0], "default"
|
||||
raise ValueError(f"Invalid preset spec '{spec}'. Use <scheme>:<variant>")
|
||||
|
||||
@@ -154,13 +154,14 @@ class TestListSchemes:
|
||||
|
||||
class TestResolvePreset:
|
||||
def test_two_parts(self):
|
||||
assert sp.resolve_preset("gruvbox:medium") == ("gruvbox", "medium", None)
|
||||
assert sp.resolve_preset("gruvbox:medium") == ("gruvbox", "medium")
|
||||
|
||||
def test_three_parts(self):
|
||||
assert sp.resolve_preset("catppuccin:mocha:mauve") == ("catppuccin", "mocha", "mauve")
|
||||
with pytest.raises(ValueError, match="Invalid preset spec"):
|
||||
sp.resolve_preset("catppuccin:mocha:mauve")
|
||||
|
||||
def test_one_part(self):
|
||||
assert sp.resolve_preset("default") == ("default", "default", None)
|
||||
assert sp.resolve_preset("default") == ("default", "default")
|
||||
|
||||
def test_edge_spaces(self):
|
||||
assert sp.resolve_preset(" catppuccin : mocha : mauve ") == (" catppuccin ", " mocha ", " mauve ")
|
||||
assert sp.resolve_preset(" catppuccin : mocha ") == (" catppuccin ", " mocha ")
|
||||
|
||||
Reference in New Issue
Block a user