feat: add StatusBar and StreamingStatic widgets

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-11 12:46:52 -05:00
parent 623ed14cbf
commit 202466f73d

65
app/ui/widgets.py Normal file
View 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("")