feat(help & spinners): improve help rendering, async spinner handling, and pipeline demo
- Refactored `Command.help_signature` to return `(usage, description, tags)` instead of a Rich `Padding`/`Panel`. - Replaced `show_help()` with `render_help()` in `Command` and `Falyx`. - Updated Falyx help rendering to use Rich `Panel`/`Padding` consistently for cleaner UI. - Swapped `print()` calls for `console.print()` for styled output. - Added hooks to `ProcessAction` to announce analysis start/finish. - Added spinners to test and deploy steps; simplified retry setup. - Converted `remove()` to `async def remove()` for consistency. - Added async lock to prevent concurrent Live loop start/stop races. - Added debug logging when starting/stopping the Live loop. - Updated `spinner_teardown_hook` to `await sm.remove(...)` to align with async `remove()`. - Removed `rich.panel`/`rich.padding` from `Command` since panels are now built in `Falyx` help rendering. - Bumped `rich` dependency to `^14.0`. - Bumped version to 0.1.78. This commit polishes help display, demo UX, and spinner lifecycle safety—making spinners thread/async safe and help output more structured and readable.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
# Falyx CLI Framework — (c) 2025 rtj.dev LLC — MIT Licensed
|
||||
"""
|
||||
Centralized spinner rendering for Falyx CLI.
|
||||
|
||||
@@ -43,13 +44,13 @@ Design Notes:
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import threading
|
||||
|
||||
from rich.console import Group
|
||||
from rich.live import Live
|
||||
from rich.spinner import Spinner
|
||||
|
||||
from falyx.console import console
|
||||
from falyx.logger import logger
|
||||
from falyx.themes import OneColors
|
||||
|
||||
|
||||
@@ -133,7 +134,7 @@ class SpinnerManager:
|
||||
self._task: asyncio.Task | None = None
|
||||
self._running: bool = False
|
||||
|
||||
self._start_lock = threading.Lock()
|
||||
self._lock = asyncio.Lock()
|
||||
|
||||
async def add(
|
||||
self,
|
||||
@@ -150,9 +151,10 @@ class SpinnerManager:
|
||||
spinner_style=spinner_style,
|
||||
spinner_speed=spinner_speed,
|
||||
)
|
||||
with self._start_lock:
|
||||
async with self._lock:
|
||||
if not self._running:
|
||||
self._start_live()
|
||||
logger.debug("[%s] Starting spinner manager Live loop.", name)
|
||||
await self._start_live()
|
||||
|
||||
def update(
|
||||
self,
|
||||
@@ -174,13 +176,17 @@ class SpinnerManager:
|
||||
data.spinner_type = spinner_type
|
||||
data.spinner = Spinner(spinner_type, text=data.text)
|
||||
|
||||
def remove(self, name: str):
|
||||
async def remove(self, name: str):
|
||||
"""Remove a spinner and stop the Live loop if no spinners remain."""
|
||||
self._spinners.pop(name, None)
|
||||
if not self._spinners:
|
||||
self._running = False
|
||||
async with self._lock:
|
||||
if not self._spinners:
|
||||
logger.debug("[%s] Stopping spinner manager, no spinners left.", name)
|
||||
if self._task:
|
||||
self._task.cancel()
|
||||
self._running = False
|
||||
|
||||
def _start_live(self):
|
||||
async def _start_live(self):
|
||||
"""Start the Live rendering loop in the background."""
|
||||
self._running = True
|
||||
self._task = asyncio.create_task(self._live_loop())
|
||||
|
||||
Reference in New Issue
Block a user