用Go实现类似WinGet风格彩色进度条

用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
}

实用场景

  1. 文件下载:红色→蓝色→绿色表示下载进度
  2. 数据处理:根据处理速度动态调整颜色
  3. 系统监控:CPU/内存使用率颜色预警
  4. 测试进度:测试通过率可视化

注意事项

  1. 终端检测 :运行时检查TERM环境变量
  2. 颜色回退:不支持真彩色时回退到16色
  3. 日志友好:重定向输出时自动禁用颜色
  4. 可访问性:提供选项禁用颜色效果

这个进度条不仅美观实用,更是终端图形化的一次有趣尝试。彩色让命令行不再单调,用户体验大幅提升。

相关推荐
淳朴小学生4 小时前
静态代理和动态代理
后端
渣哥4 小时前
数据一致性全靠它!Spring 事务传播行为没搞懂=大坑
javascript·后端·面试
三七互娱后端团队5 小时前
Serena语义检索在AI CodeReview中的应用
后端
Java水解5 小时前
Nginx平滑升级与location配置案例详解
后端·nginx
渣哥5 小时前
从 READ_UNCOMMITTED 到 SERIALIZABLE:Spring 事务隔离级别全解析
javascript·后端·面试
Codelinghu5 小时前
【bug】大模型微调bug:OSError: Failed to load tokenizer.| Lora
后端
Frank_zhou5 小时前
虚拟线程池
后端
aiopencode5 小时前
iOS混淆与IPA加固实战手记,如何构建苹果应用防反编译体系
后端