VOOZH about

URL: https://deepwiki.com/hypervel/prompts/6.2-progress-bars-and-spinners

⇱ Progress Bars and Spinners | hypervel/prompts | DeepWiki


Loading...
Last indexed: 7 February 2026 (2e2181)
Menu

Progress Bars and Spinners

Purpose and Scope

This document covers the progress bar and spinner display components for visualizing long-running operations. Progress bars are used when operations have a known number of steps (countable iterations), while spinners indicate indeterminate operations of unknown duration.

These are non-interactive display components that extend the base Prompt class but do not accept user input. For interactive prompts that accept user choices, see Interactive Prompts. For other display utilities like tables and notes, see Tables and Notes and Messages.

Sources: src/Progress.php1-216 src/helpers.php135-254


Progress Bar Architecture

The Progress class provides visual feedback for countable operations, rendering a progress bar that updates as work completes.


Sources: src/Progress.php12-216 src/helpers.php233-254

Template Type System

The Progress class uses PHP generics to preserve type information:

@template TSteps of iterable<mixed>|int

This allows two modes of operation:

  • Integer mode: Progress<int> iterates from 0 to N-1
  • Iterable mode: Progress<iterable<T>> iterates over collection items

The map() method's callback signature adapts accordingly:

  • Integer mode: Closure(int $index, Progress): TReturn
  • Iterable mode: Closure(T $item, Progress): TReturn

Sources: src/Progress.php13-14 src/Progress.php54-57


Automatic Iteration with map()

The map() method provides the simplest interface for progress bars, automatically managing the lifecycle while processing each item.

Usage Patterns


Sources: src/Progress.php59-95 src/helpers.php233-254

map() Implementation Details

AspectImplementation
Entry Pointmap(Closure $callback): array src/Progress.php59
InitializationCalls start() to set state and hide cursor src/Progress.php61
Integer Modefor ($i = 0; $i < $this->steps; ++$i) src/Progress.php67
Iterable Modeforeach ($this->steps as $step) src/Progress.php72
Callback Invocation$result[] = $callback($item, $this) src/Progress.php68-73
Progress Update$this->advance() after each callback src/Progress.php69-74
Error HandlingCatch Throwable, set error state, restore cursor src/Progress.php77-83
CompletionCall finish() to restore terminal state src/Progress.php92
Return ValueArray of callback return values src/Progress.php94

Sources: src/Progress.php59-95

Final Hint Display

When a hint is provided, the progress bar pauses briefly (250ms) after completion to ensure the final hint is visible before the display is cleared:


This prevents the hint from appearing to be skipped when operations complete rapidly.

Sources: src/Progress.php86-90


Manual Progress Control

For scenarios requiring explicit control over progress updates, the Progress instance can be managed manually through its lifecycle methods.

Lifecycle Flow


Sources: src/Progress.php100-141

Manual Control Methods

MethodSignaturePurpose
start()public function start(): voidInitializes display, hides cursor, sets up signal handlers src/Progress.php100-116
advance()public function advance(int $step = 1): voidIncrements progress counter by specified amount src/Progress.php121-130
finish()public function finish(): voidMarks completion, restores cursor, cleans up signals src/Progress.php135-141
label()public function label(string $label): staticUpdates the display label dynamically src/Progress.php154-159
hint()public function hint(string $hint): staticUpdates the hint text dynamically src/Progress.php164-169
render()public function render(): voidForces immediate re-render src/Progress.php146-149

Sources: src/Progress.php100-169

Dynamic Updates Example

The fluent interface allows chaining updates:


The render() method is automatically called by advance(), label(), and hint() to ensure visual updates.

Sources: src/Progress.php121-169


Progress Calculation and Bounds

Total Calculation

The $total property is computed during construction based on the $steps parameter:

Steps TypeCalculationCode
intDirect assignment$this->total = $this->steps src/Progress.php40
Countable iterablecount($this->steps)src/Progress.php41
Non-countable iterableiterator_count($this->steps)src/Progress.php42

An exception is thrown if $total is zero, as progress bars require at least one step.

Sources: src/Progress.php37-48

Advance Bounds Protection

The advance() method includes overflow protection:


This ensures the progress never exceeds 100%, even if advance() is called more times than expected.

Sources: src/Progress.php123-127

Percentage Calculation

The completion percentage is calculated as a simple ratio:


This returns a decimal value (0.0 to 1.0) representing completion percentage.

Sources: src/Progress.php174-177


Signal Handling and Interruption

Progress bars register signal handlers to gracefully handle interruption (Ctrl+C).


Sources: src/Progress.php104-111 src/Progress.php200-206

Signal Handler Registration

The signal handler is registered in start():


This captures the original async signals state and sets up a handler that:

  1. Changes state to 'cancel'
  2. Renders final frame showing cancellation
  3. Exits the process

Sources: src/Progress.php104-111

Signal Cleanup

The resetSignals() method restores original signal handling:


This is called by both finish() and in the exception handler during map().

Sources: src/Progress.php200-206 src/Progress.php81 src/Progress.php140


Spinner Component

Spinners provide visual feedback for indeterminate operations where the total duration or number of steps is unknown.


Sources: src/helpers.php135-148

spin() Helper Function

The spin() function signature:


The function:

  • Creates a Spinner instance with optional message
  • Executes the callback while displaying the spinner
  • Returns the callback's return value
  • Preserves type information through the @template annotation

Sources: src/helpers.php135-148

Spinner vs Progress Bar

AspectProgress BarSpinner
Use CaseKnown number of stepsUnknown duration
VisualBar filling 0-100%Rotating animation
UpdatesIncremental (advance())Continuous animation
CompletionReaches 100%Stops when callback returns
APImap() or manual controlSingle spin() call
Return ValueArray of results (map mode)Callback return value

Progress Bar Limitations

No Interactive Prompting

The Progress class explicitly disables the prompt() method inherited from the base Prompt class:


This is by design—progress bars are display-only components and do not accept user input. Calling prompt() on a Progress instance will throw an exception.

Sources: src/Progress.php180-187

value() Implementation

The required value() abstract method from Prompt returns a meaningless boolean:


This exists only to satisfy the abstract method requirement. Progress bars do not have a "value" in the sense that interactive prompts do.

Sources: src/Progress.php192-195


Integration with Base Prompt

Despite being non-interactive, Progress extends Prompt to leverage shared infrastructure.


Sources: src/Progress.php15 src/Progress.php146-149 src/Progress.php180-195 src/Prompt.php281-310

Why Extend Prompt?

Benefits of inheritance:

  1. State management: Uses Prompt::$state for lifecycle tracking
  2. Rendering infrastructure: Reuses frame rendering and terminal control
  3. Terminal integration: Access to Terminal and OutputInterface
  4. Theme system: Delegates visual rendering to ProgressRenderer
  5. Cursor control: Inherited hideCursor() and restoreCursor() methods

Drawbacks mitigated:

  • prompt() throws exception to prevent misuse
  • value() provides meaningless stub
  • Non-interactive nature clearly documented

Sources: src/Progress.php15 src/Prompt.php15-449


Constructor and Total Calculation

The constructor calculates the total number of steps based on the type of the $steps parameter.


Sources: src/Progress.php37-48

Constructor Parameters

ParameterTypePurpose
$labelstringDisplay text above progress bar
$stepsint|iterableEither count or collection to iterate
$hintstringOptional guidance text (default: '')

The constructor uses a match expression to determine the total:


Sources: src/Progress.php37-44


Summary

Key Concepts:

ComponentPurposePrimary MethodReturn Type
Progress BarVisualize countable operationsmap(Closure) or manual controlarray or Progress instance
SpinnerIndicate indeterminate operationsspin(Closure)Callback return value

Usage Patterns:

  1. Automatic iteration: progress('Label', $items, fn($item, $bar) => ...)
  2. Manual control: $bar = progress('Label', 100); $bar->start(); ... $bar->finish();
  3. Spinner: spin(fn() => someOperation(), 'Loading...')

Architecture Notes:

  • Progress bars extend Prompt but are not interactive
  • Signal handling provides graceful interruption
  • Dynamic updates supported via label() and hint() methods
  • Template types preserve item type information through iteration
  • Bounds protection prevents progress exceeding 100%

Sources: src/Progress.php1-216 src/helpers.php135-254