yacspin

repository·master·Indexed 19 days ago

https://github.com/theckman/yacspin

A Go library for customizable CLI spinners featuring smooth animations with dynamic width, concurrency safety, and decoupled message updates. It provides a variety of predefined character sets, support for TTY and non-interactive terminal modes, and customizable success and failure states.

Tokens
3.8K
Snippets
9
Records
17
Agent score
66%

What's inside yacspin

  1. How yacspin works: Core Concepts

    master

    Unlike many other spinner libraries, yacspin decouples the animation rendering from the message updates. This provides several key benefits:

    • Live Updates: You can update the spinner's Message() immediately without waiting for the next animation frame. This allows for high-frequency data updates (like progress percentages or filenames) while maintaining a slow, aesthetically pleasing animation speed.
    • Dynamic Width: The library calculates the maximum width of the animation frames and adds padding. This prevents the text following the spinner from jumping left and right as the animation frames change width.
    • Concurrency Safety: The spinner is safe for concurrent use. You can call methods to update settings (like Message()) while the spinner is actively animating.
    • Task Representation: The spinner is designed to represent tasks. You can use Stop() to indicate a successful task completion or StopFail() to indicate a failure, with customizable characters and colors for both states.
  2. Manage non-interactive (TTY) output

    master

    By default, yacspin detects if the output is a TTY. If it is not (e.g., a CI environment or redirected output):

    • Colors are disabled.
    • Automatic animation is disabled.
    • The spinner only 'animates' by printing a new line whenever the message is updated.

    To manually control this behavior, use the TerminalMode field in Config with:

    • ForceNoTTYMode or ForceSmartTerminalMode to allow manual stepping of the animation by calling Message() with the same content.
  3. Control Terminal Mode with TerminalMode

    master

    You can override how yacspin detects the terminal environment using the TerminalMode bitflag in the Config. This is useful for CI environments or specific terminal emulators.

    • AutomaticMode: (Default) Attempts to detect if the session is interactive (TTY).
    • ForceTTYMode: Forces the spinner to operate as if in a TTY session.
    • ForceNoTTYMode: Forces non-TTY mode. Animation only triggers when Message() is called, and each frame is printed on a new line.
    • ForceDumbTerminalMode: Disables ANSI escape sequences for colors/erasure. Uses space-padding for line erasure.
    • ForceSmartTerminalMode: Enables full ANSI escape sequence support (VT100) for stylized text and efficient line erasure.
    // Example: Forcing dumb terminal mode in config
    cfg := yacspin.Config{
        TerminalMode: yacspin.ForceDumbTerminalMode,
        // ... other config
    }
  4. Configure a yacspin instance

    master

    You create a new spinner using yacspin.New(cfg), where cfg is a yacspin.Config struct.

    Key configuration fields include:

    • Frequency: The duration between animation frames (e.g., 100 * time.Millisecond).
    • CharSet: The animation character set, typically selected from the yacspin.CharSets slice.
    • Suffix: Text to appear after the spinner.
    • SuffixAutoColon: If true, automatically adds a colon after the spinner/suffix.
    • Message: The main text displayed.
    • StopCharacter: The character used when Stop() is called (e.g., "✓").
    • StopColors: A slice of color names (from yacspin.ValidColors) to use upon success.
    • SpinnerAtEnd: If true, renders the spinner at the end of the line instead of the beginning.
    • TerminalMode: Controls how the spinner behaves in non-interactive environments.
    cfg := yacspin.Config{
    	Frequency:       100 * time.Millisecond,
    	CharSet:         yacspin.CharSets[59],
    	Suffix:          " backing up database to S3",
    	SuffixAutoColon: true,
    	Message:         "exporting data",
    	StopCharacter:   "✓",
    	StopColors:      []string{"fgGreen"},
    }
    
    spinner, err := yacspin.New(cfg)
  5. Initialize and use a Spinner

    master

    To use yacspin, create a new Spinner instance using yacspin.New(cfg) with a Config struct. Once created, call Start() to begin the animation. You can update the message or suffix while it is running. Finally, call Stop() to end the animation gracefully or StopFail() to indicate a failure.

    Note: If you do not set ShowCursor: true in your config, the spinner will hide the terminal cursor. Ensure you call Stop() or StopFail() to restore it, otherwise you may need to manually reset your terminal.

    cfg := yacspin.Config{
    	Frequency:     100 * time.Millisecond,
    	CharSet:       yacspin.CharSets[59],
    	Suffix:        " backing up database to S3",
    	Message:       "exporting data",
    	StopCharacter: "✓",
    	StopColors:    []string{"fgGreen"},
    }
    
    spinner, err := yacspin.New(cfg)
    if err != nil {
    	// handle error
    }
    
    spinner.Start()
    
    // doing some work
    time.Sleep(2 * time.Second)
    
    spinner.Message("uploading data")
    
    // upload...
    time.Sleep(2 * time.Second)
    
    spinner.Stop()
  6. Basic usage example

    master

    This example demonstrates initializing a spinner, starting it, updating the message mid-process, and stopping it successfully.

    cfg := yacspin.Config{
    	Frequency:       100 * time.Millisecond,
    	CharSet:         yacspin.CharSets[59],
    	Suffix:          " backing up database to S3",
    	SuffixAutoColon: true,
    	Message:         "exporting data",
    	StopCharacter:   "✓",
    	StopColors:      []string{"fgGreen"},
    }
    
    spinner, err := yacspin.New(cfg)
    // handle the error
    
    err = spinner.Start()
    
    // doing some work
    time.Sleep(2 * time.Second)
    
    spinner.Message("uploading data")
    
    // upload...
    time.Sleep(2 * time.Second)
    
    err = spinner.Stop()
  7. Handle success and failure results

    master

    Use the following methods to terminate a spinner with a specific status:

    • Stop(): Ends the animation and displays the StopCharacter and StopColors configured for success.
    • StopFail(): Ends the animation and displays a failure state. You can customize the failure character, message, and colors in the initial Config or via method calls.
  8. Pause and Unpause for configuration updates

    master

    If you need to change multiple configuration settings at once and want to avoid rendering partially applied states, use Pause() and Unpause():

    1. Call spinner.Pause().
    2. Update settings via method calls.
    3. Call spinner.Unpause() to resume animation with the new configuration.
  9. Configure the Spinner via Config struct

    master

    The yacspin.Config struct allows you to define the initial behavior of the spinner. Some fields are immutable after construction.

    Immutable Fields (Set only via New())

    • Frequency: time.Duration specifying animation speed.
    • Writer: io.Writer for output (defaults to os.Stdout).
    • ShowCursor: bool whether to show the cursor during animation.
    • SpinnerAtEnd: bool if true, renders animation at the end of the line.
    • ColorAll: bool if true, colors the entire line; if false, only colors the spinner character.
    • TerminalMode: yacspin.TerminalMode bitflag to override TTY detection.

    Mutable Fields (Can be updated after New())

    • Message: The text displayed after the spinner.
    • Prefix: Text printed before the spinner.
    • Suffix: Text printed after the spinner.
    • CharSet: The slice of strings used for animation frames.
    • Colors: Colors for the spinner line (uses github.com/fatih/color syntax).
    • Frequency: Update the animation speed dynamically.
  10. Browse available yacspin.CharSets animations

    master

    The yacspin package includes a variety of pre-defined character sets for spinner animations. You can choose an animation by its index in the yacspin.CharSets collection.

    Note that the visual speed of these animations depends on the refresh frequency you set in your implementation. The provided samples are recorded at a frequency of 200ms, but you should experiment with different values to find the speed that best suits your CLI application's aesthetic.

    // The animations are indexed via yacspin.CharSets
    // Example: index 0, 1, 2, ..., 90
    // Adjust frequency to change animation speed.
  11. Update Spinner content dynamically

    master

    While a spinner is running, you can update its visual components using the following methods. These calls are thread-safe and trigger a re-render:

    • Message(string): Updates the main message text.
    • Prefix(string): Updates the text before the spinner.
    • Suffix(string): Updates the text after the spinner.
    • Colors(...string): Updates the colors for the spinner line.
    • CharSet([]string): Updates the animation frames.
    • Frequency(time.Duration): Updates the animation speed.