1package styles
2
3import (
4 "fmt"
5 "regexp"
6 "strconv"
7 "strings"
8
9 "github.com/charmbracelet/lipgloss"
10)
11
12var ansiEscape = regexp.MustCompile("\x1b\\[[0-9;]*m")
13
14func getColorRGB(c lipgloss.TerminalColor) (uint8, uint8, uint8) {
15 r, g, b, a := c.RGBA()
16
17 // Un-premultiply alpha if needed
18 if a > 0 && a < 0xffff {
19 r = (r * 0xffff) / a
20 g = (g * 0xffff) / a
21 b = (b * 0xffff) / a
22 }
23
24 // Convert from 16-bit to 8-bit color
25 return uint8(r >> 8), uint8(g >> 8), uint8(b >> 8)
26}
27
28func ForceReplaceBackgroundWithLipgloss(input string, newBgColor lipgloss.TerminalColor) string {
29 r, g, b := getColorRGB(newBgColor)
30
31 newBg := fmt.Sprintf("48;2;%d;%d;%d", r, g, b)
32
33 return ansiEscape.ReplaceAllStringFunc(input, func(seq string) string {
34 // Extract content between "\x1b[" and "m"
35 content := seq[2 : len(seq)-1]
36 tokens := strings.Split(content, ";")
37 var newTokens []string
38
39 // Skip background color tokens
40 for i := 0; i < len(tokens); i++ {
41 if tokens[i] == "" {
42 continue
43 }
44
45 val, err := strconv.Atoi(tokens[i])
46 if err != nil {
47 newTokens = append(newTokens, tokens[i])
48 continue
49 }
50
51 // Skip background color tokens
52 if val == 48 {
53 // Skip "48;5;N" or "48;2;R;G;B" sequences
54 if i+1 < len(tokens) {
55 if nextVal, err := strconv.Atoi(tokens[i+1]); err == nil {
56 switch nextVal {
57 case 5:
58 i += 2 // Skip "5" and color index
59 case 2:
60 i += 4 // Skip "2" and RGB components
61 }
62 }
63 }
64 } else if (val < 40 || val > 47) && (val < 100 || val > 107) && val != 49 {
65 // Keep non-background tokens
66 newTokens = append(newTokens, tokens[i])
67 }
68 }
69
70 // Add new background if provided
71 if newBg != "" {
72 newTokens = append(newTokens, strings.Split(newBg, ";")...)
73 }
74
75 if len(newTokens) == 0 {
76 return ""
77 }
78
79 return "\x1b[" + strings.Join(newTokens, ";") + "m"
80 })
81}