169 lines
4.7 KiB
Go
169 lines
4.7 KiB
Go
// 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
|
||
}
|