tui/progress/progress.go

191 lines
3.6 KiB
Go
Raw Normal View History

2024-11-01 21:04:01 +01:00
package progress
import (
2024-11-11 22:36:22 +01:00
"egtyl.xyz/omnibill/tui"
2024-11-01 21:04:01 +01:00
"fmt"
"math"
"regexp"
"strconv"
"strings"
"sync"
"golang.org/x/term"
)
var regex = regexp.MustCompile("\033\\[[0-9;]+m")
//║░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░║ 40 characters
type ProgressInfo struct {
Size int64
Desc string
ClearOnFinish bool
}
type ProgressBar struct {
lock sync.Mutex
maxBytes int64
currentBytes int64
hasStarted bool
currentPercent int
desc string
clearFinish bool
textWidth int
}
func New(info ProgressInfo) *ProgressBar {
return &ProgressBar{
maxBytes: info.Size,
desc: info.Desc,
clearFinish: info.ClearOnFinish,
}
}
func (p *ProgressBar) render(final bool) {
var sb strings.Builder
numFilled := math.Round((float64(p.currentBytes) / float64(p.maxBytes)) * 40)
numBlank := 40 - numFilled
donePercent := math.Round(float64(p.currentBytes) / float64(p.maxBytes) * 100)
if int(donePercent) == p.currentPercent && !final {
2024-11-01 21:04:01 +01:00
return
}
p.currentPercent = int(donePercent)
2024-11-01 21:04:01 +01:00
var blockColor string
if final {
blockColor = tui.FgColorGreen
} else {
blockColor = tui.FgColorGold
}
sb.WriteString(p.desc)
sb.WriteString(" ")
percentString := strconv.Itoa(int(donePercent)) + "%"
blankPercent := 4 - len(percentString)
for i := 0; i < blankPercent; i++ {
sb.WriteString(" ")
}
sb.WriteString(percentString)
sb.WriteString(tui.Format(tui.FmtBold, tui.FgColorGrey) + " [" + tui.FmtReset)
//sb.WriteString("\033[1m\033[38;5;247m [\033[0m")
for i := 0; i < int(numFilled); i++ {
sb.WriteString(blockColor + "█" + tui.FmtReset)
//sb.WriteString(fmt.Sprintf("%sm█\033[0m", blockColor))
}
if numFilled < 40 {
numBlank = numBlank - 1
sb.WriteString(tui.FgColorGold + "▒" + tui.FmtReset)
//sb.WriteString("\033[38;5;214m▒\033[0m")
for i := 0; i < int(numBlank); i++ {
sb.WriteString(tui.FgColorGrey + "░" + tui.FmtReset)
//sb.WriteString("\033[38;5;247m░\033[0m")
}
} else {
for i := 0; i < int(numBlank); i++ {
sb.WriteString(tui.FgColorGrey + "░" + tui.FmtReset)
//sb.WriteString("\033[38;5;247m░\033[0m")
}
}
sb.WriteString(tui.Format(tui.FmtBold, tui.FgColorGrey) + "]" + tui.FmtReset)
//sb.WriteString("\033[1m\033[38;5;247m]\033[0m")
width, _, err := term.GetSize(0)
if err != nil {
return
}
var lineNum int
if width == 0 {
lineNum = 1
} else {
2024-12-03 14:34:17 +01:00
lineNum = (len(removeANSIEscapeCodes(sb.String())) + width - 1) / width
2024-11-01 21:04:01 +01:00
}
if p.hasStarted {
for i := 0; i < lineNum; i++ {
if i == lineNum-1 {
fmt.Println("\033[A\033[0G\033[K" + sb.String())
} else {
fmt.Println("\033[A\033[0G\033[K")
}
}
} else {
fmt.Println(sb.String())
p.hasStarted = true
}
p.textWidth = len(removeANSIEscapeCodes(sb.String()))
}
func (p *ProgressBar) Add(num int64) {
2024-12-03 14:34:17 +01:00
p.lock.Lock()
2024-11-01 21:04:01 +01:00
p.currentBytes = p.currentBytes + num
p.render(false)
2024-12-03 14:34:17 +01:00
p.lock.Unlock()
2024-11-01 21:04:01 +01:00
}
func (p *ProgressBar) Close() (err error) {
if p.clearFinish {
width, _, err := term.GetSize(0)
if err != nil {
return err
}
var lineNum int
if width == 0 {
lineNum = 1
} else {
2024-12-03 14:34:17 +01:00
lineNum = (p.textWidth + width - 1) / width
2024-11-01 21:04:01 +01:00
}
for i := 0; i < lineNum; i++ {
fmt.Println("\033[A\033[0G\033[K")
}
} else {
p.render(true)
}
return
}
func (p *ProgressBar) Write(b []byte) (n int, err error) {
n = len(b)
p.Add(int64(n))
return
}
func (p *ProgressBar) Read(b []byte) (n int, err error) {
p.Add(int64(n))
return
}
func removeANSIEscapeCodes(input string) string {
return regex.ReplaceAllString(input, "")
}