Skip to content

Commit

Permalink
Merge pull request #194 from luo-cheng-xi/feature-scrolling-detail
Browse files Browse the repository at this point in the history
Feature scrolling detail
  • Loading branch information
schollz authored Sep 15, 2024
2 parents e57a85d + c918cac commit 4c1391b
Showing 1 changed file with 82 additions and 0 deletions.
82 changes: 82 additions & 0 deletions progressbar.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ type state struct {
finished bool
exit bool // Progress bar exit halfway

details []string // details to show,only used when detail row is set to more than 0

rendered string
}

Expand Down Expand Up @@ -123,6 +125,9 @@ type config struct {
// showDescriptionAtLineEnd specifies whether description should be written at line end instead of line start
showDescriptionAtLineEnd bool

// specifies how many rows of details to show,default value is 0 and no details will be shown
maxDetailRow int

stdBuffer bytes.Buffer
}

Expand Down Expand Up @@ -308,6 +313,14 @@ func OptionShowDescriptionAtLineEnd() Option {
}
}

// OptionSetMaxDetailRow sets the max row of details
// the row count should be less than the terminal height, otherwise it will not give you the output you want
func OptionSetMaxDetailRow(row int) Option {
return func(p *ProgressBar) {
p.config.maxDetailRow = row
}
}

var defaultTheme = Theme{Saucer: "█", SaucerPadding: " ", BarStart: "|", BarEnd: "|"}

// NewOptions constructs a new instance of ProgressBar, with any options you specify
Expand Down Expand Up @@ -341,6 +354,10 @@ func NewOptions64(max int64, options ...Option) *ProgressBar {
panic("invalid spinner type, must be between 0 and 75")
}

if b.config.maxDetailRow < 0 {
panic("invalid max detail row, must be greater than 0")
}

// ignoreLength if max bytes not known
if b.config.max == -1 {
b.config.ignoreLength = true
Expand Down Expand Up @@ -596,6 +613,66 @@ func (p *ProgressBar) Add64(num int64) error {
return nil
}

// AddDetail adds a detail to the progress bar. Only used when maxDetailRow is set to a value greater than 0
func (p *ProgressBar) AddDetail(detail string) error {
if p.config.maxDetailRow == 0 {
return errors.New("maxDetailRow is set to 0, cannot add detail")
}
if p.IsFinished() {
return errors.New("cannot add detail to a finished progress bar")
}

p.lock.Lock()
defer p.lock.Unlock()
if p.state.details == nil {
// if we add a detail before the first add, it will be weird that we have detail but don't have the progress bar in the top.
// so when we add the first detail, we will render the progress bar first.
if err := p.render(); err != nil {
return err
}
}
p.state.details = append(p.state.details, detail)
if len(p.state.details) > p.config.maxDetailRow {
p.state.details = p.state.details[1:]
}
if err := p.renderDetails(); err != nil {
return err
}
return nil
}

// renderDetails renders the details of the progress bar
func (p *ProgressBar) renderDetails() error {
if p.config.invisible {
return nil
}
if p.state.finished {
return nil
}
if p.config.maxDetailRow == 0 {
return nil
}

b := strings.Builder{}
b.WriteString("\n")

// render the details row
for _, detail := range p.state.details {
b.WriteString(fmt.Sprintf("\u001B[K\r%s\n", detail))
}
// add empty lines to fill the maxDetailRow
for i := len(p.state.details); i < p.config.maxDetailRow; i++ {
b.WriteString("\u001B[K\n")
}

// move the cursor up to the start of the details row
b.WriteString(fmt.Sprintf("\u001B[%dF", p.config.maxDetailRow+1))

writeString(p.config, b.String())

return nil
}

// Clear erases the progress bar from the current line
func (p *ProgressBar) Clear() error {
return clearProgressBar(p.config, p.state)
Expand Down Expand Up @@ -695,6 +772,11 @@ func (p *ProgressBar) render() error {
io.Copy(p.config.writer, &p.config.stdBuffer)
renderProgressBar(p.config, &p.state)
}
if p.config.maxDetailRow > 0 {
p.renderDetails()
// put the cursor back to the last line of the details
writeString(p.config, fmt.Sprintf("\u001B[%dB\r\u001B[%dC", p.config.maxDetailRow, len(p.state.details[len(p.state.details)-1])))
}
if p.config.onCompletion != nil {
p.config.onCompletion()
}
Expand Down

0 comments on commit 4c1391b

Please sign in to comment.