Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: custom writer for progressbar and spinner printers #337

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
63 changes: 32 additions & 31 deletions docs/docs/printer/progressbar.md
@@ -1,6 +1,6 @@
# ProgressbarPrinter

<!--
<!--
Replace all of the following strings with the current printer.
progressbar Progressbar ProgressbarPrinter DefaultProgressbar
-->
Expand All @@ -9,7 +9,6 @@ Replace all of the following strings with the current printer.

<p align="center"><a href="https://github.com/pterm/pterm/blob/master/_examples/progressbar/main.go" target="_blank">(Show source of demo)</a></p>


## Usage

### Basic usage
Expand All @@ -23,12 +22,12 @@ progressbar.Increment()

### Functions

|Function|Description|
|--------|-----------|
|[Add(count int)](https://pkg.go.dev/github.com/pterm/pterm#TemplatePrinter.Add)|Add `count` to current value.|
|[GetElapsedTime()](https://pkg.go.dev/github.com/pterm/pterm#TemplatePrinter.GetElapsedTime)|GetElapsedTime returns the elapsed time, since the ProgressbarPrinter was started.|
|[Increment()](https://pkg.go.dev/github.com/pterm/pterm#TemplatePrinter.Increment)|Increment current value by one.|
|[UpdateTitle(title string)](https://pkg.go.dev/github.com/pterm/pterm#TemplatePrinter.UpdateTitle)|Update the progressbar's title.|
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These links seemed wrong so I updated them too :)

| Function | Description |
| ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| [Add(count int)](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.Add) | Add `count` to current value. |
| [GetElapsedTime()](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.GetElapsedTime) | GetElapsedTime returns the elapsed time, since the ProgressbarPrinter was started. |
| [Increment()](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.Increment) | Increment current value by one. |
| [UpdateTitle(title string)](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.UpdateTitle) | Update the progressbar's title. |

### Options

Expand All @@ -41,38 +40,40 @@ progressbar.Increment()
> [!TIP]
> Click the options and types to show the documentation on _pkg.go.dev_

|Option|Type|
|------|----|
|[BarCharacter](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithBarCharacter)|string|
|[BarStyle](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithBarStyle)|[*Style](https://pkg.go.dev/github.com/pterm/pterm#Style)|
|[Current](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithCurrent)|int|
|[ElapsedTimeRoundingFactor](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithElapsedTimeRoundingFactor)|time.Duration|
|[LastCharacter](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithLastCharacter)|string|
|[RemoveWhenDone](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithRemoveWhenDone)|...bool|
|[ShowCount](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithShowCount)|...bool|
|[ShowElapsedTime](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithShowElapsedTime)|...bool|
|[ShowPercentage](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithShowPercentage)|...bool|
|[ShowTitle](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithShowTitle)|...bool|
|[Title](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithTitle)|string|
|[TitleStyle](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithTitleStyle)|[*Style](https://pkg.go.dev/github.com/pterm/pterm#Style)|
|[Total](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithTotal)|int|
|[BarFiller](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithBarFiller)|string|
|[MaxWidth](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithMaxWidth)|int|
| Option | Type |
| ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| [BarCharacter](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithBarCharacter) | string |
| [BarStyle](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithBarStyle) | [\*Style](https://pkg.go.dev/github.com/pterm/pterm#Style) |
| [Current](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithCurrent) | int |
| [ElapsedTimeRoundingFactor](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithElapsedTimeRoundingFactor) | time.Duration |
| [LastCharacter](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithLastCharacter) | string |
| [RemoveWhenDone](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithRemoveWhenDone) | ...bool |
| [ShowCount](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithShowCount) | ...bool |
| [ShowElapsedTime](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithShowElapsedTime) | ...bool |
| [ShowPercentage](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithShowPercentage) | ...bool |
| [ShowTitle](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithShowTitle) | ...bool |
| [Title](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithTitle) | string |
| [TitleStyle](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithTitleStyle) | [\*Style](https://pkg.go.dev/github.com/pterm/pterm#Style) |
| [Total](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithTotal) | int |
| [BarFiller](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithBarFiller) | string |
| [MaxWidth](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithMaxWidth) | int |
| [Writer](https://pkg.go.dev/github.com/pterm/pterm#ProgressbarPrinter.WithWriter) | io.Writer |

### Output functions

> This printer implements the interface [`LivePrinter`](https://github.com/pterm/pterm/blob/master/interface_live_printer.go)

|Function|Description|
|------|---------|
|Start()|Returns itself and possible errors|
|Stop()|Returns itself and possible errors|
|GenericStart()|Returns the started LivePrinter and possible errors|
|GenericStop()|Returns the stopped LivePrinter and possible errors|
| Function | Description |
| -------------- | --------------------------------------------------- |
| Start() | Returns itself and possible errors |
| Stop() | Returns itself and possible errors |
| GenericStart() | Returns the started LivePrinter and possible errors |
| GenericStop() | Returns the stopped LivePrinter and possible errors |

> [!NOTE]
> The generic start and stop methods are only used to implement the printer into the interface.
> Use the normal `Start()` and `Stop()` methods if possible.

## Related

- [Override default printers](docs/customizing/override-default-printer.md)
54 changes: 27 additions & 27 deletions docs/docs/printer/spinner.md
@@ -1,6 +1,6 @@
# SpinnerPrinter

<!--
<!--
Replace all of the following strings with the current printer.
spinner Spinner SpinnerPrinter DefaultSpinner
-->
Expand All @@ -9,7 +9,6 @@ Replace all of the following strings with the current printer.

<p align="center"><a href="https://github.com/pterm/pterm/blob/master/_examples/spinner/main.go" target="_blank">(Show source of demo)</a></p>


## Usage

### Basic usage
Expand All @@ -20,12 +19,12 @@ pterm.DefaultSpinner.Start()

### Functions

|Function|Description|
|--------|-----------|
|[Fail(message ...interface{})](https://pkg.go.dev/github.com/pterm/pterm#TemplatePrinter.Fail)|Fail displays the fail printer. If no message is given, the text of the SpinnerPrinter will be reused as the default message.|
|[Success(message ...interface{})](https://pkg.go.dev/github.com/pterm/pterm#TemplatePrinter.Success)|Success displays the success printer. If no message is given, the text of the SpinnerPrinter will be reused as the default message.|
|[UpdateText(text string)](https://pkg.go.dev/github.com/pterm/pterm#TemplatePrinter.UpdateText)|UpdateText updates the message of the active SpinnerPrinter. Can be used live.|
|[Warning(message ...interface{})](https://pkg.go.dev/github.com/pterm/pterm#TemplatePrinter.UpdateText)|Warning displays the warning printer. If no message is given, the text of the SpinnerPrinter will be reused as the default message.|
| Function | Description |
| ------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
| [Fail(message ...interface{})](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.Fail) | Fail displays the fail printer. If no message is given, the text of the SpinnerPrinter will be reused as the default message. |
| [Success(message ...interface{})](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.Success) | Success displays the success printer. If no message is given, the text of the SpinnerPrinter will be reused as the default message. |
| [UpdateText(text string)](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.UpdateText) | UpdateText updates the message of the active SpinnerPrinter. Can be used live. |
| [Warning(message ...interface{})](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.UpdateText) | Warning displays the warning printer. If no message is given, the text of the SpinnerPrinter will be reused as the default message. |

### Options

Expand All @@ -38,33 +37,34 @@ pterm.DefaultSpinner.Start()
> [!TIP]
> Click the options and types to show the documentation on _pkg.go.dev_

|Option|Type|
|------|----|
|[Delay](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithDelay)|time.Duration|
|[MessageStyle](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithMessageStyle)|[*Style](https://pkg.go.dev/github.com/pterm/pterm#Style)|
|[RemoveWhenDone](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithRemoveWhenDone)|...bool|
|[Sequence](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithSequence)|...string|
|[Style](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithStyle)|[*Style](https://pkg.go.dev/github.com/pterm/pterm#Style)|
|[Text](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithText)|string|
|[ShowTimer](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithShowTimer)|...bool|
|[TimerRoundingFactor](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithTimerRoundingFactor)|time.Duration|
|[TimerStyle](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithTimerStyle)|[*Style](https://pkg.go.dev/github.com/pterm/pterm#Style)|

| Option | Type |
| ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| [Delay](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithDelay) | time.Duration |
| [MessageStyle](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithMessageStyle) | [\*Style](https://pkg.go.dev/github.com/pterm/pterm#Style) |
| [RemoveWhenDone](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithRemoveWhenDone) | ...bool |
| [Sequence](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithSequence) | ...string |
| [Style](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithStyle) | [\*Style](https://pkg.go.dev/github.com/pterm/pterm#Style) |
| [Text](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithText) | string |
| [ShowTimer](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithShowTimer) | ...bool |
| [TimerRoundingFactor](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithTimerRoundingFactor) | time.Duration |
| [TimerStyle](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithTimerStyle) | [\*Style](https://pkg.go.dev/github.com/pterm/pterm#Style) |
| [Writer](https://pkg.go.dev/github.com/pterm/pterm#SpinnerPrinter.WithWriter) | io.Writer |

### Output functions

> This printer implements the interface [`LivePrinter`](https://github.com/pterm/pterm/blob/master/interface_live_printer.go)

|Function|Description|
|------|---------|
|Start()|Returns itself and possible errors|
|Stop()|Returns itself and possible errors|
|GenericStart()|Returns the started LivePrinter and possible errors|
|GenericStop()|Returns the stopped LivePrinter and possible errors|
| Function | Description |
| -------------- | --------------------------------------------------- |
| Start() | Returns itself and possible errors |
| Stop() | Returns itself and possible errors |
| GenericStart() | Returns the started LivePrinter and possible errors |
| GenericStop() | Returns the stopped LivePrinter and possible errors |

> [!NOTE]
> The generic start and stop methods are only used to implement the printer into the interface.
> Use the normal `Start()` and `Stop()` methods if possible.

## Related
- [Override default printers](docs/customizing/override-default-printer.md)

- [Override default printers](docs/customizing/override-default-printer.md)
6 changes: 3 additions & 3 deletions print.go
Expand Up @@ -106,15 +106,15 @@ func Fprint(writer io.Writer, a ...interface{}) {
var printed bool

for _, bar := range ActiveProgressBarPrinters {
if bar.IsActive {
if bar.IsActive && bar.Writer == writer {
ret += sClearLine()
ret += Sprinto(a...)
printed = true
}
}

for _, spinner := range activeSpinnerPrinters {
if spinner.IsActive {
if spinner.IsActive && spinner.Writer == writer {
ret += sClearLine()
ret += Sprinto(a...)
printed = true
Expand All @@ -124,7 +124,7 @@ func Fprint(writer io.Writer, a ...interface{}) {
if !printed {
ret = color.Sprint(Sprint(a...))
}

if writer != nil {
color.Fprint(writer, Sprint(ret))
} else {
Expand Down
19 changes: 14 additions & 5 deletions progressbar_printer.go
@@ -1,6 +1,7 @@
package pterm

import (
"io"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -55,6 +56,8 @@ type ProgressbarPrinter struct {
IsActive bool

startedAt time.Time

Writer io.Writer
}

// WithTitle sets the name of the ProgressbarPrinter.
Expand Down Expand Up @@ -149,6 +152,12 @@ func (p ProgressbarPrinter) WithBarFiller(char string) *ProgressbarPrinter {
return &p
}

// WithWriter sets the custom Writer.
func (p ProgressbarPrinter) WithWriter(writer io.Writer) *ProgressbarPrinter {
p.Writer = writer
return &p
}

// Increment current value by one.
func (p *ProgressbarPrinter) Increment() *ProgressbarPrinter {
p.Add(1)
Expand Down Expand Up @@ -227,7 +236,7 @@ func (p *ProgressbarPrinter) updateProgress() *ProgressbarPrinter {
}

if !RawOutput {
Printo(before + bar + after)
Fprinto(p.Writer, before+bar+after)
}
return p
}
Expand All @@ -250,7 +259,7 @@ func (p *ProgressbarPrinter) Add(count int) *ProgressbarPrinter {
// Start the ProgressbarPrinter.
func (p ProgressbarPrinter) Start() (*ProgressbarPrinter, error) {
if RawOutput && p.ShowTitle {
Println(p.Title)
Fprintln(p.Writer, p.Title)
}
p.IsActive = true
ActiveProgressBarPrinters = append(ActiveProgressBarPrinters, &p)
Expand All @@ -268,10 +277,10 @@ func (p *ProgressbarPrinter) Stop() (*ProgressbarPrinter, error) {
}
p.IsActive = false
if p.RemoveWhenDone {
fClearLine(nil)
Fprinto(nil)
fClearLine(p.Writer)
Fprinto(p.Writer)
} else {
Fprintln(nil)
Fprintln(p.Writer)
}
return p, nil
}
Expand Down
42 changes: 42 additions & 0 deletions progressbar_printer_test.go
@@ -1,6 +1,8 @@
package pterm_test

import (
"io"
"os"
"testing"
"time"

Expand Down Expand Up @@ -209,3 +211,43 @@ func TestProgressbarPrinter_UpdateTitle(t *testing.T) {

testza.AssertEqual(t, "test2", p2.Title)
}

func TestProgressbarPrinter_WithWriter(t *testing.T) {
p := pterm.ProgressbarPrinter{}
s := os.Stderr
p2 := p.WithWriter(s)

testza.AssertEqual(t, s, p2.Writer)
testza.AssertZero(t, p.Writer)
}

func TestProgressbarPrinter_OutputToWriters(t *testing.T) {
testCases := map[string]struct {
action func(*pterm.ProgressbarPrinter)
expectOutputToContain string
}{
"ExpectUpdatedTitleToBeWrittenToStderr": {
action: func(pb *pterm.ProgressbarPrinter) {
pb.UpdateTitle("Updated text")
},
expectOutputToContain: "Updated text",
},
}

for testTitle, testCase := range testCases {
t.Run(testTitle, func(t *testing.T) {
stderr, err := testza.CaptureStderr(func(w io.Writer) error {
pb, err := pterm.DefaultProgressbar.WithTitle("Hello world").WithWriter(os.Stderr).Start()
time.Sleep(time.Second) // Required otherwise the goroutine doesn't run and the text isnt outputted
testza.AssertNoError(t, err)
testCase.action(pb)
time.Sleep(time.Second) // Required otherwise the goroutine doesn't run and the text isnt updated
return nil
})

testza.AssertNoError(t, err)
testza.AssertContains(t, stderr, "Hello world")
testza.AssertContains(t, stderr, testCase.expectOutputToContain)
})
}
}