Skip to content

Restore spinner customization to prompt loading indicator and session list dialog #238

@shuv1337

Description

@shuv1337

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:

  1. Prompt loading indicator (packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx:1268) - Uses a hardcoded Knight Rider style spinner from ui/spinner.ts instead of the user-configurable spinner
  2. 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)
  • 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:

  1. Converting the createFrames() output to a static frame array
  2. Adding it to the SPINNERS record

Files to Modify

  1. packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx

    • Lines 942-960: spinnerDef memo
    • Line 1268: <spinner> usage
  2. packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx

    • Line 28: Remove hardcoded spinnerFrames
    • Line 52: Use getSpinnerFrame() instead

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.tsx to use getSpinnerFrame() for the loading spinner
  • Update dialog-session-list.tsx to use getSpinnerFrame() 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions