Yet Another CLi Spinner; providing over 70 easy to use and customizable terminal spinners for multiple OSes

Overview

Yet Another CLi Spinner (for Go)

License GoDoc Latest Git Tag Travis master Build Status Go Report Card Codecov

Package yacspin provides yet another CLi spinner for Go, taking inspiration (and some utility code) from the https://github.com/briandowns/spinner project. Specifically yacspin borrows the default character sets, and color mappings to github.com/fatih/color colors, from that project.

License

Because this package adopts the spinner character sets from https://github.com/briandowns/spinner, this package is released under the Apache 2.0 License.

Yet Another CLi Spinner?

The other Go spinner ties the ability to show updated information to the spinner's animation, meaning you can't always show all the information you want to the end user without changing the animation speed. In addition there were also some API design choices that have made it unsafe for concurrent use (while it's running), which presents challenges when trying to update the text in the spinner while it's animating in the first place

There was also an interest in the spinner being able to represent a task, and to indicate whether it failed or was successful. This would have further compounded the API issues mentioned above.

This project takes inspiration from that other project, and takes a new approach to address the challenges above.

Features

Provided Spinners

There are over 70 spinners available in the CharSets package variable. They were borrowed from github.com/briandowns/spinner. There is a table with all of the spinners at the bottom of this README.

Dynamic Width of Animation

Because of how some spinners are animated, they may have different widths are different times in the animation. The spinner calculates the maximum width, and pads the animation to ensure the text's position on the screen doesn't change. This results in a smoother looking animation.

yacspin

yacspin animation with dynamic width

other spinners

other spinners' animation with dynamic width

Success and Failure Results

The spinner has both a Stop() and StopFail() method, which allows the spinner to result in a success message or a failure message. The messages, colors, and even the character used to denote success or failure are customizable in either the initial config or via the methods.

By doing this you can use the spinner to display the status of a list of tasks being executed serially.

Stop

Animation with Success

StopFail

Animation with Failure

Concurrency

The spinner is safe for concurrent use, so you can update any of its settings via methods whether the spinner is stopped or is currently running.

Live Updates

Most spinners tie the ability to show new messages with the animation of the spinner. So if the spinner animates every 200ms, you can only show updated information every 200ms. If you wanted more frequent updates, you'd need to tradeoff the asthetics of the animation to display more data.

This spinner updates the printed information of the spinner immediately on change, without the animation updating. This allows you to use an animation speed that looks astheticaly pleasing, while also knowing the data presented to the user will be updated live.

You can see this in action in the following gif, where the filenames being uploaded are rendered independent of the spinner being animated:

Animation with Success

Pausing for Updates

Sometimes you want to change a few settings, and don't want the spinner to render your partially applied configuration. If your spinner is running, and you want to change a few configuration items via method calls, you can Pause() the spinner first. After making the changes you can call Unpause(), and it will continue rendering like normal with the newly applied configuration.

Usage

go get github.com/theckman/yacspin

Within the yacspin package there are some default spinners stored in the yacspin.CharSets variable, and you can also provide your own. There is also a list of known colors in the yacspin.ValidColors variable.

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

spinner.Start()

// doing some work
time.Sleep(2 * time.Second)

spinner.Message("uploading data")

// upload...
time.Sleep(2 * time.Second)

spinner.Stop()

Spinners

yacspin.CharSets index sample gif (Frequency: 200ms)
0 0 gif
1 1 gif
2 2 gif
3 3 gif
4 4 gif
5 5 gif
6 6 gif
7 7 gif
8 8 gif
9 9 gif
10 10 gif
11 11 gif
12 12 gif
13 13 gif
14 14 gif
15 15 gif
16 16 gif
17 17 gif
18 18 gif
19 19 gif
20 20 gif
21 21 gif
22 22 gif
23 23 gif
24 24 gif
25 25 gif
26 26 gif
27 27 gif
28 28 gif
29 29 gif
30 30 gif
31 31 gif
32 32 gif
33 33 gif
34 34 gif
35 35 gif
36 36 gif
37 37 gif
38 38 gif
39 39 gif
40 40 gif
41 41 gif
42 42 gif
43 43 gif
44 44 gif
45 45 gif
46 46 gif
47 47 gif
48 48 gif
49 49 gif
50 50 gif
51 51 gif
52 52 gif
53 53 gif
54 54 gif
55 55 gif
56 56 gif
57 57 gif
58 58 gif
59 59 gif
60 60 gif
61 61 gif
62 62 gif
63 63 gif
64 64 gif
65 65 gif
66 66 gif
67 67 gif
68 68 gif
69 69 gif
70 70 gif
71 71 gif
72 72 gif
73 73 gif
74 74 gif
75 75 gif
76 76 gif
77 77 gif
Comments
  • Alternative writer interface `func(string)`

    Alternative writer interface `func(string)`

    I was wondering if you would be interested in providing an alternative interface for writing, a func(string) in the config.

    This would allow support for some special cases when using a carriage return to "reset" the displayed string is not supported.

    opened by ghostsquad 12
  • Use a byte buffer to reduce number of write calls to stdout

    Use a byte buffer to reduce number of write calls to stdout

    This change introduces a 2KB (growable) byte buffer, to sit in between the painting function(s) and stdout. Previously, as we were animating the spinner we would write the bytes directly to stdout as we were generating the animation.

    This change makes it so that most of our writes are to an in-memory buffer, and then we only have one system call to write to the actaul terminal the contents of that buffer.

    This should act like a bit of a frame buffer, so if if anyone was experiencing any sort of stutter, where they could see the cursor as the spinner was animated, I believe this should result in a smoother adnimation.

    opened by theckman 3
  • Reduce missed Frequency updates, reduce mutex locks, update docs

    Reduce missed Frequency updates, reduce mutex locks, update docs

    This change is a small update to help make the spinner a bit more robust.

    The first increases internal channel buffer size for frequency updates, to hopefully non-blocking write dropping an update. The buffer size increase is arbitrary, and calling .Frequency() in a hot loop could still result in dropped updates.

    The second is the removal of a mutex lock within the Status() method, and an unnecessary nil check. There is not a need for either of them based on how the *Spinner is constructed.

    The third is some refinemennt of the documentation both in comments on exported identifiers, and comments within the source code.

    opened by theckman 2
  • Looking for some implementation advice

    Looking for some implementation advice

    Hey, first off, love the lib! Great work!

    I was wondering if you could provide some implementation advice. Refer to this stackoverflow question for the original question.

    I refactored since the post, and almost have it working the way I would want it, but because I am stopping and then starting the spinner because before logger print, it is adding a new line which I cannot get rid off.

    Any advice on how to fix this?

    Currently, the output is:

    Apr 19 01:05:29 INF  data=k
    
    Apr 19 01:05:29 INF  data=m
    
    Apr 19 01:05:29 INF  data=l
    ⣾13/26
    

    What I am hoping for is (no extra newline):

    Apr 19 01:05:29 INF  data=k
    Apr 19 01:05:29 INF  data=m
    Apr 19 01:05:29 INF  data=l
    ⣾13/26
    

    This is my working code so far:

    package main
    
    import (
    	"fmt"
    	"os"
    	"os/signal"
    	"sync"
    	"syscall"
    	"time"
    
    	"github.com/rs/zerolog"
    	"github.com/rs/zerolog/log"
    	"github.com/theckman/yacspin"
    )
    
    var stdOut = zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: "Jan 02 15:04:05"}
    
    func main() {
    	var Logger = log.Output(stdOut)
    
    	// pauseItForAMoment := false
    	// create a spinner
    	spinner, err := createSpinner()
    	if err != nil {
    		fmt.Printf("failed to make spinner from config struct: %v\n", err)
    		os.Exit(1)
    	}
    
    	// start the spinner
    	if err := spinner.Start(); err != nil {
    		panic(err)
    	}
    
    	wg := &sync.WaitGroup{}
    	wg.Add(1)
    	var (
    		total   int
    		current int
    	)
    
    	data := make(chan string)
    
    	// only want one go routine at a time but this is not important
    	max := make(chan struct{}, 1)
    
    	go func() {
    		defer wg.Done()
    		for d := range data {
    			wg.Add(1)
    			go func(wg *sync.WaitGroup, d string) {
    				max <- struct{}{}
    				defer func() {
    					<-max
    				}()
    
    				// function is doing work and printing the result once done.
    				// pauseItForAMoment = true
    				// spinner.Prefix(d)
    				if spinner.Status() == yacspin.SpinnerRunning {
    					spinner.Stop()
    				}
    
    				// fmt.Println(d)
    				Logger.Info().Str("data", d).Send()
    				// fmt.Println(d)
    				if spinner.Status() == yacspin.SpinnerStopped {
    					spinner.Start()
    				}
    				current += 1
    				spinner.Message(fmt.Sprintf("%d/%d", current, total))
    				// pauseItForAMoment = false
    
    				// sends a value to the spinner go routine so that it can show
    				// the updated count
    				time.Sleep(100 * time.Millisecond)
    				// spinnerCh <- 1
    				wg.Done()
    			}(wg, d)
    		}
    	}()
    
    	// simulate queing some work
    	ss := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}
    	for _, s := range ss {
    		data <- s
    	}
    	total = len(ss)
    
    	close(data)
    	wg.Wait()
    	if err := spinner.Stop(); err != nil {
    		spinner.StopFail()
    	}
    }
    
    func createSpinner() (*yacspin.Spinner, error) {
    	// build the configuration, each field is documented
    	cfg := yacspin.Config{
    		Frequency: 100 * time.Millisecond,
    		CharSet:   yacspin.CharSets[11],
    		Suffix:    "", // puts a least one space between the animating spinner and the Message
    		// Message:           "collecting files",
    		// SuffixAutoColon: true,
    		// ColorAll:        true,
    		Colors:        []string{"fgYellow"},
    		StopCharacter: " ",
    		StopColors:    []string{"fgGreen"},
    		// StopMessage:       "done",
    		StopFailCharacter: "✗",
    		StopFailColors:    []string{"fgRed"},
    		StopFailMessage:   "failed",
    	}
    
    	s, err := yacspin.New(cfg)
    	if err != nil {
    		return nil, fmt.Errorf("failed to make spinner from struct: %w", err)
    	}
    
    	return s, nil
    }
    
    func stopOnSignal(spinner *yacspin.Spinner) {
    	// ensure we stop the spinner before exiting, otherwise cursor will remain
    	// hidden and terminal will require a `reset`
    	sigCh := make(chan os.Signal, 1)
    	signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
    	go func() {
    		<-sigCh
    
    		spinner.StopFailMessage("interrupted")
    
    		// ignoring error intentionally
    		_ = spinner.StopFail()
    
    		os.Exit(0)
    	}()
    }
    

    Thanks in advance!

    opened by securisec 1
  • Use colorable to support Windows terminals; remove vendor/ directory

    Use colorable to support Windows terminals; remove vendor/ directory

    This change adds a direct dependency on github.com/mattn/go-colorable to support Windows terminals, and removes the plumbing that hardcodes Windows as a dumb terminal. This is inspired by #32 opened by @OtisOat.

    This also removes the vendor/ directory, as it's even less valuable with our usage of Modules.

    Closes #32

    opened by theckman 1
  • Update README to include features, spinners, and comparisons

    Update README to include features, spinners, and comparisons

    This is a major update to the README and includes the following bits:

    • History of why the project exists
    • GIFs showing the differences between our package and others
    • GIFs showing the full set of spinners
    opened by theckman 1
  • Rename Config.Delay to Config.Frequency

    Rename Config.Delay to Config.Frequency

    The name "delay" made more sense when the ability to update data was tied to the animation's frequency. Now that data updates happen independently from the spinner animating, it made more sense to make this the animation frequency.

    opened by theckman 1
  • Support stopping a paused spinner

    Support stopping a paused spinner

    It seems reasonable that someone may want a paused spinner to be stopped, without the user seeing another animation or data update. This supports Stop() and StopFail() working on a spinner whose Status() is SpinnerPaused.

    opened by theckman 1
  • Reduce number operations we do inside of the mutex

    Reduce number operations we do inside of the mutex

    Some of the things we were doing inside of the mutex weren't protected by the mutex itself. This reshuffles the code a bit to consider that and do as little inside of the mutex as we can.

    opened by theckman 1
  • Add ability to pause spinner and get its status

    Add ability to pause spinner and get its status

    This change adds three new methods to the Spinner type, and deprecates the Active method.

    The first are the Pause() and Unpause() methods, which put the spinner in a paused state so that you can update multiple configuration options without users seeing a spinner rendered with partial changes applied. Such as changing the suffix, message, or colors.

    The third method is the Status() method, which deprecates Active(). Because the internal state machine for the spinner has become more complex, it's no longer reasonable to consider it active or inactive. With this we include a new type, SpinnerStatus, and constants to represent each state of the internal state machine:

    • SpinnerStopped
    • SpinnerStarting
    • SpinnerRunning
    • SpinnerStoppping
    • SpinnerPausing
    • SpinnerPaused
    • SpinnerUnpausing
    opened by theckman 1
  • Do not reset timer when painting a data update; fix races

    Do not reset timer when painting a data update; fix races

    Without this change, updates of data reset the timer making the animation no longer render smoothly.

    This also fixes some potential race conditions with Start() or Stop() and any of the setter methods.

    opened by theckman 1
  • Pre/Post Update function

    Pre/Post Update function

    I'd love to update the message every tick of the spinner - would that be possible? with other (less functional) spinners, it's done by passing in a Preupdate/Postupdate function. Would that be possible?

    opened by aronchick 0
  • Using uilive to render multiple outputs

    Using uilive to render multiple outputs

    I tried to use uilive to make multiple parallel spinners work based on this comment on stackoverflow.

    The code itself looks like this:

    package main
    
    import (
    	"fmt"
    	"github.com/gosuri/uilive"
    	"github.com/theckman/yacspin"
    	"io"
    	"time"
    )
    
    func main() {
    	writer := uilive.New()
    	writer2 := writer.Newline()
    	writer.Start()
    	defer writer.Stop()
    	spinner1, _ := createSpinner1(writer)
    	spinner2, _ := createSpinner2(writer2)
    	spinner1.Start()
    	time.Sleep(2 * time.Second)
    	// update message
    	spinner1.Message("uploading files")
    	time.Sleep(2 * time.Second)
    	spinner2.Start()
    	time.Sleep(2 * time.Second)
    	spinner1.Message("test")
    	time.Sleep(2 * time.Second)
    	spinner2.Stop()
    	spinner1.Stop()
    }
    
    func createSpinner1(writer io.Writer) (*yacspin.Spinner, error) {
    	// build the configuration, each field is documented
    	cfg := yacspin.Config{
    		Prefix:            "s1",
    		Writer:            writer,
    		Frequency:         100 * time.Millisecond,
    		CharSet:           yacspin.CharSets[11],
    		Suffix:            " ", // puts a least one space between the animating spinner and the Message
    		Message:           "collecting files",
    		SuffixAutoColon:   true,
    		ColorAll:          true,
    		Colors:            []string{"fgYellow"},
    		StopCharacter:     "✓",
    		StopColors:        []string{"fgGreen"},
    		StopMessage:       "done",
    		StopFailCharacter: "✗",
    		StopFailColors:    []string{"fgRed"},
    		StopFailMessage:   "failed",
    	}
    
    	s, err := yacspin.New(cfg)
    	if err != nil {
    		return nil, fmt.Errorf("failed to make spinner from struct: %w", err)
    	}
    
    	return s, nil
    }
    func createSpinner2(writer io.Writer) (*yacspin.Spinner, error) {
    	// build the configuration, each field is documented
    	cfg := yacspin.Config{
    		Writer:            writer,
    		Prefix:            "s2",
    		Frequency:         100 * time.Millisecond,
    		CharSet:           yacspin.CharSets[11],
    		Suffix:            " ", // puts a least one space between the animating spinner and the Message
    		Message:           "doing stuff",
    		SuffixAutoColon:   true,
    		ColorAll:          true,
    		Colors:            []string{"fgYellow"},
    		StopCharacter:     "✓",
    		StopColors:        []string{"fgGreen"},
    		StopMessage:       "done",
    		StopFailCharacter: "✗",
    		StopFailColors:    []string{"fgRed"},
    		StopFailMessage:   "failed",
    	}
    
    	s, err := yacspin.New(cfg)
    	if err != nil {
    		return nil, fmt.Errorf("failed to make spinner from struct: %w", err)
    	}
    
    	return s, nil
    }
    

    I have absolutely no idea why this does not work as it should write to two different writers as in spinner.go in line 830 defined:

        if s.buffer.Len() > 0 {
    		if _, err := s.writer.Write(s.buffer.Bytes()); err != nil {
    			panic(fmt.Sprintf("failed to output buffer to writer: %v", err))
    		}
    	}
    

    Could you please offer some assistance?

    Thanks in advance.

    opened by Wulfheart 0
  • Add support for logging progress messages

    Add support for logging progress messages

    It is sometimes desirable to log messages while rendering the spinner. Users can do this currently is by not setting a StopMessage and using Stop + Start to temporarily pause the spinner, remove the spinner text and log the message to standard output (example program below).

    While this does work, I think it is worthwhile to add a spinner.LogMessage API that adds this functionality. Would love to contribute changes here if this idea makes sense.

    package main
    
    import (
    	"fmt"
    	"time"
    
    	"github.com/theckman/yacspin"
    )
    
    func logProgress(spin *yacspin.Spinner, message string) {
    	spin.Stop()
    	fmt.Println(message)
    	spin.Start()
    }
    
    func main() {
    	spin, _ := yacspin.New(yacspin.Config{
    		Frequency: time.Millisecond * 200,
    		CharSet:   yacspin.CharSets[9],
    		Message:   " Spinning...",
    	})
    
    	spin.Start()
    
    	for i := 0; i < 10; i++ {
    		logProgress(spin, fmt.Sprintf("Step %d completed.", i))
    		time.Sleep(1000 * time.Millisecond)
    	}
    
    	spin.Stop()
    }
    
    opened by weikanglim 0
Releases(v0.13.12)
  • v0.13.12(Dec 31, 2021)

    Changes all accomplished via #59.

    New Features

    • Add new TerminalMode field to Config struct, to better control the non-TTY a dumb terminal handling
    • Make Frequency configuration field optional, as non-TTY TerminalMode doesn't animate
    • The new non-TTY TerminalMode now allows the terminal to be animated manually, versus it happening implicitly within the started spinner.

    Deprecations

    • The NotTTY field in the Config struct has been deprecated in favor of the TerminalMode field
    Source code(tar.gz)
    Source code(zip)
  • v0.13.11(Dec 30, 2021)

    Bug Fix

    • Return error from Start() when CharSet wasn't set, otherwise it'd panic #57

    Other

    • Add test to make sure all character sets in CharSets variable work with .CharSet method
    • Add a note to README about the new spinner animation frequencies
    Source code(tar.gz)
    Source code(zip)
  • v0.13.10(Dec 30, 2021)

  • v0.13.9(Dec 30, 2021)

  • v0.13.8(Dec 29, 2021)

  • v0.13.7(Dec 28, 2021)

  • v0.13.6(Dec 21, 2021)

  • v0.13.5(Dec 17, 2021)

  • v0.13.4(Dec 15, 2021)

    Breaking Changes

    This release hides the cursor by default when animating the spinner. It introduces a new Config field, ShowCursor, to allow consumers to tell the spinner to show the cursor. This new field deprecates the HideCursor one.

    Source code(tar.gz)
    Source code(zip)
  • v0.13.3(Dec 15, 2021)

  • v0.13.2(Dec 12, 2021)

  • v0.13.1(Dec 12, 2021)

  • v0.13.0(Dec 11, 2021)

    New Features

    • Improve rendering performance by writing the current line to an internal buffer first, and then output the full buffer to stdout. #44
    • Update GoDoc and README file to be more clear / accurate. #46
    Source code(tar.gz)
    Source code(zip)
  • v0.12.0(Dec 11, 2021)

  • v0.11.1(Dec 11, 2021)

  • v0.11.0(Dec 11, 2021)

    Breaking Changes

    This release removes identifiers that were deprecated in v0.8.0.

    • Delay field of the Config struct
    • Delay() method on the *Spinner type
    • Active() method on the *Spinner type
    Source code(tar.gz)
    Source code(zip)
  • v0.10.0(Dec 11, 2021)

  • v0.9.0(Dec 10, 2021)

  • v0.8.0(Mar 22, 2020)

    Deprecations

    • Config.Delay field is deprecated in favor of Frequency field
    • *Spinner.Delay() method is deprecated in favor of Frequency() method
    • *Spinner.Active() method is deprecated in favor of Status() method

    New Features

    • Data / Config updates to a running spinner are applied immediately, instead of waiting for next spinner animation. This means data is live-updating.
    • Added ability to pause/unpause a spinner so that you can make the Data / Config changes from the previous bullet point, and have that change appear atomic (i.e., don't render partially applied settings)
    • You can now call the Status method on its spinner to get the current status of the internal state machine. This replaces and provides more functionality than the Active method. This also introduces a new SpinnerStatus type and associated constants

    Bug Fixes

    • Fix pipe (|) animation to render smoothly, was missing one frame
    • Fix some concurrency issues/data races that likely were benign
    Source code(tar.gz)
    Source code(zip)
  • v0.7.0(Mar 18, 2020)

  • v0.6.0(Mar 18, 2020)

    This releae adds two major features:

    • This adds a new configuration option, SuffixAutoColon, which puts a colon after the suffix if there's a message
    • Add better support for printing (clearing) the line for Windows terminals
    Source code(tar.gz)
    Source code(zip)
  • v0.5.0(Mar 18, 2020)

    • CharSets() method now returns an error
    • When printing the suffix, a : isn't implicitly added
    • When updating the refresh delay, the painter can be preempted if the delay is shorter and should trigger a paint
    • Has many fixes to make the spinner safer for concurrent modification, while making the internal implementation simpler
    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(Dec 30, 2019)

  • v0.3.0(Dec 30, 2019)

  • v0.2.0(Dec 29, 2019)

    • add StopFail() method and associated Config fields and configuration methods to support failure stop scenario (for different character, colors, and message)
    • If no color specified for Colors, StopColors, or StopFailColors don't assume we want a color (even if just white).
    • No longer generate CharSets 37 and 38 at runtime; make them part of the literal so users can see them in the documentation.
    Source code(tar.gz)
    Source code(zip)
  • v0.1.3(Dec 29, 2019)

  • v0.1.2(Dec 29, 2019)

  • v0.1.1(Dec 29, 2019)

  • v0.1.0(Dec 29, 2019)

  • v0.0.0(Dec 29, 2019)

Owner
Tim Heckman
Senior Site Reliability Engineer @ Netflix
Tim Heckman
Terminal string styling for go done right, with full and painless Windows 10 support.

GChalk GChalk is a library heavily inspired by chalk, the popular Node.js terminal color library, and using go ports of supports-color and ansi-styles

Jason Walton 318 Dec 28, 2022
Intuitive package for prettifying terminal/console output. http://godoc.org/github.com/ttacon/chalk

chalk Chalk is a go package for styling console/terminal output. Check out godoc for some example usage: http://godoc.org/github.com/ttacon/chalk The

Trey Tacon 418 Dec 23, 2022
An ANSI colour terminal package for Go

colourize An ANSI colour terminal package for Go. Supports all ANSI colours and emphasis. Not compatible with Windows systems. Installation go get gi

Trey Bastian 26 Sep 26, 2022
Console Text Colors - The non-invasive cross-platform terminal color library does not need to modify the Print method

ctc - Console Text Colors The non-invasive cross-platform terminal color library does not need to modify the Print method Virtual unix-like environmen

null 41 Nov 9, 2022
Simple tables in terminal with Go

Simple tables in terminal with Go This package allows to generate and display ascii tables in the terminal, f.e.: +----+------------------+-----------

Alexey Popov 408 Dec 29, 2022
Terminal based dashboard.

Termdash is a cross-platform customizable terminal based dashboard. The feature set is inspired by the gizak/termui project, which in turn was inspire

Jakub Sobon 2.2k Dec 28, 2022
Golang terminal dashboard

termui termui is a cross-platform and fully-customizable terminal dashboard and widget library built on top of termbox-go. It is inspired by blessed-c

Zack Guo 12.3k Dec 27, 2022
uilive is a go library for updating terminal output in realtime

uilive uilive is a go library for updating terminal output in realtime. It provides a buffered io.Writer that is flushed at a timed interval. uilive p

Greg Osuri 1.5k Dec 28, 2022
A go library to render progress bars in terminal applications

uiprogress A Go library to render progress bars in terminal applications. It provides a set of flexible features with a customizable API. Progress bar

Greg Osuri 2k Dec 29, 2022
A go library to improve readability in terminal apps using tabular data

uitable uitable is a go library for representing data as tables for terminal applications. It provides primitives for sizing and wrapping columns to i

Greg Osuri 685 Dec 30, 2022
multi progress bar for Go cli applications

Multi Progress Bar mpb is a Go lib for rendering progress bars in terminal applications. Features Multiple Bars: Multiple progress bars are supported

Vladimir Bauer 1.9k Dec 30, 2022
A CLI to adjust display brightness using xrandr. Made because Ubuntu desktop was baking my eyeballs in low light.

bright This is a simple program to set monitor brightness using xrandr. I made this because Ubuntu does not come with a built-in way to change monitor

Micah Parks 0 Jan 15, 2022
✨ #PTerm is a modern go module to beautify console output. Featuring charts, progressbars, tables, trees, and many more 🚀 It's completely configurable and 100% cross-platform compatible.

?? PTerm | Pretty Terminal Printer A golang module to print pretty text Show Demo Code PTerm.sh | Installation | Documentation | Quick Start | Example

null 3.1k Dec 27, 2022
Small library for simple and convenient formatted stylized output to the console.

cfmt cfmt is a small library for simple and convenient formatted stylized output to the console, providing an interface that is exactly the same as th

Makhnev Petr 54 Jan 7, 2023
Extensible Go terminal spinner with advanced functions with 82 built-in spinners

Features Start/Stop Customizable character sets (spinners) Custom spinner color, background Custom spinner text Restarting and reversing the spinner P

Anish De 15 Aug 19, 2022
Vivasoft Limited 7 May 11, 2023
Yaf - Yet another system fetch that is minimal and customizable

Yaf - Yet Another Fetch [Support] [Installation] [Usage] Brief Yet Another Fetch

Deepjyoti Barman 23 Oct 11, 2022
Go (golang) package with 70+ configurable terminal spinner/progress indicators.

Spinner spinner is a simple package to add a spinner / progress indicator to any terminal application. Examples can be found below as well as full exa

Brian Downs 1.9k Dec 26, 2022
Simple yet customizable bot framework written in Go.

Introduction Sarah is a general-purpose bot framework named after the author's firstborn daughter. This comes with a unique feature called "stateful c

Go Hagiwara 250 Dec 12, 2022
A Go (golang) package providing high-performance asynchronous logging, message filtering by severity and category, and multiple message targets.

ozzo-log Other languages 简体中文 Русский Description ozzo-log is a Go package providing enhanced logging support for Go programs. It has the following fe

Ozzo Framework 121 Dec 17, 2022