func LoadingWidget(chars []rune) WidgetFunc {
	builder := loadingCharBuilder(chars)
	return func(_ *Progress) string {
		return builder()
	}
}
LoadingWidget create a loading progress widget
package progress
import (
	"fmt"
	"runtime"
	"sort"
	"strings"
	"time"
	"github.com/gookit/goutil/fmtutil"
)
var builtinWidgets = map[string]WidgetFunc{
	"elapsed": func(p *Progress) string {  
		elapsed := time.Since(p.StartedAt()).Seconds()
		return fmtutil.HowLongAgo(int64(elapsed))
	},
	"remaining": func(p *Progress) string {  
		step := p.Progress()  
		if p.MaxSteps == 0 || step == 0 {
			return "unknown"
		}
		elapsed := int64(time.Since(p.StartedAt()).Seconds())
		remaining := uint(elapsed) / step * (p.MaxSteps - step)
		return fmtutil.HowLongAgo(int64(remaining))
	},
	"estimated": func(p *Progress) string {  
		step := p.Progress()  
		if p.MaxSteps == 0 || step == 0 {
			return "unknown"
		}
		elapsed := int64(time.Since(p.StartedAt()).Seconds())
		estimated := float32(elapsed) / float32(step) * float32(p.MaxSteps)
		return fmtutil.HowLongAgo(int64(estimated))
	},
	"memory": func(p *Progress) string {  
		mem := new(runtime.MemStats)
		runtime.ReadMemStats(mem)
		return fmtutil.DataSize(mem.Sys)
	},
	"max": func(p *Progress) string {
		return fmt.Sprint(p.MaxSteps)
	},
	"current": func(p *Progress) string {
		step := fmt.Sprint(p.Progress())
		width := fmt.Sprint(p.StepWidth)
		diff := len(width) - len(step)
		if diff <= 0 {
			return step
		}
		return strings.Repeat(" ", diff) + step
	},
	"percent": func(p *Progress) string {
		return fmt.Sprintf("%.1f", p.Percent()*100)
	},
}
func DynamicTextWidget(messages map[int]string) WidgetFunc {
	var numbers []int
	for val := range messages {
		numbers = append(numbers, val)
	}
	sort.Ints(numbers)
	return func(p *Progress) string {
		percent := int(p.Percent() * 100)
		for _, val := range numbers {
			if percent <= val {
				return messages[val]
			}
		}
		return " Handling ..."  
	}
}