diff options
| author | Kujtim Hoxha <[email protected]> | 2025-04-21 19:59:35 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-04-21 19:59:35 +0200 |
| commit | f33dff87725764af0b675b5e5b2e011b21c14c90 (patch) | |
| tree | 4fe2c022305f13775f2cab3cdd80cd808259765b /internal/tui/styles | |
| parent | 6b1c64bcc75b89c530294b6a2d4404682b435d56 (diff) | |
| parent | 3a6a26981a8074b6ab0eaadb520db986e04799ff (diff) | |
| download | opencode-f33dff87725764af0b675b5e5b2e011b21c14c90.tar.gz opencode-f33dff87725764af0b675b5e5b2e011b21c14c90.zip | |
Merge pull request #27 from kujtimiihoxha/opencode
OpenCode - Initial Implementation
Diffstat (limited to 'internal/tui/styles')
| -rw-r--r-- | internal/tui/styles/background.go | 123 | ||||
| -rw-r--r-- | internal/tui/styles/icons.go | 20 | ||||
| -rw-r--r-- | internal/tui/styles/markdown.go | 447 | ||||
| -rw-r--r-- | internal/tui/styles/styles.go | 49 |
4 files changed, 624 insertions, 15 deletions
diff --git a/internal/tui/styles/background.go b/internal/tui/styles/background.go new file mode 100644 index 000000000..2fbb34efb --- /dev/null +++ b/internal/tui/styles/background.go @@ -0,0 +1,123 @@ +package styles + +import ( + "fmt" + "regexp" + "strings" + + "github.com/charmbracelet/lipgloss" +) + +var ansiEscape = regexp.MustCompile("\x1b\\[[0-9;]*m") + +func getColorRGB(c lipgloss.TerminalColor) (uint8, uint8, uint8) { + r, g, b, a := c.RGBA() + + // Un-premultiply alpha if needed + if a > 0 && a < 0xffff { + r = (r * 0xffff) / a + g = (g * 0xffff) / a + b = (b * 0xffff) / a + } + + // Convert from 16-bit to 8-bit color + return uint8(r >> 8), uint8(g >> 8), uint8(b >> 8) +} + +// ForceReplaceBackgroundWithLipgloss replaces any ANSI background color codes +// in `input` with a single 24‑bit background (48;2;R;G;B). +func ForceReplaceBackgroundWithLipgloss(input string, newBgColor lipgloss.TerminalColor) string { + // Precompute our new-bg sequence once + r, g, b := getColorRGB(newBgColor) + newBg := fmt.Sprintf("48;2;%d;%d;%d", r, g, b) + + return ansiEscape.ReplaceAllStringFunc(input, func(seq string) string { + const ( + escPrefixLen = 2 // "\x1b[" + escSuffixLen = 1 // "m" + ) + + raw := seq + start := escPrefixLen + end := len(raw) - escSuffixLen + + var sb strings.Builder + // reserve enough space: original content minus bg codes + our newBg + sb.Grow((end - start) + len(newBg) + 2) + + // scan from start..end, token by token + for i := start; i < end; { + // find the next ';' or end + j := i + for j < end && raw[j] != ';' { + j++ + } + token := raw[i:j] + + // fast‑path: skip "48;5;N" or "48;2;R;G;B" + if len(token) == 2 && token[0] == '4' && token[1] == '8' { + k := j + 1 + if k < end { + // find next token + l := k + for l < end && raw[l] != ';' { + l++ + } + next := raw[k:l] + if next == "5" { + // skip "48;5;N" + m := l + 1 + for m < end && raw[m] != ';' { + m++ + } + i = m + 1 + continue + } else if next == "2" { + // skip "48;2;R;G;B" + m := l + 1 + for count := 0; count < 3 && m < end; count++ { + for m < end && raw[m] != ';' { + m++ + } + m++ + } + i = m + continue + } + } + } + + // decide whether to keep this token + // manually parse ASCII digits to int + isNum := true + val := 0 + for p := i; p < j; p++ { + c := raw[p] + if c < '0' || c > '9' { + isNum = false + break + } + val = val*10 + int(c-'0') + } + keep := !isNum || + ((val < 40 || val > 47) && (val < 100 || val > 107) && val != 49) + + if keep { + if sb.Len() > 0 { + sb.WriteByte(';') + } + sb.WriteString(token) + } + // advance past this token (and the semicolon) + i = j + 1 + } + + // append our new background + if sb.Len() > 0 { + sb.WriteByte(';') + } + sb.WriteString(newBg) + + return "\x1b[" + sb.String() + "m" + }) +} diff --git a/internal/tui/styles/icons.go b/internal/tui/styles/icons.go index f641984e7..96d1b8976 100644 --- a/internal/tui/styles/icons.go +++ b/internal/tui/styles/icons.go @@ -1,19 +1,13 @@ package styles const ( - SessionsIcon string = "" - ChatIcon string = "" - - BotIcon string = "" - ToolIcon string = "" - UserIcon string = "" + OpenCodeIcon string = "⌬" CheckIcon string = "✓" - ErrorIcon string = "" - WarningIcon string = "" - InfoIcon string = "" - HintIcon string = "" + ErrorIcon string = "✖" + WarningIcon string = "⚠" + InfoIcon string = "" + HintIcon string = "i" SpinnerIcon string = "..." - BugIcon string = "" - SleepIcon string = "" -) + LoadingIcon string = "⟳" +)
\ No newline at end of file diff --git a/internal/tui/styles/markdown.go b/internal/tui/styles/markdown.go index 77dc314f5..52816eab3 100644 --- a/internal/tui/styles/markdown.go +++ b/internal/tui/styles/markdown.go @@ -36,12 +36,13 @@ var catppuccinDark = ansi.StyleConfig{ Italic: boolPtr(true), Prefix: "┃ ", }, - Indent: uintPtr(1), - Margin: uintPtr(defaultMargin), + Indent: uintPtr(1), + IndentToken: stringPtr(BaseStyle.Render(" ")), }, List: ansi.StyleList{ LevelIndent: defaultMargin, StyleBlock: ansi.StyleBlock{ + IndentToken: stringPtr(BaseStyle.Render(" ")), StylePrimitive: ansi.StylePrimitive{ Color: stringPtr(dark.Text().Hex), }, @@ -496,3 +497,445 @@ var catppuccinLight = ansi.StyleConfig{ Color: stringPtr(light.Sapphire().Hex), }, } + +func MarkdownTheme(focused bool) ansi.StyleConfig { + if !focused { + return ASCIIStyleConfig + } else { + return DraculaStyleConfig + } +} + +const ( + defaultListIndent = 2 + defaultListLevelIndent = 4 +) + +var ASCIIStyleConfig = ansi.StyleConfig{ + Document: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + Color: stringPtr(ForgroundDim.Dark), + }, + Indent: uintPtr(1), + IndentToken: stringPtr(BaseStyle.Render(" ")), + }, + BlockQuote: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + }, + Indent: uintPtr(1), + IndentToken: stringPtr("| "), + }, + Paragraph: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + }, + }, + List: ansi.StyleList{ + StyleBlock: ansi.StyleBlock{ + IndentToken: stringPtr(BaseStyle.Render(" ")), + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + }, + }, + LevelIndent: defaultListLevelIndent, + }, + Heading: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + BlockSuffix: "\n", + }, + }, + H1: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + Prefix: "# ", + }, + }, + H2: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + Prefix: "## ", + }, + }, + H3: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + Prefix: "### ", + }, + }, + H4: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + Prefix: "#### ", + }, + }, + H5: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + Prefix: "##### ", + }, + }, + H6: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + Prefix: "###### ", + }, + }, + Strikethrough: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + BlockPrefix: "~~", + BlockSuffix: "~~", + }, + Emph: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + BlockPrefix: "*", + BlockSuffix: "*", + }, + Strong: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + BlockPrefix: "**", + BlockSuffix: "**", + }, + HorizontalRule: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + Format: "\n--------\n", + }, + Item: ansi.StylePrimitive{ + BlockPrefix: "• ", + BackgroundColor: stringPtr(Background.Dark), + }, + Enumeration: ansi.StylePrimitive{ + BlockPrefix: ". ", + BackgroundColor: stringPtr(Background.Dark), + }, + Task: ansi.StyleTask{ + Ticked: "[x] ", + Unticked: "[ ] ", + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + }, + }, + ImageText: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + Format: "Image: {{.text}} →", + }, + Code: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + BlockPrefix: "`", + BlockSuffix: "`", + BackgroundColor: stringPtr(Background.Dark), + }, + }, + CodeBlock: ansi.StyleCodeBlock{ + StyleBlock: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + }, + Margin: uintPtr(defaultMargin), + }, + }, + Table: ansi.StyleTable{ + StyleBlock: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + }, + IndentToken: stringPtr(BaseStyle.Render(" ")), + }, + CenterSeparator: stringPtr("|"), + ColumnSeparator: stringPtr("|"), + RowSeparator: stringPtr("-"), + }, + DefinitionDescription: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + BlockPrefix: "\n* ", + }, +} + +var DraculaStyleConfig = ansi.StyleConfig{ + Document: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + Color: stringPtr(Forground.Dark), + BackgroundColor: stringPtr(Background.Dark), + }, + Indent: uintPtr(defaultMargin), + IndentToken: stringPtr(BaseStyle.Render(" ")), + }, + BlockQuote: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + Color: stringPtr("#f1fa8c"), + Italic: boolPtr(true), + BackgroundColor: stringPtr(Background.Dark), + }, + Indent: uintPtr(defaultMargin), + IndentToken: stringPtr(BaseStyle.Render(" ")), + }, + Paragraph: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + }, + }, + List: ansi.StyleList{ + LevelIndent: defaultMargin, + StyleBlock: ansi.StyleBlock{ + IndentToken: stringPtr(BaseStyle.Render(" ")), + StylePrimitive: ansi.StylePrimitive{ + Color: stringPtr(Forground.Dark), + BackgroundColor: stringPtr(Background.Dark), + }, + }, + }, + Heading: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + BlockSuffix: "\n", + Color: stringPtr(PrimaryColor.Dark), + Bold: boolPtr(true), + BackgroundColor: stringPtr(Background.Dark), + }, + }, + H1: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + Prefix: "# ", + BackgroundColor: stringPtr(Background.Dark), + }, + }, + H2: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + Prefix: "## ", + BackgroundColor: stringPtr(Background.Dark), + }, + }, + H3: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + Prefix: "### ", + BackgroundColor: stringPtr(Background.Dark), + }, + }, + H4: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + Prefix: "#### ", + BackgroundColor: stringPtr(Background.Dark), + }, + }, + H5: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + Prefix: "##### ", + BackgroundColor: stringPtr(Background.Dark), + }, + }, + H6: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + Prefix: "###### ", + BackgroundColor: stringPtr(Background.Dark), + }, + }, + Strikethrough: ansi.StylePrimitive{ + CrossedOut: boolPtr(true), + BackgroundColor: stringPtr(Background.Dark), + }, + Emph: ansi.StylePrimitive{ + Color: stringPtr("#f1fa8c"), + Italic: boolPtr(true), + BackgroundColor: stringPtr(Background.Dark), + }, + Strong: ansi.StylePrimitive{ + Bold: boolPtr(true), + Color: stringPtr(Blue.Dark), + BackgroundColor: stringPtr(Background.Dark), + }, + HorizontalRule: ansi.StylePrimitive{ + Color: stringPtr("#6272A4"), + Format: "\n--------\n", + BackgroundColor: stringPtr(Background.Dark), + }, + Item: ansi.StylePrimitive{ + BlockPrefix: "• ", + BackgroundColor: stringPtr(Background.Dark), + }, + Enumeration: ansi.StylePrimitive{ + BlockPrefix: ". ", + Color: stringPtr("#8be9fd"), + BackgroundColor: stringPtr(Background.Dark), + }, + Task: ansi.StyleTask{ + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + }, + Ticked: "[✓] ", + Unticked: "[ ] ", + }, + Link: ansi.StylePrimitive{ + Color: stringPtr("#8be9fd"), + Underline: boolPtr(true), + BackgroundColor: stringPtr(Background.Dark), + }, + LinkText: ansi.StylePrimitive{ + Color: stringPtr("#ff79c6"), + BackgroundColor: stringPtr(Background.Dark), + }, + Image: ansi.StylePrimitive{ + Color: stringPtr("#8be9fd"), + Underline: boolPtr(true), + BackgroundColor: stringPtr(Background.Dark), + }, + ImageText: ansi.StylePrimitive{ + Color: stringPtr("#ff79c6"), + Format: "Image: {{.text}} →", + BackgroundColor: stringPtr(Background.Dark), + }, + Code: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + Color: stringPtr("#50fa7b"), + BackgroundColor: stringPtr(Background.Dark), + }, + }, + Text: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + }, + DefinitionList: ansi.StyleBlock{}, + CodeBlock: ansi.StyleCodeBlock{ + StyleBlock: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + Color: stringPtr(Blue.Dark), + BackgroundColor: stringPtr(Background.Dark), + }, + Margin: uintPtr(defaultMargin), + }, + Chroma: &ansi.Chroma{ + NameOther: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + }, + Literal: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + }, + NameException: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + }, + LiteralDate: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + }, + Text: ansi.StylePrimitive{ + Color: stringPtr(Forground.Dark), + BackgroundColor: stringPtr(Background.Dark), + }, + Error: ansi.StylePrimitive{ + Color: stringPtr("#f8f8f2"), + BackgroundColor: stringPtr("#ff5555"), + }, + Comment: ansi.StylePrimitive{ + Color: stringPtr("#6272A4"), + BackgroundColor: stringPtr(Background.Dark), + }, + CommentPreproc: ansi.StylePrimitive{ + Color: stringPtr("#ff79c6"), + BackgroundColor: stringPtr(Background.Dark), + }, + Keyword: ansi.StylePrimitive{ + Color: stringPtr("#ff79c6"), + BackgroundColor: stringPtr(Background.Dark), + }, + KeywordReserved: ansi.StylePrimitive{ + Color: stringPtr("#ff79c6"), + BackgroundColor: stringPtr(Background.Dark), + }, + KeywordNamespace: ansi.StylePrimitive{ + Color: stringPtr("#ff79c6"), + BackgroundColor: stringPtr(Background.Dark), + }, + KeywordType: ansi.StylePrimitive{ + Color: stringPtr("#8be9fd"), + BackgroundColor: stringPtr(Background.Dark), + }, + Operator: ansi.StylePrimitive{ + Color: stringPtr("#ff79c6"), + BackgroundColor: stringPtr(Background.Dark), + }, + Punctuation: ansi.StylePrimitive{ + Color: stringPtr(Forground.Dark), + BackgroundColor: stringPtr(Background.Dark), + }, + Name: ansi.StylePrimitive{ + Color: stringPtr("#8be9fd"), + BackgroundColor: stringPtr(Background.Dark), + }, + NameBuiltin: ansi.StylePrimitive{ + Color: stringPtr("#8be9fd"), + BackgroundColor: stringPtr(Background.Dark), + }, + NameTag: ansi.StylePrimitive{ + Color: stringPtr("#ff79c6"), + BackgroundColor: stringPtr(Background.Dark), + }, + NameAttribute: ansi.StylePrimitive{ + Color: stringPtr("#50fa7b"), + BackgroundColor: stringPtr(Background.Dark), + }, + NameClass: ansi.StylePrimitive{ + Color: stringPtr("#8be9fd"), + BackgroundColor: stringPtr(Background.Dark), + }, + NameConstant: ansi.StylePrimitive{ + Color: stringPtr("#bd93f9"), + BackgroundColor: stringPtr(Background.Dark), + }, + NameDecorator: ansi.StylePrimitive{ + Color: stringPtr("#50fa7b"), + BackgroundColor: stringPtr(Background.Dark), + }, + NameFunction: ansi.StylePrimitive{ + Color: stringPtr("#50fa7b"), + BackgroundColor: stringPtr(Background.Dark), + }, + LiteralNumber: ansi.StylePrimitive{ + Color: stringPtr("#6EEFC0"), + BackgroundColor: stringPtr(Background.Dark), + }, + LiteralString: ansi.StylePrimitive{ + Color: stringPtr("#f1fa8c"), + BackgroundColor: stringPtr(Background.Dark), + }, + LiteralStringEscape: ansi.StylePrimitive{ + Color: stringPtr("#ff79c6"), + BackgroundColor: stringPtr(Background.Dark), + }, + GenericDeleted: ansi.StylePrimitive{ + Color: stringPtr("#ff5555"), + BackgroundColor: stringPtr(Background.Dark), + }, + GenericEmph: ansi.StylePrimitive{ + Color: stringPtr("#f1fa8c"), + Italic: boolPtr(true), + BackgroundColor: stringPtr(Background.Dark), + }, + GenericInserted: ansi.StylePrimitive{ + Color: stringPtr("#50fa7b"), + BackgroundColor: stringPtr(Background.Dark), + }, + GenericStrong: ansi.StylePrimitive{ + Color: stringPtr("#ffb86c"), + Bold: boolPtr(true), + BackgroundColor: stringPtr(Background.Dark), + }, + GenericSubheading: ansi.StylePrimitive{ + Color: stringPtr("#bd93f9"), + BackgroundColor: stringPtr(Background.Dark), + }, + Background: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + }, + }, + }, + Table: ansi.StyleTable{ + StyleBlock: ansi.StyleBlock{ + StylePrimitive: ansi.StylePrimitive{ + BackgroundColor: stringPtr(Background.Dark), + }, + IndentToken: stringPtr(BaseStyle.Render(" ")), + }, + }, + DefinitionDescription: ansi.StylePrimitive{ + BlockPrefix: "\n* ", + BackgroundColor: stringPtr(Background.Dark), + }, +} diff --git a/internal/tui/styles/styles.go b/internal/tui/styles/styles.go index fe92959e1..476339b57 100644 --- a/internal/tui/styles/styles.go +++ b/internal/tui/styles/styles.go @@ -10,6 +10,50 @@ var ( dark = catppuccin.Mocha ) +// NEW STYLES +var ( + Background = lipgloss.AdaptiveColor{ + Dark: "#212121", + Light: "#212121", + } + BackgroundDim = lipgloss.AdaptiveColor{ + Dark: "#2c2c2c", + Light: "#2c2c2c", + } + BackgroundDarker = lipgloss.AdaptiveColor{ + Dark: "#181818", + Light: "#181818", + } + BorderColor = lipgloss.AdaptiveColor{ + Dark: "#4b4c5c", + Light: "#4b4c5c", + } + + Forground = lipgloss.AdaptiveColor{ + Dark: "#d3d3d3", + Light: "#d3d3d3", + } + + ForgroundMid = lipgloss.AdaptiveColor{ + Dark: "#a0a0a0", + Light: "#a0a0a0", + } + + ForgroundDim = lipgloss.AdaptiveColor{ + Dark: "#737373", + Light: "#737373", + } + + BaseStyle = lipgloss.NewStyle(). + Background(Background). + Foreground(Forground) + + PrimaryColor = lipgloss.AdaptiveColor{ + Dark: "#fab283", + Light: "#fab283", + } +) + var ( Regular = lipgloss.NewStyle() Bold = Regular.Bold(true) @@ -120,6 +164,11 @@ var ( Light: light.Peach().Hex, } + Yellow = lipgloss.AdaptiveColor{ + Dark: dark.Yellow().Hex, + Light: light.Yellow().Hex, + } + Primary = Blue Secondary = Mauve |
