-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Problem/Context
During upstream merges, the TUI spinner customizations became inconsistent across the application. While the configurable spinner system exists and works for some components (bash tool, sidebar, session loading), it's not being used in two key places:
- Prompt loading indicator (
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx:1268) - Uses a hardcoded Knight Rider style spinner fromui/spinner.tsinstead of the user-configurable spinner - Session list dialog (
packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx:28,52) - Uses hardcoded braille frames["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]instead of the user's selected spinner
This means users who customize their spinner style via the "Change spinner style" command (spinner.style) or interval (spinner.interval) won't see their preferences reflected consistently.
Current State
Configurable Spinner System (Working)
- Location:
packages/opencode/src/cli/cmd/tui/util/spinners.ts - Used by:
- Bash tool output (
session/index.tsx:2245) - Session loading indicator (
session/index.tsx:1422) - Sidebar active session indicator (
sidebar.tsx:217) - ToolTitle component (
session/index.tsx:2167)
- Bash tool output (
- Features:
- 60+ spinner styles (braille, blocks, emoji, etc.)
- Configurable interval (20ms-500ms)
- Persisted via KV store
Not Using Configurable System
| Location | Current Implementation | Issue |
|---|---|---|
prompt/index.tsx:1268 |
<spinner ... frames={spinnerDef().frames}> |
Uses Knight Rider createFrames() from ui/spinner.ts |
dialog-session-list.tsx:28 |
Hardcoded ["⠋", "⠙", ...] array |
Never reads user preference |
Acceptance Criteria
- User's spinner style preference from "Change spinner style" is used in the prompt loading area
- User's spinner style preference is used in the session list dialog
- User's spinner interval preference is respected in both locations
- Existing Knight Rider style remains available as one of the configurable options (don't remove it)
- No visual regression for users who haven't customized their spinner
Implementation Details
Option A: Integrate getSpinnerFrame() everywhere (Simpler)
Replace hardcoded spinners with the reactive getSpinnerFrame() function:
// In prompt/index.tsx - replace spinnerDef() usage with:
import { getSpinnerFrame } from "../../util/spinners"
// ...
<text fg={spinnerColor}>{getSpinnerFrame()}</text>// In dialog-session-list.tsx - replace hardcoded frames:
import { getSpinnerFrame } from "../../util/spinners"
// Remove: const spinnerFrames = ["⠋", "⠙", ...]
// Use: {getSpinnerFrame()}Option B: Add Knight Rider to configurable options (More Complete)
Add the Knight Rider style as an option in util/spinners.ts alongside the existing braille/block spinners. This would require:
- Converting the
createFrames()output to a static frame array - Adding it to the
SPINNERSrecord
Files to Modify
-
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx- Lines 942-960:
spinnerDefmemo - Line 1268:
<spinner>usage
- Lines 942-960:
-
packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx- Line 28: Remove hardcoded
spinnerFrames - Line 52: Use
getSpinnerFrame()instead
- Line 28: Remove hardcoded
Reference: Existing Pattern
The sidebar already demonstrates the correct pattern:
// packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx:12,217
import { getSpinnerFrame } from "../../util/spinners"
// ...
{isActive() ? getSpinnerFrame() : isError() ? "✗" : "✓"}Tasks
- Update
prompt/index.tsxto usegetSpinnerFrame()for the loading spinner - Update
dialog-session-list.tsxto usegetSpinnerFrame()for session list - Consider preserving the Knight Rider animation as a special high-fidelity option
- Test spinner customization works consistently across all TUI components
- Verify animations_enabled setting still works as a fallback
External References
- cli-spinners - Standard CLI spinner library with similar frame-based approach
- ora - Popular Node.js spinner with configurable frames/interval