mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
template-processor: added "closest_color" support in hooks
This commit is contained in:
@@ -310,3 +310,44 @@ def lab_distance(lab1: LAB, lab2: LAB) -> float:
|
||||
da = lab1[1] - lab2[1]
|
||||
db = lab1[2] - lab2[2]
|
||||
return math.sqrt(dL * dL + da * da + db * db)
|
||||
|
||||
|
||||
def find_closest_color(
|
||||
compare_to: str,
|
||||
colors: list[dict[str, str]]
|
||||
) -> str:
|
||||
"""
|
||||
Find the closest named color from a list (matugen-compatible).
|
||||
|
||||
Uses Lab color space Euclidean distance for perceptual color matching.
|
||||
|
||||
Args:
|
||||
compare_to: Hex color to compare (e.g., "#ff5500")
|
||||
colors: List of {"name": "...", "color": "#..."} dicts
|
||||
|
||||
Returns:
|
||||
Name of the closest color, or empty string if no colors provided
|
||||
"""
|
||||
if not colors:
|
||||
return ""
|
||||
|
||||
# Parse target color
|
||||
target = Color.from_hex(compare_to)
|
||||
target_lab = rgb_to_lab(target.r, target.g, target.b)
|
||||
|
||||
closest_name = ""
|
||||
closest_dist = float('inf')
|
||||
|
||||
for entry in colors:
|
||||
try:
|
||||
entry_color = Color.from_hex(entry["color"])
|
||||
entry_lab = rgb_to_lab(entry_color.r, entry_color.g, entry_color.b)
|
||||
dist = lab_distance(target_lab, entry_lab)
|
||||
if dist < closest_dist:
|
||||
closest_dist = dist
|
||||
closest_name = entry["name"]
|
||||
except (KeyError, ValueError):
|
||||
# Skip invalid entries
|
||||
continue
|
||||
|
||||
return closest_name
|
||||
|
||||
@@ -17,7 +17,7 @@ try:
|
||||
except ImportError:
|
||||
tomllib = None
|
||||
|
||||
from .color import Color
|
||||
from .color import Color, find_closest_color
|
||||
|
||||
|
||||
class TemplateRenderer:
|
||||
@@ -318,6 +318,10 @@ class TemplateRenderer:
|
||||
self._current_file = None
|
||||
return success
|
||||
|
||||
def _substitute_closest_color(self, text: str, closest_color: str) -> str:
|
||||
"""Substitute {{closest_color}} in text."""
|
||||
return re.sub(r"\{\{\s*closest_color\s*\}\}", closest_color, text)
|
||||
|
||||
def process_config_file(self, config_path: Path):
|
||||
"""Process Matugen TOML configuration file."""
|
||||
if not tomllib:
|
||||
@@ -339,10 +343,38 @@ class TemplateRenderer:
|
||||
|
||||
self.render_file(Path(input_path).expanduser(), Path(output_path).expanduser())
|
||||
|
||||
# Handle closest_color if configured (matugen-compatible)
|
||||
closest_color_value = ""
|
||||
colors_to_compare = template.get("colors_to_compare")
|
||||
compare_to = template.get("compare_to")
|
||||
|
||||
if colors_to_compare and compare_to:
|
||||
# Render compare_to to get the actual hex color
|
||||
rendered_compare_to = self.render(compare_to)
|
||||
# Find the closest color name
|
||||
closest_color_value = find_closest_color(rendered_compare_to, colors_to_compare)
|
||||
|
||||
# Execute pre_hook if specified
|
||||
pre_hook = template.get("pre_hook")
|
||||
if pre_hook:
|
||||
import subprocess
|
||||
# Substitute closest_color first, then render color variables
|
||||
if closest_color_value:
|
||||
pre_hook = self._substitute_closest_color(pre_hook, closest_color_value)
|
||||
pre_hook = self.render(pre_hook)
|
||||
try:
|
||||
subprocess.run(pre_hook, shell=True, check=False)
|
||||
except Exception as e:
|
||||
print(f"Error running pre_hook for {name}: {e}", file=sys.stderr)
|
||||
|
||||
# Execute post_hook if specified
|
||||
post_hook = template.get("post_hook")
|
||||
if post_hook:
|
||||
import subprocess
|
||||
# Substitute closest_color first, then render color variables
|
||||
if closest_color_value:
|
||||
post_hook = self._substitute_closest_color(post_hook, closest_color_value)
|
||||
post_hook = self.render(post_hook)
|
||||
try:
|
||||
subprocess.run(post_hook, shell=True, check=False)
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user