k9s/internal/color/colorize.go

85 lines
1.9 KiB
Go

// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of K9s
package color
import (
"fmt"
"strconv"
)
const colorFmt = "\x1b[%dm%s\x1b[0m"
// Paint describes a terminal color.
type Paint int
// Defines basic ANSI colors.
const (
Black Paint = iota + 30 // 30
Red // 31
Green // 32
Yellow // 33
Blue // 34
Magenta // 35
Cyan // 36
LightGray // 37
DarkGray = 90
Bold = 1
)
// Colorize returns an ASCII colored string based on given color.
func Colorize(s string, c Paint) string {
if c == 0 {
return s
}
return fmt.Sprintf(colorFmt, c, s)
}
// ANSIColorize colors a string.
func ANSIColorize(text string, color int) string {
return "\033[38;5;" + strconv.Itoa(color) + "m" + text + "\033[0m"
}
// Highlight colorize bytes at given indices.
func Highlight(bb []byte, ii []int, c int) []byte {
if len(ii) == 0 {
return bb
}
result := make([]byte, 0, len(bb)+len(ii)*20) // Extra space for color codes
// Create a map of byte positions that should be highlighted
highlightMap := make(map[int]bool)
for _, pos := range ii {
highlightMap[pos] = true
}
// Process each byte
for i := 0; i < len(bb); i++ {
if highlightMap[i] {
// Check if this is the start of a UTF-8 character
if (bb[i] & 0xC0) != 0x80 {
// This is the start of a character, find the end
charStart := i
charEnd := i + 1
for charEnd < len(bb) && (bb[charEnd]&0xC0) == 0x80 {
charEnd++
}
// Colorize the entire character
char := string(bb[charStart:charEnd])
colored := ANSIColorize(char, c)
result = append(result, []byte(colored)...)
i = charEnd - 1 // Skip the rest of the character bytes
} else {
// This is a continuation byte, skip it (already handled)
continue
}
} else {
result = append(result, bb[i])
}
}
return result
}