Repository: pterm/pterm
Pull request #380 (2022-07-22 12:54:01)

Adds InfoPrinter in SpinnerPrinter
### Description
In addition to Success/Warning/Failure message style in Spinner, this PR adds Info style.
For example, this allows to customize the new InfoPrinter with a "No change" printer, as a "no change" state is now common in idem potency systems.

Spinner example is update to:

![pterm-info-spinner](https://user-images.githubusercontent.com/5042463/180449705-2286ba5f-bce7-4c48-9132-9e364857af23.gif)


### Scope
> What is affected by this pull request?

- [ ] Bug Fix
- [x] New Feature
- [ ] Documentation
- [ ] Other

### Related Issue
Fixes #


### To-Do Checklist
- [x] I tested my changes
- [x] I have commented every method that I created/changed
- [x] I updated the examples to fit with my changes
- [x] I have added tests for my newly created methods



Patch:
diff --git a/_examples/spinner/demo/main.go b/_examples/spinner/demo/main.go
index cacd45f5..a41397db 100644
--- a/_examples/spinner/demo/main.go
+++ b/_examples/spinner/demo/main.go
@@ -7,6 +7,11 @@ import (
 )
 
 func main() {
+	// Create and start a fork of the default spinner.
+	spinnerInfo, _ := pterm.DefaultSpinner.Start("Some informational action...")
+	time.Sleep(time.Second * 2) // Simulate 3 seconds of processing something.
+	spinnerInfo.Info()          // Resolve spinner with error message.
+
 	// Create and start a fork of the default spinner.
 	spinnerSuccess, _ := pterm.DefaultSpinner.Start("Doing something important... (will succeed)")
 	time.Sleep(time.Second * 2) // Simulate 3 seconds of processing something.
@@ -22,6 +27,19 @@ func main() {
 	time.Sleep(time.Second * 2) // Simulate 3 seconds of processing something.
 	spinnerFail.Fail()          // Resolve spinner with error message.
 
+	// Create and start a fork of the default spinner.
+	spinnerNochange, _ := pterm.DefaultSpinner.Start("Checking something important... (will result in no change)")
+	// Replace the InfoPrinter with a custom "NOCHG" one
+	spinnerNochange.InfoPrinter = &pterm.PrefixPrinter{
+		MessageStyle: &pterm.Style{pterm.FgLightBlue},
+		Prefix: pterm.Prefix{
+			Style: &pterm.Style{pterm.FgBlack, pterm.BgLightBlue},
+			Text:  " NOCHG ",
+		},
+	}
+	time.Sleep(time.Second * 2)                     // Simulate 3 seconds of processing something.
+	spinnerNochange.Info("No change were required") // Resolve spinner with error message.
+
 	// Create and start a fork of the default spinner.
 	spinnerLiveText, _ := pterm.DefaultSpinner.Start("Doing a lot of stuff...")
 	time.Sleep(time.Second)                          // Simulate 2 seconds of processing something.
diff --git a/spinner_printer.go b/spinner_printer.go
index 5dfda541..ec0a4e84 100644
--- a/spinner_printer.go
+++ b/spinner_printer.go
@@ -18,6 +18,7 @@ var DefaultSpinner = SpinnerPrinter{
 	TimerRoundingFactor: time.Second,
 	TimerStyle:          &ThemeDefault.TimerStyle,
 	MessageStyle:        &ThemeDefault.SpinnerTextStyle,
+	InfoPrinter:         &Info,
 	SuccessPrinter:      &Success,
 	FailPrinter:         &Error,
 	WarningPrinter:      &Warning,
@@ -32,6 +33,7 @@ type SpinnerPrinter struct {
 	Style               *Style
 	Delay               time.Duration
 	MessageStyle        *Style
+	InfoPrinter         TextPrinter
 	SuccessPrinter      TextPrinter
 	FailPrinter         TextPrinter
 	WarningPrinter      TextPrinter
@@ -187,6 +189,21 @@ func (s *SpinnerPrinter) GenericStop() (*LivePrinter, error) {
 	return &lp, nil
 }
 
+// Info displays an info message
+// If no message is given, the text of the SpinnerPrinter will be reused as the default message.
+func (s *SpinnerPrinter) Info(message ...interface{}) {
+	if s.InfoPrinter == nil {
+		s.InfoPrinter = &Info
+	}
+
+	if len(message) == 0 {
+		message = []interface{}{s.Text}
+	}
+	fClearLine(s.Writer)
+	Fprinto(s.Writer, s.InfoPrinter.Sprint(message...))
+	_ = s.Stop()
+}
+
 // Success displays the success printer.
 // If no message is given, the text of the SpinnerPrinter will be reused as the default message.
 func (s *SpinnerPrinter) Success(message ...interface{}) {


Test patch:
diff --git a/spinner_printer_test.go b/spinner_printer_test.go
index 1f78d5ac..99803559 100644
--- a/spinner_printer_test.go
+++ b/spinner_printer_test.go
@@ -12,6 +12,7 @@ import (
 
 func TestSpinnerPrinter_NilPrint(t *testing.T) {
 	p := pterm.SpinnerPrinter{}
+	p.Info()
 	p.Success()
 	p.Warning()
 	p.Fail()
@@ -43,6 +44,13 @@ func TestSpinnerPrinter_GenericStop(t *testing.T) {
 	p.GenericStop()
 }
 
+func TestSpinnerPrinter_Info(t *testing.T) {
+	p := pterm.DefaultSpinner
+	testPrintContains(t, func(w io.Writer, a interface{}) {
+		p.Info(a)
+	})
+}
+
 func TestSpinnerPrinter_Success(t *testing.T) {
 	p := pterm.DefaultSpinner
 	testPrintContains(t, func(w io.Writer, a interface{}) {
@@ -172,6 +180,7 @@ func TestSpinnerPrinter_DifferentVariations(t *testing.T) {
 		Style          *pterm.Style
 		Delay          time.Duration
 		MessageStyle   *pterm.Style
+		InfoPrinter    pterm.TextPrinter
 		SuccessPrinter pterm.TextPrinter
 		FailPrinter    pterm.TextPrinter
 		WarningPrinter pterm.TextPrinter
@@ -198,6 +207,7 @@ func TestSpinnerPrinter_DifferentVariations(t *testing.T) {
 				Style:          tt.fields.Style,
 				Delay:          tt.fields.Delay,
 				MessageStyle:   tt.fields.MessageStyle,
+				InfoPrinter:    tt.fields.InfoPrinter,
 				SuccessPrinter: tt.fields.SuccessPrinter,
 				FailPrinter:    tt.fields.FailPrinter,
 				WarningPrinter: tt.fields.WarningPrinter,