用Go实现WinGet风格彩色进度条
命令行界面也可以很酷。受WinGet启发,我用Go实现了一个彩色渐变进度条,让终端交互更有活力。

终端色彩深度解析
ANSI转义码:终端的色彩语言
ANSI转义码始于1970年代,最初用于VT100终端。现代终端已支持24位真彩色:
bash
# 基本格式
\033[38;2;R;G;Bm # 设置前景色
\033[48;2;R;G;Bm # 设置背景色
\033[0m # 重置样式
# 示例:红色文字
echo -e "\033[38;2;255;0;0mHello World\033[0m"
终端兼容性矩阵
终端 | 真彩色支持 | 备注 |
---|---|---|
iTerm2 | ✅ | macOS最佳体验 |
Windows Terminal | ✅ | Windows 10+ |
GNOME Terminal | ✅ | Linux主流 |
cmd.exe | ❌ | 仅支持16色 |
PowerShell | ✅ | Win10+支持真彩色 |
色彩心理学在CLI中的应用
- 红色:警告、错误、高温
- 绿色:完成、成功、安全
- 蓝色:进行中、信息提示
- 黄色:警告、需要注意
核心实现要点
颜色渐变算法
线性插值实现平滑过渡:
go
func getGradientColor(start, end RGB, progress float64) RGB {
r := start.R + int(float64(end.R-start.R)*progress)
g := start.G + int(float64(end.G-start.G)*progress)
b := start.B + int(float64(end.B-start.B)*progress)
return RGB{r, g, b}
}
高效字符串构建
使用strings.Builder
避免内存碎片:
swift
var builder strings.Builder
builder.Grow(100) // 预分配内存
builder.WriteString("\033[38;2;")
// ... 拼接操作
光标控制技巧
\r
:回车回到行首\033[K
:清除当前行\033[A
:上移一行
完整代码实现
go
package main
import (
"fmt"
"math"
"strings"
"time"
)
type RGB struct{ R, G, B int }
type ProgressBar struct {
Width int
StartColor RGB
EndColor RGB
Title string
}
func NewProgressBar(width int, start, end RGB, title string) *ProgressBar {
return &ProgressBar{
Width: width,
StartColor: start,
EndColor: end,
Title: title,
}
}
func (p *ProgressBar) getColor(progress float64) RGB {
progress = math.Max(0, math.Min(1, progress))
r := p.StartColor.R + int(float64(p.EndColor.R-p.StartColor.R)*progress)
g := p.StartColor.G + int(float64(p.EndColor.G-p.StartColor.G)*progress)
b := p.StartColor.B + int(float64(p.EndColor.B-p.StartColor.B)*progress)
return RGB{r, g, b}
}
func colorCode(rgb RGB) string {
return fmt.Sprintf("\033[38;2;%d;%d;%dm", rgb.R, rgb.G, rgb.B)
}
const resetCode = "\033[0m"
func (p *ProgressBar) Render(progress float64) string {
progress = math.Max(0, math.Min(1, progress))
var builder strings.Builder
builder.Grow(100)
if p.Title != "" {
builder.WriteString(p.Title)
builder.WriteString(" ")
}
completed := int(float64(p.Width) * progress)
for i := 0; i < completed; i++ {
color := p.getColor(float64(i) / float64(p.Width))
builder.WriteString(colorCode(color))
builder.WriteString("█")
}
builder.WriteString(resetCode)
percentColor := p.getColor(progress)
builder.WriteString(colorCode(percentColor))
builder.WriteString(fmt.Sprintf(" %d%%", int(progress*100)))
builder.WriteString(resetCode)
return builder.String()
}
func (p *ProgressBar) Show(progress float64) {
fmt.Printf("\r%s", p.Render(progress))
if progress >= 1.0 {
fmt.Println()
}
}
func main() {
// 示例用法
bar := NewProgressBar(40,
RGB{255, 50, 50},
RGB{50, 255, 50},
"下载:")
for i := 0; i <= 100; i++ {
bar.Show(float64(i) / 100)
time.Sleep(30 * time.Millisecond)
}
fmt.Println("✅ 完成")
}
高级技巧
多段渐变支持
go
func MultiGradient(colors []RGB, progress float64) RGB {
segment := 1.0 / float64(len(colors)-1)
idx := int(progress / segment)
segmentProgress := (progress - float64(idx)*segment) / segment
return getGradientColor(colors[idx], colors[idx+1], segmentProgress)
}
性能优化版本
对于需要高频更新的场景:
go
func (p *ProgressBar) FastRender(progress float64) string {
// 预计算颜色值,避免重复计算
// 使用sync.Pool重用strings.Builder
}
实用场景
- 文件下载:红色→蓝色→绿色表示下载进度
- 数据处理:根据处理速度动态调整颜色
- 系统监控:CPU/内存使用率颜色预警
- 测试进度:测试通过率可视化
注意事项
- 终端检测 :运行时检查
TERM
环境变量 - 颜色回退:不支持真彩色时回退到16色
- 日志友好:重定向输出时自动禁用颜色
- 可访问性:提供选项禁用颜色效果
这个进度条不仅美观实用,更是终端图形化的一次有趣尝试。彩色让命令行不再单调,用户体验大幅提升。