vbauerster / mpb

multi progress bar for Go cli applications
The Unlicense
2.29k stars 123 forks source link

Add width option that allows Decorator to be cut off in its length #55

Closed nektro closed 4 years ago

nektro commented 4 years ago

This issue has popped up due to the fact that the way I use mpb I don't always know the exact titles that are going to be on all the bars I use, namely URLs. This leads to a situation where the line overflows and then the erase/redraw isn't clean and repeats a bunch of lines until the bar is finished/removed.

So being able to set a particular decorator as 'able to be cropped' would be very handy.

(If you're unsure of what I'm referring to I can try and reproduce and at screenshots at a later time.)

vbauerster commented 4 years ago

Yes please screenshot would be helpful.

nektro commented 4 years ago

image

nektro commented 4 years ago

image

vbauerster commented 4 years ago

There is such option which is effective if no any WCsync... = DSyncWidth involved. WCsync... option means sync width among multiple bars of the same column decorator. If you still want to limit width in that case (allow width sync among same column decorators, but limit it by some value), you can use something like following:

func LimitWidthDecorator(str string, limit int, wcc ...decor.WC) decor.Decorator {
    format := fmt.Sprintf("%%.%ds", limit)
    return decor.Any(func(*decor.Statistics) string {
        return fmt.Sprintf(format, str)
    }, wcc...)
}
nektro commented 4 years ago

I'm not trying to set a max width for a column, in this particular case I want to be able to say that the title decorator's (the one with the url in this case) length is not important. This way, if mpb goes to print a line and determines that it is wider than the current terminal, it can be shrunk, just as the progress bar itself has in the pictures above.

vbauerster commented 4 years ago

I've refactored decor.Statistics to include two new fields OccupiedWidth and TermWidth. So basically you can do something like following, hope it helps.

fn := func(s decor.Statistics) string {
    longString := getLongStringFromSomewhere()
    if s.OccupiedWidth + utf8.RuneCountInString(longString) > s.TermWidth {
        // need to cut longString here,
        // but leave some space for the bar, otherwise it will be shrinked
        availableWidth := s.TermWidth - s.OccupiedWidth
        //cutString, so its final len is less than availableWidth
        return cutStrting
    }
    return longString
}
// convert fn to decorator
decor.Any(fn, decor.WCsyncWidth)
nektro commented 4 years ago

Will update and check this out, thanks!

vbauerster commented 4 years ago

I've changed decor.Statistics, so aforementioned snippet should now look like this:

fn := func(s decor.Statistics) string {
    longString := getLongStringFromSomewhere()
    if utf8.RuneCountInString(longString) > s.AvailableWidth {
        // need to cut longString, so it's less than s.AvailableWidth
        return cutStrting
    }
    return longString
}
// convert fn to decorator
decor.Any(fn, decor.WCsyncWidth)
vbauerster commented 4 years ago

So you can either manually track and limit decorator's width as described above, or don't take any action at all. In latter case decorator's part will be truncated:

Screenshot-2020-05-15-at-13-42-47.png Here PrependDecorators have been truncated ↑.

Screenshot-2020-05-15-at-13-43-42.png Here AppendDecorators have been truncated ↑.