Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jedib0t/go-pretty
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v6.3.9
Choose a base ref
...
head repository: jedib0t/go-pretty
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v6.4.0
Choose a head ref
  • 3 commits
  • 8 files changed
  • 2 contributors

Commits on Oct 2, 2022

  1. Copy the full SHA
    99ac11f View commit details
  2. Copy the full SHA
    7d299c2 View commit details
  3. Copy the full SHA
    e88b800 View commit details
Showing with 222 additions and 87 deletions.
  1. +7 −0 cmd/demo-progress/demo.go
  2. +15 −2 progress/progress.go
  3. +8 −0 progress/progress_test.go
  4. +27 −3 progress/render.go
  5. +147 −82 progress/render_test.go
  6. +4 −0 progress/style.go
  7. +1 −0 progress/writer.go
  8. +13 −0 text/direction_test.go
7 changes: 7 additions & 0 deletions cmd/demo-progress/demo.go
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ var (
flagNumTrackers = flag.Int("num-trackers", 13, "Number of Trackers")
flagShowSpeed = flag.Bool("show-speed", false, "Show the tracker speed?")
flagShowSpeedOverall = flag.Bool("show-speed-overall", false, "Show the overall tracker speed?")
flagShowPinned = flag.Bool("show-pinned", false, "Show a pinned message?")
flagRandomFail = flag.Bool("rnd-fail", false, "Introduce random failures in tracking")
flagRandomLogs = flag.Bool("rnd-logs", false, "Output random logs in the middle of tracking")

@@ -33,6 +34,7 @@ var (
text.FgCyan,
text.FgWhite,
}
timeStart = time.Now()
)

func getMessage(idx int64, units *progress.Units) string {
@@ -87,6 +89,10 @@ func trackSomething(pw progress.Writer, idx int64, updateMessage bool) {
} else if *flagRandomFail && rand.Float64() < 0.1 {
tracker.MarkAsErrored()
}
pw.SetPinnedMessages(
fmt.Sprintf(">> Current Time: %-32s", time.Now().Format(time.RFC3339)),
fmt.Sprintf(">> Total Time: %-32s", time.Now().Sub(timeStart).Round(time.Millisecond)),
)
case <-updateTicker:
if updateMessage {
rndIdx := rand.Intn(len(messageColors))
@@ -123,6 +129,7 @@ func main() {
pw.Style().Visibility.Time = !*flagHideTime
pw.Style().Visibility.TrackerOverall = !*flagHideOverallTracker
pw.Style().Visibility.Value = !*flagHideValue
pw.Style().Visibility.Pinned = *flagShowPinned

// call Render() in async mode; yes we don't have any trackers at the moment
go pw.Render()
17 changes: 15 additions & 2 deletions progress/progress.go
Original file line number Diff line number Diff line change
@@ -24,16 +24,19 @@ var (
type Progress struct {
autoStop bool
done chan bool
lengthTracker int
lengthProgress int
lengthProgressOverall int
outputWriter io.Writer
lengthTracker int
logsToRender []string
logsToRenderMutex sync.RWMutex
messageWidth int
numTrackersExpected int64
outputWriter io.Writer
overallTracker *Tracker
overallTrackerMutex sync.RWMutex
pinnedMessages []string
pinnedMessageMutex sync.RWMutex
pinnedMessageNumLines int
renderInProgress bool
renderInProgressMutex sync.RWMutex
sortBy SortBy
@@ -183,6 +186,16 @@ func (p *Progress) SetOutputWriter(writer io.Writer) {
p.outputWriter = writer
}

// SetPinnedMessages sets message(s) pinned above all the trackers of the
// progress bar. This method can be used to overwrite all the pinned messages.
// Call this function without arguments to "clear" the pinned messages.
func (p *Progress) SetPinnedMessages(messages ...string) {
p.pinnedMessageMutex.Lock()
defer p.pinnedMessageMutex.Unlock()

p.pinnedMessages = messages
}

// SetSortBy defines the sorting mechanism to use to sort the Active Trackers
// before rendering the. Default: no-sorting == sort-by-insertion-order.
func (p *Progress) SetSortBy(sortBy SortBy) {
8 changes: 8 additions & 0 deletions progress/progress_test.go
Original file line number Diff line number Diff line change
@@ -119,6 +119,14 @@ func TestProgress_SetOutputWriter(t *testing.T) {
assert.Equal(t, os.Stdout, p.outputWriter)
}

func TestProgress_SetPinnedMessages(t *testing.T) {
p := Progress{}
assert.Nil(t, p.pinnedMessages)

p.SetPinnedMessages("pin1", "pin2")
assert.Equal(t, []string{"pin1", "pin2"}, p.pinnedMessages)
}

func TestProgress_SetSortBy(t *testing.T) {
p := Progress{}
assert.Zero(t, p.sortBy)
30 changes: 27 additions & 3 deletions progress/render.go
Original file line number Diff line number Diff line change
@@ -158,9 +158,29 @@ func (p *Progress) moveCursorToTheTop(out *strings.Builder) {
if p.style.Visibility.TrackerOverall && p.overallTracker != nil && !p.overallTracker.IsDone() {
numLinesToMoveUp++
}
if numLinesToMoveUp > 0 {
out.WriteString(text.CursorUp.Sprintn(numLinesToMoveUp))
if p.style.Visibility.Pinned {
numLinesToMoveUp += p.pinnedMessageNumLines
}
for numLinesToMoveUp > 0 {
out.WriteString(text.CursorUp.Sprint())
out.WriteString(text.EraseLine.Sprint())
numLinesToMoveUp--
}
}

func (p *Progress) renderPinnedMessages(out *strings.Builder) {
p.pinnedMessageMutex.RLock()
defer p.pinnedMessageMutex.RUnlock()

numLines := len(p.pinnedMessages)
for _, msg := range p.pinnedMessages {
msg = strings.TrimSpace(msg)
out.WriteString(p.style.Colors.Pinned.Sprint(msg))
out.WriteRune('\n')

numLines += strings.Count(msg, "\n")
}
p.pinnedMessageNumLines = numLines
}

func (p *Progress) renderTracker(out *strings.Builder, t *Tracker, hint renderHint) {
@@ -180,7 +200,6 @@ func (p *Progress) renderTracker(out *strings.Builder, t *Tracker, hint renderHi
}
}

out.WriteString(text.EraseLine.Sprint())
if hint.isOverallTracker {
if !t.IsDone() {
hint := renderHint{hideValue: true, isOverallTracker: true}
@@ -309,6 +328,11 @@ func (p *Progress) renderTrackersDoneAndActive(out *strings.Builder) {
p.logsToRender = nil
p.logsToRenderMutex.Unlock()

// render pinned messages
if len(trackersActive) > 0 && p.style.Visibility.Pinned {
p.renderPinnedMessages(out)
}

// sort and render the active trackers
for _, tracker := range trackersActive {
p.renderTracker(out, tracker, renderHint{})
Loading