refactor: 项目结构重组,src/ 扁平化为根目录,提取 pkg/ 子包
- 模块名重命名 yunshu -> hub.gaomia.site/titor/YunShu - Go 版本升级 1.21 -> 1.25 - src/ 目录删除,所有文件移至根目录 - 新增 pkg/mdprint/: Markdown AST 解析+ANSI 渲染 - 新增 pkg/style/: 终端颜色样式(8色 ANSI + 24位真彩色) - 新增 pkg/termui/: 终端输入组件(交互式输入/密码/确认) - 更新文档:AGENTS.md、architecture.md、changelog.md、taolun.md - gitignore 通配符修复 yunshu.exe -> yunshu.exe*
This commit is contained in:
132
pkg/style/style.go
Normal file
132
pkg/style/style.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package style
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var noColor = os.Getenv("NO_COLOR") != "" || os.Getenv("TERM") == "dumb"
|
||||
|
||||
type Style struct {
|
||||
codes []string
|
||||
}
|
||||
|
||||
func New() *Style {
|
||||
return &Style{}
|
||||
}
|
||||
|
||||
func (s *Style) clone() *Style {
|
||||
c := &Style{codes: make([]string, len(s.codes))}
|
||||
copy(c.codes, s.codes)
|
||||
return c
|
||||
}
|
||||
|
||||
func (s *Style) Bold() *Style {
|
||||
c := s.clone()
|
||||
c.codes = append(c.codes, "1")
|
||||
return c
|
||||
}
|
||||
|
||||
func (s *Style) Dim() *Style {
|
||||
c := s.clone()
|
||||
c.codes = append(c.codes, "2")
|
||||
return c
|
||||
}
|
||||
|
||||
func (s *Style) Italic() *Style {
|
||||
c := s.clone()
|
||||
c.codes = append(c.codes, "3")
|
||||
return c
|
||||
}
|
||||
|
||||
func (s *Style) Underline() *Style {
|
||||
c := s.clone()
|
||||
c.codes = append(c.codes, "4")
|
||||
return c
|
||||
}
|
||||
|
||||
func (s *Style) Fg(c Color) *Style {
|
||||
n := s.clone()
|
||||
n.codes = append(n.codes, fmt.Sprintf("%d", c))
|
||||
return n
|
||||
}
|
||||
|
||||
func (s *Style) Bg(c Color) *Style {
|
||||
n := s.clone()
|
||||
n.codes = append(n.codes, fmt.Sprintf("%d", c+10))
|
||||
return n
|
||||
}
|
||||
|
||||
func (s *Style) FgHex(hex string) *Style {
|
||||
n := s.clone()
|
||||
r, g, b := hexToRGB(hex)
|
||||
n.codes = append(n.codes, fmt.Sprintf("38;2;%d;%d;%d", r, g, b))
|
||||
return n
|
||||
}
|
||||
|
||||
func (s *Style) BgHex(hex string) *Style {
|
||||
n := s.clone()
|
||||
r, g, b := hexToRGB(hex)
|
||||
n.codes = append(n.codes, fmt.Sprintf("48;2;%d;%d;%d", r, g, b))
|
||||
return n
|
||||
}
|
||||
|
||||
func hexToRGB(hex string) (r, g, b int) {
|
||||
hex = strings.TrimPrefix(hex, "#")
|
||||
if len(hex) != 6 {
|
||||
return 255, 255, 255
|
||||
}
|
||||
r = parseHex(hex[0:2])
|
||||
g = parseHex(hex[2:4])
|
||||
b = parseHex(hex[4:6])
|
||||
return
|
||||
}
|
||||
|
||||
func parseHex(s string) int {
|
||||
v := 0
|
||||
for _, c := range s {
|
||||
v *= 16
|
||||
switch {
|
||||
case c >= '0' && c <= '9':
|
||||
v += int(c - '0')
|
||||
case c >= 'a' && c <= 'f':
|
||||
v += int(c - 'a' + 10)
|
||||
case c >= 'A' && c <= 'F':
|
||||
v += int(c - 'A' + 10)
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func (s *Style) Render(text string) string {
|
||||
if noColor || len(s.codes) == 0 {
|
||||
return text
|
||||
}
|
||||
return "\033[" + strings.Join(s.codes, ";") + "m" + text + "\033[0m"
|
||||
}
|
||||
|
||||
type Color int
|
||||
|
||||
const (
|
||||
ColorBlack Color = 30
|
||||
ColorRed Color = 31
|
||||
ColorGreen Color = 32
|
||||
ColorYellow Color = 33
|
||||
ColorBlue Color = 34
|
||||
ColorMagenta Color = 35
|
||||
ColorCyan Color = 36
|
||||
ColorWhite Color = 37
|
||||
)
|
||||
|
||||
var (
|
||||
Red = New().Fg(ColorRed)
|
||||
Green = New().Fg(ColorGreen)
|
||||
Yellow = New().Fg(ColorYellow)
|
||||
Cyan = New().Fg(ColorCyan)
|
||||
Blue = New().Fg(ColorBlue)
|
||||
Magenta = New().Fg(ColorMagenta)
|
||||
White = New().Fg(ColorWhite)
|
||||
Bold = New().Bold()
|
||||
Dim = New().Dim()
|
||||
)
|
||||
Reference in New Issue
Block a user