first commit
This commit is contained in:
168
pkg/ansi/colors.go
Normal file
168
pkg/ansi/colors.go
Normal file
@@ -0,0 +1,168 @@
|
||||
// colors.go - система цветного вывода для fush shell
|
||||
// Преобразует hex цвета в ANSI escape последовательности
|
||||
// Поддерживает 256-цветную палитру для совместимости с терминалами
|
||||
// Автоматически отключает цвета при выводе не в терминал
|
||||
|
||||
package ansi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
// Color представляет ANSI цвет
|
||||
type Color struct {
|
||||
code string
|
||||
}
|
||||
|
||||
// Основные цвета
|
||||
var (
|
||||
Reset = Color{"\033[0m"}
|
||||
Bold = Color{"\033[1m"}
|
||||
Dim = Color{"\033[2m"}
|
||||
Italic = Color{"\033[3m"}
|
||||
Underline = Color{"\033[4m"}
|
||||
|
||||
Black = Color{"\033[30m"}
|
||||
Red = Color{"\033[31m"}
|
||||
Green = Color{"\033[32m"}
|
||||
Yellow = Color{"\033[33m"}
|
||||
Blue = Color{"\033[34m"}
|
||||
Magenta = Color{"\033[35m"}
|
||||
Cyan = Color{"\033[36m"}
|
||||
White = Color{"\033[37m"}
|
||||
|
||||
BrightBlack = Color{"\033[90m"}
|
||||
BrightRed = Color{"\033[91m"}
|
||||
BrightGreen = Color{"\033[92m"}
|
||||
BrightYellow = Color{"\033[93m"}
|
||||
BrightBlue = Color{"\033[94m"}
|
||||
BrightMagenta = Color{"\033[95m"}
|
||||
BrightCyan = Color{"\033[96m"}
|
||||
BrightWhite = Color{"\033[97m"}
|
||||
)
|
||||
|
||||
// HexToANSI преобразует hex цвет в ANSI код
|
||||
func HexToANSI(hex string) (Color, error) {
|
||||
// Удаляем # если есть
|
||||
hex = strings.TrimPrefix(hex, "#")
|
||||
|
||||
if len(hex) != 6 && len(hex) != 3 {
|
||||
return Color{}, fmt.Errorf("неверный формат hex цвета: %s", hex)
|
||||
}
|
||||
|
||||
// Обработка 3-символьных hex кодов (например, #0FF)
|
||||
if len(hex) == 3 {
|
||||
hex = string([]byte{hex[0], hex[0], hex[1], hex[1], hex[2], hex[2]})
|
||||
}
|
||||
|
||||
// Парсим RGB компоненты
|
||||
r, err := strconv.ParseInt(hex[0:2], 16, 64)
|
||||
if err != nil {
|
||||
return Color{}, err
|
||||
}
|
||||
|
||||
g, err := strconv.ParseInt(hex[2:4], 16, 64)
|
||||
if err != nil {
|
||||
return Color{}, err
|
||||
}
|
||||
|
||||
b, err := strconv.ParseInt(hex[4:6], 16, 64)
|
||||
if err != nil {
|
||||
return Color{}, err
|
||||
}
|
||||
|
||||
// Определяем, является ли цвет одним из стандартных
|
||||
if r == 0 && g == 255 && b == 255 {
|
||||
return BrightCyan, nil // #00ffff -> BrightCyan
|
||||
}
|
||||
if r == 255 && g == 255 && b == 0 {
|
||||
return BrightYellow, nil // #ffff00 -> BrightYellow
|
||||
}
|
||||
if r == 0 && g == 255 && b == 0 {
|
||||
return BrightGreen, nil // #00ff00 -> BrightGreen
|
||||
}
|
||||
if r == 255 && g == 0 && b == 0 {
|
||||
return BrightRed, nil // #ff0000 -> BrightRed
|
||||
}
|
||||
if r == 0 && g == 0 && b == 255 {
|
||||
return BrightBlue, nil // #0000ff -> BrightBlue
|
||||
}
|
||||
if r == 255 && g == 0 && b == 255 {
|
||||
return BrightMagenta, nil // #ff00ff -> BrightMagenta
|
||||
}
|
||||
if r == 255 && g == 255 && b == 255 {
|
||||
return BrightWhite, nil // #ffffff -> BrightWhite
|
||||
}
|
||||
if r == 0 && g == 0 && b == 0 {
|
||||
return Black, nil // #000000 -> Black
|
||||
}
|
||||
|
||||
// Используем 256-цветную палитру для других цветов
|
||||
// Формула: 16 + 36*r + 6*g + b, где r,g,b в диапазоне 0-5
|
||||
rIdx := int(r * 5 / 255)
|
||||
gIdx := int(g * 5 / 255)
|
||||
bIdx := int(b * 5 / 255)
|
||||
|
||||
colorCode := 16 + (36 * rIdx) + (6 * gIdx) + bIdx
|
||||
|
||||
return Color{fmt.Sprintf("\033[38;5;%dm", colorCode)}, nil
|
||||
}
|
||||
|
||||
// Colorize окрашивает строку в указанный цвет
|
||||
func Colorize(s string, color Color) string {
|
||||
if !IsTerminalSupported() {
|
||||
return s
|
||||
}
|
||||
return color.code + s + Reset.code
|
||||
}
|
||||
|
||||
// Sprintf форматирует строку с цветом
|
||||
func Sprintf(color Color, format string, args ...interface{}) string {
|
||||
if !IsTerminalSupported() {
|
||||
return fmt.Sprintf(format, args...)
|
||||
}
|
||||
return color.code + fmt.Sprintf(format, args...) + Reset.code
|
||||
}
|
||||
|
||||
// Println выводит строку с цветом
|
||||
func Println(color Color, args ...interface{}) {
|
||||
if !IsTerminalSupported() {
|
||||
fmt.Println(args...)
|
||||
return
|
||||
}
|
||||
fmt.Print(color.code)
|
||||
fmt.Println(args...)
|
||||
fmt.Print(Reset.code)
|
||||
}
|
||||
|
||||
// Printf выводит форматированную строку с цветом
|
||||
func Printf(color Color, format string, args ...interface{}) {
|
||||
if !IsTerminalSupported() {
|
||||
fmt.Printf(format, args...)
|
||||
return
|
||||
}
|
||||
fmt.Print(color.code)
|
||||
fmt.Printf(format, args...)
|
||||
fmt.Print(Reset.code)
|
||||
}
|
||||
|
||||
// IsTerminalSupported проверяет поддержку цвета в терминале
|
||||
func IsTerminalSupported() bool {
|
||||
// Проверяем переменную окружения TERM
|
||||
term := strings.ToLower(os.Getenv("TERM"))
|
||||
if term == "dumb" || term == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
// Проверяем, что вывод идет в терминал
|
||||
if !isatty.IsTerminal(os.Stdout.Fd()) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user