feat: add StatusBar and StreamingStatic widgets
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
65
app/ui/widgets.py
Normal file
65
app/ui/widgets.py
Normal file
@@ -0,0 +1,65 @@
|
||||
"""Custom Textual widgets for SneakyCode TUI."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from rich.text import Text
|
||||
from textual.widgets import Static
|
||||
|
||||
|
||||
class StatusBar(Static):
|
||||
"""Single-line status bar showing token usage and iteration count."""
|
||||
|
||||
DEFAULT_CSS = """
|
||||
StatusBar {
|
||||
dock: bottom;
|
||||
height: 1;
|
||||
background: $surface;
|
||||
color: $text-muted;
|
||||
padding: 0 2;
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__("")
|
||||
self._tokens: int = 0
|
||||
self._budget: int = 0
|
||||
self._iteration: int = 0
|
||||
self._max_iterations: int = 0
|
||||
|
||||
def update_tokens(self, tokens: int, budget: int) -> None:
|
||||
"""Update the token usage display."""
|
||||
self._tokens = tokens
|
||||
self._budget = budget
|
||||
self._refresh_display()
|
||||
|
||||
def update_iteration(self, iteration: int, max_iterations: int) -> None:
|
||||
"""Update the iteration count display."""
|
||||
self._iteration = iteration
|
||||
self._max_iterations = max_iterations
|
||||
self._refresh_display()
|
||||
|
||||
def _refresh_display(self) -> None:
|
||||
"""Rebuild the status bar text."""
|
||||
parts: list[str] = []
|
||||
if self._budget > 0:
|
||||
parts.append(f"Tokens: ~{self._tokens:,} / {self._budget:,}")
|
||||
if self._max_iterations > 0:
|
||||
parts.append(f"Iteration {self._iteration}/{self._max_iterations}")
|
||||
self.update(Text(" │ ".join(parts), style="dim"))
|
||||
|
||||
|
||||
class StreamingStatic(Static):
|
||||
"""A Static widget that stays mounted but hidden during non-streaming periods.
|
||||
|
||||
During streaming, call show() to make visible and update() with partial content.
|
||||
When streaming ends, call hide() to conceal.
|
||||
"""
|
||||
|
||||
def show_streaming(self) -> None:
|
||||
"""Make the widget visible for streaming."""
|
||||
self.add_class("visible")
|
||||
|
||||
def hide_streaming(self) -> None:
|
||||
"""Hide the widget and clear content."""
|
||||
self.remove_class("visible")
|
||||
self.update("")
|
||||
Reference in New Issue
Block a user