summaryrefslogtreecommitdiffhomepage
path: root/packages/tui/internal/util
diff options
context:
space:
mode:
authorAdam <[email protected]>2025-06-26 10:16:07 -0500
committerGitHub <[email protected]>2025-06-26 10:16:07 -0500
commit7d13baadc84d7377a352c6d58ed9deeea2c918be (patch)
tree575b6897431e390ae8bf4b9ccde2803446c6c67a /packages/tui/internal/util
parentdb24bf87c01d3fff2a9594e55e9fab0d9ef52cfe (diff)
downloadopencode-7d13baadc84d7377a352c6d58ed9deeea2c918be.tar.gz
opencode-7d13baadc84d7377a352c6d58ed9deeea2c918be.zip
feat: default system theme (#419)
Co-authored-by: adamdottv <[email protected]>
Diffstat (limited to 'packages/tui/internal/util')
-rw-r--r--packages/tui/internal/util/color.go93
1 files changed, 93 insertions, 0 deletions
diff --git a/packages/tui/internal/util/color.go b/packages/tui/internal/util/color.go
new file mode 100644
index 000000000..f0d73bcb2
--- /dev/null
+++ b/packages/tui/internal/util/color.go
@@ -0,0 +1,93 @@
+package util
+
+import (
+ "regexp"
+ "strings"
+)
+
+var csiRE *regexp.Regexp
+
+func init() {
+ csiRE = regexp.MustCompile(`\x1b\[([0-9;]+)m`)
+}
+
+var targetFGMap = map[string]string{
+ "0;0;0": "\x1b[30m", // Black
+ "128;0;0": "\x1b[31m", // Red
+ "0;128;0": "\x1b[32m", // Green
+ "128;128;0": "\x1b[33m", // Yellow
+ "0;0;128": "\x1b[34m", // Blue
+ "128;0;128": "\x1b[35m", // Magenta
+ "0;128;128": "\x1b[36m", // Cyan
+ "192;192;192": "\x1b[37m", // White (light grey)
+ "128;128;128": "\x1b[90m", // Bright Black (dark grey)
+ "255;0;0": "\x1b[91m", // Bright Red
+ "0;255;0": "\x1b[92m", // Bright Green
+ "255;255;0": "\x1b[93m", // Bright Yellow
+ "0;0;255": "\x1b[94m", // Bright Blue
+ "255;0;255": "\x1b[95m", // Bright Magenta
+ "0;255;255": "\x1b[96m", // Bright Cyan
+ "255;255;255": "\x1b[97m", // Bright White
+}
+
+var targetBGMap = map[string]string{
+ "0;0;0": "\x1b[40m",
+ "128;0;0": "\x1b[41m",
+ "0;128;0": "\x1b[42m",
+ "128;128;0": "\x1b[43m",
+ "0;0;128": "\x1b[44m",
+ "128;0;128": "\x1b[45m",
+ "0;128;128": "\x1b[46m",
+ "192;192;192": "\x1b[47m",
+ "128;128;128": "\x1b[100m",
+ "255;0;0": "\x1b[101m",
+ "0;255;0": "\x1b[102m",
+ "255;255;0": "\x1b[103m",
+ "0;0;255": "\x1b[104m",
+ "255;0;255": "\x1b[105m",
+ "0;255;255": "\x1b[106m",
+ "255;255;255": "\x1b[107m",
+}
+
+func ConvertRGBToAnsi16Colors(s string) string {
+ return csiRE.ReplaceAllStringFunc(s, func(seq string) string {
+ params := strings.Split(csiRE.FindStringSubmatch(seq)[1], ";")
+ out := make([]string, 0, len(params))
+
+ for i := 0; i < len(params); {
+ // Detect “38 | 48 ; 2 ; r ; g ; b ( ; alpha? )”
+ if (params[i] == "38" || params[i] == "48") &&
+ i+4 < len(params) &&
+ params[i+1] == "2" {
+
+ key := strings.Join(params[i+2:i+5], ";")
+ var repl string
+ if params[i] == "38" {
+ repl = targetFGMap[key]
+ } else {
+ repl = targetBGMap[key]
+ }
+
+ if repl != "" { // exact RGB hit
+ out = append(out, repl[2:len(repl)-1])
+ i += 5 // skip 38/48;2;r;g;b
+
+ // if i == len(params)-1 && looksLikeByte(params[i]) {
+ // i++ // swallow the alpha byte
+ // }
+ continue
+ }
+ }
+ // Normal token — keep verbatim.
+ out = append(out, params[i])
+ i++
+ }
+
+ return "\x1b[" + strings.Join(out, ";") + "m"
+ })
+}
+
+// func looksLikeByte(tok string) bool {
+// v, err := strconv.Atoi(tok)
+// return err == nil && v >= 0 && v <= 255
+// }