diff options
| author | Dax Raad <[email protected]> | 2025-05-18 22:30:41 -0400 |
|---|---|---|
| committer | Dax Raad <[email protected]> | 2025-05-26 12:40:17 -0400 |
| commit | 99af6146d5def31c59993636d60eb75a483a283b (patch) | |
| tree | eb57ed227c15cf9be54bc9f231c83895d812f881 /pkg/tui/theme | |
| parent | 020e0ca039287b73fa33041fbd1bb214e6ccb396 (diff) | |
| download | opencode-99af6146d5def31c59993636d60eb75a483a283b.tar.gz opencode-99af6146d5def31c59993636d60eb75a483a283b.zip | |
openapi
Diffstat (limited to 'pkg/tui/theme')
| -rw-r--r-- | pkg/tui/theme/catppuccin.go | 248 | ||||
| -rw-r--r-- | pkg/tui/theme/dracula.go | 274 | ||||
| -rw-r--r-- | pkg/tui/theme/flexoki.go | 282 | ||||
| -rw-r--r-- | pkg/tui/theme/gruvbox.go | 302 | ||||
| -rw-r--r-- | pkg/tui/theme/manager.go | 265 | ||||
| -rw-r--r-- | pkg/tui/theme/monokai.go | 273 | ||||
| -rw-r--r-- | pkg/tui/theme/onedark.go | 274 | ||||
| -rw-r--r-- | pkg/tui/theme/theme.go | 290 | ||||
| -rw-r--r-- | pkg/tui/theme/theme_test.go | 89 | ||||
| -rw-r--r-- | pkg/tui/theme/tokyonight.go | 274 | ||||
| -rw-r--r-- | pkg/tui/theme/tron.go | 276 |
11 files changed, 2847 insertions, 0 deletions
diff --git a/pkg/tui/theme/catppuccin.go b/pkg/tui/theme/catppuccin.go new file mode 100644 index 000000000..c3c32501e --- /dev/null +++ b/pkg/tui/theme/catppuccin.go @@ -0,0 +1,248 @@ +package theme + +import ( + catppuccin "github.com/catppuccin/go" + "github.com/charmbracelet/lipgloss" +) + +// CatppuccinTheme implements the Theme interface with Catppuccin colors. +// It provides both dark (Mocha) and light (Latte) variants. +type CatppuccinTheme struct { + BaseTheme +} + +// NewCatppuccinTheme creates a new instance of the Catppuccin theme. +func NewCatppuccinTheme() *CatppuccinTheme { + // Get the Catppuccin palettes + mocha := catppuccin.Mocha + latte := catppuccin.Latte + + theme := &CatppuccinTheme{} + + // Base colors + theme.PrimaryColor = lipgloss.AdaptiveColor{ + Dark: mocha.Blue().Hex, + Light: latte.Blue().Hex, + } + theme.SecondaryColor = lipgloss.AdaptiveColor{ + Dark: mocha.Mauve().Hex, + Light: latte.Mauve().Hex, + } + theme.AccentColor = lipgloss.AdaptiveColor{ + Dark: mocha.Peach().Hex, + Light: latte.Peach().Hex, + } + + // Status colors + theme.ErrorColor = lipgloss.AdaptiveColor{ + Dark: mocha.Red().Hex, + Light: latte.Red().Hex, + } + theme.WarningColor = lipgloss.AdaptiveColor{ + Dark: mocha.Peach().Hex, + Light: latte.Peach().Hex, + } + theme.SuccessColor = lipgloss.AdaptiveColor{ + Dark: mocha.Green().Hex, + Light: latte.Green().Hex, + } + theme.InfoColor = lipgloss.AdaptiveColor{ + Dark: mocha.Blue().Hex, + Light: latte.Blue().Hex, + } + + // Text colors + theme.TextColor = lipgloss.AdaptiveColor{ + Dark: mocha.Text().Hex, + Light: latte.Text().Hex, + } + theme.TextMutedColor = lipgloss.AdaptiveColor{ + Dark: mocha.Subtext0().Hex, + Light: latte.Subtext0().Hex, + } + theme.TextEmphasizedColor = lipgloss.AdaptiveColor{ + Dark: mocha.Lavender().Hex, + Light: latte.Lavender().Hex, + } + + // Background colors + theme.BackgroundColor = lipgloss.AdaptiveColor{ + Dark: "#212121", // From existing styles + Light: "#EEEEEE", // Light equivalent + } + theme.BackgroundSecondaryColor = lipgloss.AdaptiveColor{ + Dark: "#2c2c2c", // From existing styles + Light: "#E0E0E0", // Light equivalent + } + theme.BackgroundDarkerColor = lipgloss.AdaptiveColor{ + Dark: "#181818", // From existing styles + Light: "#F5F5F5", // Light equivalent + } + + // Border colors + theme.BorderNormalColor = lipgloss.AdaptiveColor{ + Dark: "#4b4c5c", // From existing styles + Light: "#BDBDBD", // Light equivalent + } + theme.BorderFocusedColor = lipgloss.AdaptiveColor{ + Dark: mocha.Blue().Hex, + Light: latte.Blue().Hex, + } + theme.BorderDimColor = lipgloss.AdaptiveColor{ + Dark: mocha.Surface0().Hex, + Light: latte.Surface0().Hex, + } + + // Diff view colors + theme.DiffAddedColor = lipgloss.AdaptiveColor{ + Dark: "#478247", // From existing diff.go + Light: "#2E7D32", // Light equivalent + } + theme.DiffRemovedColor = lipgloss.AdaptiveColor{ + Dark: "#7C4444", // From existing diff.go + Light: "#C62828", // Light equivalent + } + theme.DiffContextColor = lipgloss.AdaptiveColor{ + Dark: "#a0a0a0", // From existing diff.go + Light: "#757575", // Light equivalent + } + theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{ + Dark: "#a0a0a0", // From existing diff.go + Light: "#757575", // Light equivalent + } + theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{ + Dark: "#DAFADA", // From existing diff.go + Light: "#A5D6A7", // Light equivalent + } + theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{ + Dark: "#FADADD", // From existing diff.go + Light: "#EF9A9A", // Light equivalent + } + theme.DiffAddedBgColor = lipgloss.AdaptiveColor{ + Dark: "#303A30", // From existing diff.go + Light: "#E8F5E9", // Light equivalent + } + theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{ + Dark: "#3A3030", // From existing diff.go + Light: "#FFEBEE", // Light equivalent + } + theme.DiffContextBgColor = lipgloss.AdaptiveColor{ + Dark: "#212121", // From existing diff.go + Light: "#F5F5F5", // Light equivalent + } + theme.DiffLineNumberColor = lipgloss.AdaptiveColor{ + Dark: "#888888", // From existing diff.go + Light: "#9E9E9E", // Light equivalent + } + theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{ + Dark: "#293229", // From existing diff.go + Light: "#C8E6C9", // Light equivalent + } + theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{ + Dark: "#332929", // From existing diff.go + Light: "#FFCDD2", // Light equivalent + } + + // Markdown colors + theme.MarkdownTextColor = lipgloss.AdaptiveColor{ + Dark: mocha.Text().Hex, + Light: latte.Text().Hex, + } + theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{ + Dark: mocha.Mauve().Hex, + Light: latte.Mauve().Hex, + } + theme.MarkdownLinkColor = lipgloss.AdaptiveColor{ + Dark: mocha.Sky().Hex, + Light: latte.Sky().Hex, + } + theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{ + Dark: mocha.Pink().Hex, + Light: latte.Pink().Hex, + } + theme.MarkdownCodeColor = lipgloss.AdaptiveColor{ + Dark: mocha.Green().Hex, + Light: latte.Green().Hex, + } + theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{ + Dark: mocha.Yellow().Hex, + Light: latte.Yellow().Hex, + } + theme.MarkdownEmphColor = lipgloss.AdaptiveColor{ + Dark: mocha.Yellow().Hex, + Light: latte.Yellow().Hex, + } + theme.MarkdownStrongColor = lipgloss.AdaptiveColor{ + Dark: mocha.Peach().Hex, + Light: latte.Peach().Hex, + } + theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{ + Dark: mocha.Overlay0().Hex, + Light: latte.Overlay0().Hex, + } + theme.MarkdownListItemColor = lipgloss.AdaptiveColor{ + Dark: mocha.Blue().Hex, + Light: latte.Blue().Hex, + } + theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{ + Dark: mocha.Sky().Hex, + Light: latte.Sky().Hex, + } + theme.MarkdownImageColor = lipgloss.AdaptiveColor{ + Dark: mocha.Sapphire().Hex, + Light: latte.Sapphire().Hex, + } + theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{ + Dark: mocha.Pink().Hex, + Light: latte.Pink().Hex, + } + theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{ + Dark: mocha.Text().Hex, + Light: latte.Text().Hex, + } + + // Syntax highlighting colors + theme.SyntaxCommentColor = lipgloss.AdaptiveColor{ + Dark: mocha.Overlay1().Hex, + Light: latte.Overlay1().Hex, + } + theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{ + Dark: mocha.Pink().Hex, + Light: latte.Pink().Hex, + } + theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{ + Dark: mocha.Green().Hex, + Light: latte.Green().Hex, + } + theme.SyntaxVariableColor = lipgloss.AdaptiveColor{ + Dark: mocha.Sky().Hex, + Light: latte.Sky().Hex, + } + theme.SyntaxStringColor = lipgloss.AdaptiveColor{ + Dark: mocha.Yellow().Hex, + Light: latte.Yellow().Hex, + } + theme.SyntaxNumberColor = lipgloss.AdaptiveColor{ + Dark: mocha.Teal().Hex, + Light: latte.Teal().Hex, + } + theme.SyntaxTypeColor = lipgloss.AdaptiveColor{ + Dark: mocha.Sky().Hex, + Light: latte.Sky().Hex, + } + theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{ + Dark: mocha.Pink().Hex, + Light: latte.Pink().Hex, + } + theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{ + Dark: mocha.Text().Hex, + Light: latte.Text().Hex, + } + + return theme +} + +func init() { + // Register the Catppuccin theme with the theme manager + RegisterTheme("catppuccin", NewCatppuccinTheme()) +} diff --git a/pkg/tui/theme/dracula.go b/pkg/tui/theme/dracula.go new file mode 100644 index 000000000..29a1457d4 --- /dev/null +++ b/pkg/tui/theme/dracula.go @@ -0,0 +1,274 @@ +package theme + +import ( + "github.com/charmbracelet/lipgloss" +) + +// DraculaTheme implements the Theme interface with Dracula colors. +// It provides both dark and light variants, though Dracula is primarily a dark theme. +type DraculaTheme struct { + BaseTheme +} + +// NewDraculaTheme creates a new instance of the Dracula theme. +func NewDraculaTheme() *DraculaTheme { + // Dracula color palette + // Official colors from https://draculatheme.com/ + darkBackground := "#282a36" + darkCurrentLine := "#44475a" + darkSelection := "#44475a" + darkForeground := "#f8f8f2" + darkComment := "#6272a4" + darkCyan := "#8be9fd" + darkGreen := "#50fa7b" + darkOrange := "#ffb86c" + darkPink := "#ff79c6" + darkPurple := "#bd93f9" + darkRed := "#ff5555" + darkYellow := "#f1fa8c" + darkBorder := "#44475a" + + // Light mode approximation (Dracula is primarily a dark theme) + lightBackground := "#f8f8f2" + lightCurrentLine := "#e6e6e6" + lightSelection := "#d8d8d8" + lightForeground := "#282a36" + lightComment := "#6272a4" + lightCyan := "#0097a7" + lightGreen := "#388e3c" + lightOrange := "#f57c00" + lightPink := "#d81b60" + lightPurple := "#7e57c2" + lightRed := "#e53935" + lightYellow := "#fbc02d" + lightBorder := "#d8d8d8" + + theme := &DraculaTheme{} + + // Base colors + theme.PrimaryColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.SecondaryColor = lipgloss.AdaptiveColor{ + Dark: darkPink, + Light: lightPink, + } + theme.AccentColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + + // Status colors + theme.ErrorColor = lipgloss.AdaptiveColor{ + Dark: darkRed, + Light: lightRed, + } + theme.WarningColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + theme.SuccessColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.InfoColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + + // Text colors + theme.TextColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + theme.TextMutedColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.TextEmphasizedColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + + // Background colors + theme.BackgroundColor = lipgloss.AdaptiveColor{ + Dark: darkBackground, + Light: lightBackground, + } + theme.BackgroundSecondaryColor = lipgloss.AdaptiveColor{ + Dark: darkCurrentLine, + Light: lightCurrentLine, + } + theme.BackgroundDarkerColor = lipgloss.AdaptiveColor{ + Dark: "#21222c", // Slightly darker than background + Light: "#ffffff", // Slightly lighter than background + } + + // Border colors + theme.BorderNormalColor = lipgloss.AdaptiveColor{ + Dark: darkBorder, + Light: lightBorder, + } + theme.BorderFocusedColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.BorderDimColor = lipgloss.AdaptiveColor{ + Dark: darkSelection, + Light: lightSelection, + } + + // Diff view colors + theme.DiffAddedColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.DiffRemovedColor = lipgloss.AdaptiveColor{ + Dark: darkRed, + Light: lightRed, + } + theme.DiffContextColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{ + Dark: "#50fa7b", + Light: "#a5d6a7", + } + theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{ + Dark: "#ff5555", + Light: "#ef9a9a", + } + theme.DiffAddedBgColor = lipgloss.AdaptiveColor{ + Dark: "#2c3b2c", + Light: "#e8f5e9", + } + theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{ + Dark: "#3b2c2c", + Light: "#ffebee", + } + theme.DiffContextBgColor = lipgloss.AdaptiveColor{ + Dark: darkBackground, + Light: lightBackground, + } + theme.DiffLineNumberColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{ + Dark: "#253025", + Light: "#c8e6c9", + } + theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{ + Dark: "#302525", + Light: "#ffcdd2", + } + + // Markdown colors + theme.MarkdownTextColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{ + Dark: darkPink, + Light: lightPink, + } + theme.MarkdownLinkColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.MarkdownCodeColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + theme.MarkdownEmphColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + theme.MarkdownStrongColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.MarkdownListItemColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.MarkdownImageColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + + // Syntax highlighting colors + theme.SyntaxCommentColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{ + Dark: darkPink, + Light: lightPink, + } + theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.SyntaxVariableColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + theme.SyntaxStringColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + theme.SyntaxNumberColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.SyntaxTypeColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{ + Dark: darkPink, + Light: lightPink, + } + theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + + return theme +} + +func init() { + // Register the Dracula theme with the theme manager + RegisterTheme("dracula", NewDraculaTheme()) +} diff --git a/pkg/tui/theme/flexoki.go b/pkg/tui/theme/flexoki.go new file mode 100644 index 000000000..5da5683c5 --- /dev/null +++ b/pkg/tui/theme/flexoki.go @@ -0,0 +1,282 @@ +package theme + +import ( + "github.com/charmbracelet/lipgloss" +) + +// Flexoki color palette constants +const ( + // Base colors + flexokiPaper = "#FFFCF0" // Paper (lightest) + flexokiBase50 = "#F2F0E5" // bg-2 (light) + flexokiBase100 = "#E6E4D9" // ui (light) + flexokiBase150 = "#DAD8CE" // ui-2 (light) + flexokiBase200 = "#CECDC3" // ui-3 (light) + flexokiBase300 = "#B7B5AC" // tx-3 (light) + flexokiBase500 = "#878580" // tx-2 (light) + flexokiBase600 = "#6F6E69" // tx (light) + flexokiBase700 = "#575653" // tx-3 (dark) + flexokiBase800 = "#403E3C" // ui-3 (dark) + flexokiBase850 = "#343331" // ui-2 (dark) + flexokiBase900 = "#282726" // ui (dark) + flexokiBase950 = "#1C1B1A" // bg-2 (dark) + flexokiBlack = "#100F0F" // bg (darkest) + + // Accent colors - Light theme (600) + flexokiRed600 = "#AF3029" + flexokiOrange600 = "#BC5215" + flexokiYellow600 = "#AD8301" + flexokiGreen600 = "#66800B" + flexokiCyan600 = "#24837B" + flexokiBlue600 = "#205EA6" + flexokiPurple600 = "#5E409D" + flexokiMagenta600 = "#A02F6F" + + // Accent colors - Dark theme (400) + flexokiRed400 = "#D14D41" + flexokiOrange400 = "#DA702C" + flexokiYellow400 = "#D0A215" + flexokiGreen400 = "#879A39" + flexokiCyan400 = "#3AA99F" + flexokiBlue400 = "#4385BE" + flexokiPurple400 = "#8B7EC8" + flexokiMagenta400 = "#CE5D97" +) + +// FlexokiTheme implements the Theme interface with Flexoki colors. +// It provides both dark and light variants. +type FlexokiTheme struct { + BaseTheme +} + +// NewFlexokiTheme creates a new instance of the Flexoki theme. +func NewFlexokiTheme() *FlexokiTheme { + theme := &FlexokiTheme{} + + // Base colors + theme.PrimaryColor = lipgloss.AdaptiveColor{ + Dark: flexokiBlue400, + Light: flexokiBlue600, + } + theme.SecondaryColor = lipgloss.AdaptiveColor{ + Dark: flexokiPurple400, + Light: flexokiPurple600, + } + theme.AccentColor = lipgloss.AdaptiveColor{ + Dark: flexokiOrange400, + Light: flexokiOrange600, + } + + // Status colors + theme.ErrorColor = lipgloss.AdaptiveColor{ + Dark: flexokiRed400, + Light: flexokiRed600, + } + theme.WarningColor = lipgloss.AdaptiveColor{ + Dark: flexokiYellow400, + Light: flexokiYellow600, + } + theme.SuccessColor = lipgloss.AdaptiveColor{ + Dark: flexokiGreen400, + Light: flexokiGreen600, + } + theme.InfoColor = lipgloss.AdaptiveColor{ + Dark: flexokiCyan400, + Light: flexokiCyan600, + } + + // Text colors + theme.TextColor = lipgloss.AdaptiveColor{ + Dark: flexokiBase300, + Light: flexokiBase600, + } + theme.TextMutedColor = lipgloss.AdaptiveColor{ + Dark: flexokiBase700, + Light: flexokiBase500, + } + theme.TextEmphasizedColor = lipgloss.AdaptiveColor{ + Dark: flexokiYellow400, + Light: flexokiYellow600, + } + + // Background colors + theme.BackgroundColor = lipgloss.AdaptiveColor{ + Dark: flexokiBlack, + Light: flexokiPaper, + } + theme.BackgroundSecondaryColor = lipgloss.AdaptiveColor{ + Dark: flexokiBase950, + Light: flexokiBase50, + } + theme.BackgroundDarkerColor = lipgloss.AdaptiveColor{ + Dark: flexokiBase900, + Light: flexokiBase100, + } + + // Border colors + theme.BorderNormalColor = lipgloss.AdaptiveColor{ + Dark: flexokiBase900, + Light: flexokiBase100, + } + theme.BorderFocusedColor = lipgloss.AdaptiveColor{ + Dark: flexokiBlue400, + Light: flexokiBlue600, + } + theme.BorderDimColor = lipgloss.AdaptiveColor{ + Dark: flexokiBase850, + Light: flexokiBase150, + } + + // Diff view colors + theme.DiffAddedColor = lipgloss.AdaptiveColor{ + Dark: flexokiGreen400, + Light: flexokiGreen600, + } + theme.DiffRemovedColor = lipgloss.AdaptiveColor{ + Dark: flexokiRed400, + Light: flexokiRed600, + } + theme.DiffContextColor = lipgloss.AdaptiveColor{ + Dark: flexokiBase700, + Light: flexokiBase500, + } + theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{ + Dark: flexokiBase700, + Light: flexokiBase500, + } + theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{ + Dark: flexokiGreen400, + Light: flexokiGreen600, + } + theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{ + Dark: flexokiRed400, + Light: flexokiRed600, + } + theme.DiffAddedBgColor = lipgloss.AdaptiveColor{ + Dark: "#1D2419", // Darker green background + Light: "#EFF2E2", // Light green background + } + theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{ + Dark: "#241919", // Darker red background + Light: "#F2E2E2", // Light red background + } + theme.DiffContextBgColor = lipgloss.AdaptiveColor{ + Dark: flexokiBlack, + Light: flexokiPaper, + } + theme.DiffLineNumberColor = lipgloss.AdaptiveColor{ + Dark: flexokiBase700, + Light: flexokiBase500, + } + theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{ + Dark: "#1A2017", // Slightly darker green + Light: "#E5EBD9", // Light green + } + theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{ + Dark: "#201717", // Slightly darker red + Light: "#EBD9D9", // Light red + } + + // Markdown colors + theme.MarkdownTextColor = lipgloss.AdaptiveColor{ + Dark: flexokiBase300, + Light: flexokiBase600, + } + theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{ + Dark: flexokiYellow400, + Light: flexokiYellow600, + } + theme.MarkdownLinkColor = lipgloss.AdaptiveColor{ + Dark: flexokiCyan400, + Light: flexokiCyan600, + } + theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{ + Dark: flexokiMagenta400, + Light: flexokiMagenta600, + } + theme.MarkdownCodeColor = lipgloss.AdaptiveColor{ + Dark: flexokiGreen400, + Light: flexokiGreen600, + } + theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{ + Dark: flexokiCyan400, + Light: flexokiCyan600, + } + theme.MarkdownEmphColor = lipgloss.AdaptiveColor{ + Dark: flexokiYellow400, + Light: flexokiYellow600, + } + theme.MarkdownStrongColor = lipgloss.AdaptiveColor{ + Dark: flexokiOrange400, + Light: flexokiOrange600, + } + theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{ + Dark: flexokiBase800, + Light: flexokiBase200, + } + theme.MarkdownListItemColor = lipgloss.AdaptiveColor{ + Dark: flexokiBlue400, + Light: flexokiBlue600, + } + theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{ + Dark: flexokiBlue400, + Light: flexokiBlue600, + } + theme.MarkdownImageColor = lipgloss.AdaptiveColor{ + Dark: flexokiPurple400, + Light: flexokiPurple600, + } + theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{ + Dark: flexokiMagenta400, + Light: flexokiMagenta600, + } + theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{ + Dark: flexokiBase300, + Light: flexokiBase600, + } + + // Syntax highlighting colors (based on Flexoki's mappings) + theme.SyntaxCommentColor = lipgloss.AdaptiveColor{ + Dark: flexokiBase700, // tx-3 + Light: flexokiBase300, // tx-3 + } + theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{ + Dark: flexokiGreen400, // gr + Light: flexokiGreen600, // gr + } + theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{ + Dark: flexokiOrange400, // or + Light: flexokiOrange600, // or + } + theme.SyntaxVariableColor = lipgloss.AdaptiveColor{ + Dark: flexokiBlue400, // bl + Light: flexokiBlue600, // bl + } + theme.SyntaxStringColor = lipgloss.AdaptiveColor{ + Dark: flexokiCyan400, // cy + Light: flexokiCyan600, // cy + } + theme.SyntaxNumberColor = lipgloss.AdaptiveColor{ + Dark: flexokiPurple400, // pu + Light: flexokiPurple600, // pu + } + theme.SyntaxTypeColor = lipgloss.AdaptiveColor{ + Dark: flexokiYellow400, // ye + Light: flexokiYellow600, // ye + } + theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{ + Dark: flexokiBase500, // tx-2 + Light: flexokiBase500, // tx-2 + } + theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{ + Dark: flexokiBase500, // tx-2 + Light: flexokiBase500, // tx-2 + } + + return theme +} + +func init() { + // Register the Flexoki theme with the theme manager + RegisterTheme("flexoki", NewFlexokiTheme()) +} diff --git a/pkg/tui/theme/gruvbox.go b/pkg/tui/theme/gruvbox.go new file mode 100644 index 000000000..51719faaa --- /dev/null +++ b/pkg/tui/theme/gruvbox.go @@ -0,0 +1,302 @@ +package theme + +import ( + "github.com/charmbracelet/lipgloss" +) + +// Gruvbox color palette constants +const ( + // Dark theme colors + gruvboxDarkBg0 = "#282828" + gruvboxDarkBg0Soft = "#32302f" + gruvboxDarkBg1 = "#3c3836" + gruvboxDarkBg2 = "#504945" + gruvboxDarkBg3 = "#665c54" + gruvboxDarkBg4 = "#7c6f64" + gruvboxDarkFg0 = "#fbf1c7" + gruvboxDarkFg1 = "#ebdbb2" + gruvboxDarkFg2 = "#d5c4a1" + gruvboxDarkFg3 = "#bdae93" + gruvboxDarkFg4 = "#a89984" + gruvboxDarkGray = "#928374" + gruvboxDarkRed = "#cc241d" + gruvboxDarkRedBright = "#fb4934" + gruvboxDarkGreen = "#98971a" + gruvboxDarkGreenBright = "#b8bb26" + gruvboxDarkYellow = "#d79921" + gruvboxDarkYellowBright = "#fabd2f" + gruvboxDarkBlue = "#458588" + gruvboxDarkBlueBright = "#83a598" + gruvboxDarkPurple = "#b16286" + gruvboxDarkPurpleBright = "#d3869b" + gruvboxDarkAqua = "#689d6a" + gruvboxDarkAquaBright = "#8ec07c" + gruvboxDarkOrange = "#d65d0e" + gruvboxDarkOrangeBright = "#fe8019" + + // Light theme colors + gruvboxLightBg0 = "#fbf1c7" + gruvboxLightBg0Soft = "#f2e5bc" + gruvboxLightBg1 = "#ebdbb2" + gruvboxLightBg2 = "#d5c4a1" + gruvboxLightBg3 = "#bdae93" + gruvboxLightBg4 = "#a89984" + gruvboxLightFg0 = "#282828" + gruvboxLightFg1 = "#3c3836" + gruvboxLightFg2 = "#504945" + gruvboxLightFg3 = "#665c54" + gruvboxLightFg4 = "#7c6f64" + gruvboxLightGray = "#928374" + gruvboxLightRed = "#9d0006" + gruvboxLightRedBright = "#cc241d" + gruvboxLightGreen = "#79740e" + gruvboxLightGreenBright = "#98971a" + gruvboxLightYellow = "#b57614" + gruvboxLightYellowBright = "#d79921" + gruvboxLightBlue = "#076678" + gruvboxLightBlueBright = "#458588" + gruvboxLightPurple = "#8f3f71" + gruvboxLightPurpleBright = "#b16286" + gruvboxLightAqua = "#427b58" + gruvboxLightAquaBright = "#689d6a" + gruvboxLightOrange = "#af3a03" + gruvboxLightOrangeBright = "#d65d0e" +) + +// GruvboxTheme implements the Theme interface with Gruvbox colors. +// It provides both dark and light variants. +type GruvboxTheme struct { + BaseTheme +} + +// NewGruvboxTheme creates a new instance of the Gruvbox theme. +func NewGruvboxTheme() *GruvboxTheme { + theme := &GruvboxTheme{} + + // Base colors + theme.PrimaryColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkBlueBright, + Light: gruvboxLightBlueBright, + } + theme.SecondaryColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkPurpleBright, + Light: gruvboxLightPurpleBright, + } + theme.AccentColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkOrangeBright, + Light: gruvboxLightOrangeBright, + } + + // Status colors + theme.ErrorColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkRedBright, + Light: gruvboxLightRedBright, + } + theme.WarningColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkYellowBright, + Light: gruvboxLightYellowBright, + } + theme.SuccessColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkGreenBright, + Light: gruvboxLightGreenBright, + } + theme.InfoColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkBlueBright, + Light: gruvboxLightBlueBright, + } + + // Text colors + theme.TextColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkFg1, + Light: gruvboxLightFg1, + } + theme.TextMutedColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkFg4, + Light: gruvboxLightFg4, + } + theme.TextEmphasizedColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkYellowBright, + Light: gruvboxLightYellowBright, + } + + // Background colors + theme.BackgroundColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkBg0, + Light: gruvboxLightBg0, + } + theme.BackgroundSecondaryColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkBg1, + Light: gruvboxLightBg1, + } + theme.BackgroundDarkerColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkBg0Soft, + Light: gruvboxLightBg0Soft, + } + + // Border colors + theme.BorderNormalColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkBg2, + Light: gruvboxLightBg2, + } + theme.BorderFocusedColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkBlueBright, + Light: gruvboxLightBlueBright, + } + theme.BorderDimColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkBg1, + Light: gruvboxLightBg1, + } + + // Diff view colors + theme.DiffAddedColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkGreenBright, + Light: gruvboxLightGreenBright, + } + theme.DiffRemovedColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkRedBright, + Light: gruvboxLightRedBright, + } + theme.DiffContextColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkFg4, + Light: gruvboxLightFg4, + } + theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkFg3, + Light: gruvboxLightFg3, + } + theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkGreenBright, + Light: gruvboxLightGreenBright, + } + theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkRedBright, + Light: gruvboxLightRedBright, + } + theme.DiffAddedBgColor = lipgloss.AdaptiveColor{ + Dark: "#3C4C3C", // Darker green background + Light: "#E8F5E9", // Light green background + } + theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{ + Dark: "#4C3C3C", // Darker red background + Light: "#FFEBEE", // Light red background + } + theme.DiffContextBgColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkBg0, + Light: gruvboxLightBg0, + } + theme.DiffLineNumberColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkFg4, + Light: gruvboxLightFg4, + } + theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{ + Dark: "#32432F", // Slightly darker green + Light: "#C8E6C9", // Light green + } + theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{ + Dark: "#43322F", // Slightly darker red + Light: "#FFCDD2", // Light red + } + + // Markdown colors + theme.MarkdownTextColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkFg1, + Light: gruvboxLightFg1, + } + theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkYellowBright, + Light: gruvboxLightYellowBright, + } + theme.MarkdownLinkColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkBlueBright, + Light: gruvboxLightBlueBright, + } + theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkAquaBright, + Light: gruvboxLightAquaBright, + } + theme.MarkdownCodeColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkGreenBright, + Light: gruvboxLightGreenBright, + } + theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkAquaBright, + Light: gruvboxLightAquaBright, + } + theme.MarkdownEmphColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkYellowBright, + Light: gruvboxLightYellowBright, + } + theme.MarkdownStrongColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkOrangeBright, + Light: gruvboxLightOrangeBright, + } + theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkBg3, + Light: gruvboxLightBg3, + } + theme.MarkdownListItemColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkBlueBright, + Light: gruvboxLightBlueBright, + } + theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkBlueBright, + Light: gruvboxLightBlueBright, + } + theme.MarkdownImageColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkPurpleBright, + Light: gruvboxLightPurpleBright, + } + theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkAquaBright, + Light: gruvboxLightAquaBright, + } + theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkFg1, + Light: gruvboxLightFg1, + } + + // Syntax highlighting colors + theme.SyntaxCommentColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkGray, + Light: gruvboxLightGray, + } + theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkRedBright, + Light: gruvboxLightRedBright, + } + theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkGreenBright, + Light: gruvboxLightGreenBright, + } + theme.SyntaxVariableColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkBlueBright, + Light: gruvboxLightBlueBright, + } + theme.SyntaxStringColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkYellowBright, + Light: gruvboxLightYellowBright, + } + theme.SyntaxNumberColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkPurpleBright, + Light: gruvboxLightPurpleBright, + } + theme.SyntaxTypeColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkYellow, + Light: gruvboxLightYellow, + } + theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkAquaBright, + Light: gruvboxLightAquaBright, + } + theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{ + Dark: gruvboxDarkFg1, + Light: gruvboxLightFg1, + } + + return theme +} + +func init() { + // Register the Gruvbox theme with the theme manager + RegisterTheme("gruvbox", NewGruvboxTheme()) +} diff --git a/pkg/tui/theme/manager.go b/pkg/tui/theme/manager.go new file mode 100644 index 000000000..5a5c791fb --- /dev/null +++ b/pkg/tui/theme/manager.go @@ -0,0 +1,265 @@ +package theme + +import ( + "fmt" + "log/slog" + "slices" + "strings" + "sync" + + "github.com/alecthomas/chroma/v2/styles" + "github.com/sst/opencode/internal/config" +) + +// Manager handles theme registration, selection, and retrieval. +// It maintains a registry of available themes and tracks the currently active theme. +type Manager struct { + themes map[string]Theme + currentName string + mu sync.RWMutex +} + +// Global instance of the theme manager +var globalManager = &Manager{ + themes: make(map[string]Theme), + currentName: "", +} + +// Default theme instance for custom theme defaulting +var defaultThemeColors = NewOpenCodeTheme() + +// RegisterTheme adds a new theme to the registry. +// If this is the first theme registered, it becomes the default. +func RegisterTheme(name string, theme Theme) { + globalManager.mu.Lock() + defer globalManager.mu.Unlock() + + globalManager.themes[name] = theme + + // If this is the first theme, make it the default + if globalManager.currentName == "" { + globalManager.currentName = name + } +} + +// SetTheme changes the active theme to the one with the specified name. +// Returns an error if the theme doesn't exist. +func SetTheme(name string) error { + globalManager.mu.Lock() + defer globalManager.mu.Unlock() + + delete(styles.Registry, "charm") + + // Handle custom theme + if name == "custom" { + cfg := config.Get() + if cfg == nil || cfg.TUI.CustomTheme == nil || len(cfg.TUI.CustomTheme) == 0 { + return fmt.Errorf("custom theme selected but no custom theme colors defined in config") + } + + customTheme, err := LoadCustomTheme(cfg.TUI.CustomTheme) + if err != nil { + return fmt.Errorf("failed to load custom theme: %w", err) + } + + // Register the custom theme + globalManager.themes["custom"] = customTheme + } else if _, exists := globalManager.themes[name]; !exists { + return fmt.Errorf("theme '%s' not found", name) + } + + globalManager.currentName = name + + // Update the config file using viper + if err := updateConfigTheme(name); err != nil { + // Log the error but don't fail the theme change + slog.Warn("Warning: Failed to update config file with new theme", "err", err) + } + + return nil +} + +// CurrentTheme returns the currently active theme. +// If no theme is set, it returns nil. +func CurrentTheme() Theme { + globalManager.mu.RLock() + defer globalManager.mu.RUnlock() + + if globalManager.currentName == "" { + return nil + } + + return globalManager.themes[globalManager.currentName] +} + +// CurrentThemeName returns the name of the currently active theme. +func CurrentThemeName() string { + globalManager.mu.RLock() + defer globalManager.mu.RUnlock() + + return globalManager.currentName +} + +// AvailableThemes returns a list of all registered theme names. +func AvailableThemes() []string { + globalManager.mu.RLock() + defer globalManager.mu.RUnlock() + + names := make([]string, 0, len(globalManager.themes)) + for name := range globalManager.themes { + names = append(names, name) + } + slices.SortFunc(names, func(a, b string) int { + if a == "opencode" { + return -1 + } else if b == "opencode" { + return 1 + } + return strings.Compare(a, b) + }) + return names +} + +// GetTheme returns a specific theme by name. +// Returns nil if the theme doesn't exist. +func GetTheme(name string) Theme { + globalManager.mu.RLock() + defer globalManager.mu.RUnlock() + + return globalManager.themes[name] +} + +// LoadCustomTheme creates a new theme instance based on the custom theme colors +// defined in the configuration. It uses the default OpenCode theme as a base +// and overrides colors that are specified in the customTheme map. +func LoadCustomTheme(customTheme map[string]any) (Theme, error) { + // Create a new theme based on the default OpenCode theme + theme := NewOpenCodeTheme() + + // Process each color in the custom theme map + for key, value := range customTheme { + adaptiveColor, err := ParseAdaptiveColor(value) + if err != nil { + slog.Warn("Invalid color definition in custom theme", "key", key, "error", err) + continue // Skip this color but continue processing others + } + + // Set the color in the theme based on the key + switch strings.ToLower(key) { + case "primary": + theme.PrimaryColor = adaptiveColor + case "secondary": + theme.SecondaryColor = adaptiveColor + case "accent": + theme.AccentColor = adaptiveColor + case "error": + theme.ErrorColor = adaptiveColor + case "warning": + theme.WarningColor = adaptiveColor + case "success": + theme.SuccessColor = adaptiveColor + case "info": + theme.InfoColor = adaptiveColor + case "text": + theme.TextColor = adaptiveColor + case "textmuted": + theme.TextMutedColor = adaptiveColor + case "textemphasized": + theme.TextEmphasizedColor = adaptiveColor + case "background": + theme.BackgroundColor = adaptiveColor + case "backgroundsecondary": + theme.BackgroundSecondaryColor = adaptiveColor + case "backgrounddarker": + theme.BackgroundDarkerColor = adaptiveColor + case "bordernormal": + theme.BorderNormalColor = adaptiveColor + case "borderfocused": + theme.BorderFocusedColor = adaptiveColor + case "borderdim": + theme.BorderDimColor = adaptiveColor + case "diffadded": + theme.DiffAddedColor = adaptiveColor + case "diffremoved": + theme.DiffRemovedColor = adaptiveColor + case "diffcontext": + theme.DiffContextColor = adaptiveColor + case "diffhunkheader": + theme.DiffHunkHeaderColor = adaptiveColor + case "diffhighlightadded": + theme.DiffHighlightAddedColor = adaptiveColor + case "diffhighlightremoved": + theme.DiffHighlightRemovedColor = adaptiveColor + case "diffaddedbg": + theme.DiffAddedBgColor = adaptiveColor + case "diffremovedbg": + theme.DiffRemovedBgColor = adaptiveColor + case "diffcontextbg": + theme.DiffContextBgColor = adaptiveColor + case "difflinenumber": + theme.DiffLineNumberColor = adaptiveColor + case "diffaddedlinenumberbg": + theme.DiffAddedLineNumberBgColor = adaptiveColor + case "diffremovedlinenumberbg": + theme.DiffRemovedLineNumberBgColor = adaptiveColor + case "syntaxcomment": + theme.SyntaxCommentColor = adaptiveColor + case "syntaxkeyword": + theme.SyntaxKeywordColor = adaptiveColor + case "syntaxfunction": + theme.SyntaxFunctionColor = adaptiveColor + case "syntaxvariable": + theme.SyntaxVariableColor = adaptiveColor + case "syntaxstring": + theme.SyntaxStringColor = adaptiveColor + case "syntaxnumber": + theme.SyntaxNumberColor = adaptiveColor + case "syntaxtype": + theme.SyntaxTypeColor = adaptiveColor + case "syntaxoperator": + theme.SyntaxOperatorColor = adaptiveColor + case "syntaxpunctuation": + theme.SyntaxPunctuationColor = adaptiveColor + case "markdowntext": + theme.MarkdownTextColor = adaptiveColor + case "markdownheading": + theme.MarkdownHeadingColor = adaptiveColor + case "markdownlink": + theme.MarkdownLinkColor = adaptiveColor + case "markdownlinktext": + theme.MarkdownLinkTextColor = adaptiveColor + case "markdowncode": + theme.MarkdownCodeColor = adaptiveColor + case "markdownblockquote": + theme.MarkdownBlockQuoteColor = adaptiveColor + case "markdownemph": + theme.MarkdownEmphColor = adaptiveColor + case "markdownstrong": + theme.MarkdownStrongColor = adaptiveColor + case "markdownhorizontalrule": + theme.MarkdownHorizontalRuleColor = adaptiveColor + case "markdownlistitem": + theme.MarkdownListItemColor = adaptiveColor + case "markdownlistitemenum": + theme.MarkdownListEnumerationColor = adaptiveColor + case "markdownimage": + theme.MarkdownImageColor = adaptiveColor + case "markdownimagetext": + theme.MarkdownImageTextColor = adaptiveColor + case "markdowncodeblock": + theme.MarkdownCodeBlockColor = adaptiveColor + case "markdownlistenumeration": + theme.MarkdownListEnumerationColor = adaptiveColor + default: + slog.Warn("Unknown color key in custom theme", "key", key) + } + } + + return theme, nil +} + +// updateConfigTheme updates the theme setting in the configuration file +func updateConfigTheme(themeName string) error { + // Use the config package to update the theme + return config.UpdateTheme(themeName) +} diff --git a/pkg/tui/theme/monokai.go b/pkg/tui/theme/monokai.go new file mode 100644 index 000000000..7511d3333 --- /dev/null +++ b/pkg/tui/theme/monokai.go @@ -0,0 +1,273 @@ +package theme + +import ( + "github.com/charmbracelet/lipgloss" +) + +// MonokaiProTheme implements the Theme interface with Monokai Pro colors. +// It provides both dark and light variants. +type MonokaiProTheme struct { + BaseTheme +} + +// NewMonokaiProTheme creates a new instance of the Monokai Pro theme. +func NewMonokaiProTheme() *MonokaiProTheme { + // Monokai Pro color palette (dark mode) + darkBackground := "#2d2a2e" + darkCurrentLine := "#403e41" + darkSelection := "#5b595c" + darkForeground := "#fcfcfa" + darkComment := "#727072" + darkRed := "#ff6188" + darkOrange := "#fc9867" + darkYellow := "#ffd866" + darkGreen := "#a9dc76" + darkCyan := "#78dce8" + darkBlue := "#ab9df2" + darkPurple := "#ab9df2" + darkBorder := "#403e41" + + // Light mode colors (adapted from dark) + lightBackground := "#fafafa" + lightCurrentLine := "#f0f0f0" + lightSelection := "#e5e5e6" + lightForeground := "#2d2a2e" + lightComment := "#939293" + lightRed := "#f92672" + lightOrange := "#fd971f" + lightYellow := "#e6db74" + lightGreen := "#9bca65" + lightCyan := "#66d9ef" + lightBlue := "#7e75db" + lightPurple := "#ae81ff" + lightBorder := "#d3d3d3" + + theme := &MonokaiProTheme{} + + // Base colors + theme.PrimaryColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.SecondaryColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.AccentColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + + // Status colors + theme.ErrorColor = lipgloss.AdaptiveColor{ + Dark: darkRed, + Light: lightRed, + } + theme.WarningColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + theme.SuccessColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.InfoColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + + // Text colors + theme.TextColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + theme.TextMutedColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.TextEmphasizedColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + + // Background colors + theme.BackgroundColor = lipgloss.AdaptiveColor{ + Dark: darkBackground, + Light: lightBackground, + } + theme.BackgroundSecondaryColor = lipgloss.AdaptiveColor{ + Dark: darkCurrentLine, + Light: lightCurrentLine, + } + theme.BackgroundDarkerColor = lipgloss.AdaptiveColor{ + Dark: "#221f22", // Slightly darker than background + Light: "#ffffff", // Slightly lighter than background + } + + // Border colors + theme.BorderNormalColor = lipgloss.AdaptiveColor{ + Dark: darkBorder, + Light: lightBorder, + } + theme.BorderFocusedColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.BorderDimColor = lipgloss.AdaptiveColor{ + Dark: darkSelection, + Light: lightSelection, + } + + // Diff view colors + theme.DiffAddedColor = lipgloss.AdaptiveColor{ + Dark: "#a9dc76", + Light: "#9bca65", + } + theme.DiffRemovedColor = lipgloss.AdaptiveColor{ + Dark: "#ff6188", + Light: "#f92672", + } + theme.DiffContextColor = lipgloss.AdaptiveColor{ + Dark: "#a0a0a0", + Light: "#757575", + } + theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{ + Dark: "#a0a0a0", + Light: "#757575", + } + theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{ + Dark: "#c2e7a9", + Light: "#c5e0b4", + } + theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{ + Dark: "#ff8ca6", + Light: "#ffb3c8", + } + theme.DiffAddedBgColor = lipgloss.AdaptiveColor{ + Dark: "#3a4a35", + Light: "#e8f5e9", + } + theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{ + Dark: "#4a3439", + Light: "#ffebee", + } + theme.DiffContextBgColor = lipgloss.AdaptiveColor{ + Dark: darkBackground, + Light: lightBackground, + } + theme.DiffLineNumberColor = lipgloss.AdaptiveColor{ + Dark: "#888888", + Light: "#9e9e9e", + } + theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{ + Dark: "#2d3a28", + Light: "#c8e6c9", + } + theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{ + Dark: "#3d2a2e", + Light: "#ffcdd2", + } + + // Markdown colors + theme.MarkdownTextColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.MarkdownLinkColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.MarkdownCodeColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + theme.MarkdownEmphColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + theme.MarkdownStrongColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.MarkdownListItemColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.MarkdownImageColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + + // Syntax highlighting colors + theme.SyntaxCommentColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{ + Dark: darkRed, + Light: lightRed, + } + theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.SyntaxVariableColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + theme.SyntaxStringColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + theme.SyntaxNumberColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.SyntaxTypeColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + + return theme +} + +func init() { + // Register the Monokai Pro theme with the theme manager + RegisterTheme("monokai", NewMonokaiProTheme()) +} diff --git a/pkg/tui/theme/onedark.go b/pkg/tui/theme/onedark.go new file mode 100644 index 000000000..a2c1447ca --- /dev/null +++ b/pkg/tui/theme/onedark.go @@ -0,0 +1,274 @@ +package theme + +import ( + "github.com/charmbracelet/lipgloss" +) + +// OneDarkTheme implements the Theme interface with Atom's One Dark colors. +// It provides both dark and light variants. +type OneDarkTheme struct { + BaseTheme +} + +// NewOneDarkTheme creates a new instance of the One Dark theme. +func NewOneDarkTheme() *OneDarkTheme { + // One Dark color palette + // Dark mode colors from Atom One Dark + darkBackground := "#282c34" + darkCurrentLine := "#2c313c" + darkSelection := "#3e4451" + darkForeground := "#abb2bf" + darkComment := "#5c6370" + darkRed := "#e06c75" + darkOrange := "#d19a66" + darkYellow := "#e5c07b" + darkGreen := "#98c379" + darkCyan := "#56b6c2" + darkBlue := "#61afef" + darkPurple := "#c678dd" + darkBorder := "#3b4048" + + // Light mode colors from Atom One Light + lightBackground := "#fafafa" + lightCurrentLine := "#f0f0f0" + lightSelection := "#e5e5e6" + lightForeground := "#383a42" + lightComment := "#a0a1a7" + lightRed := "#e45649" + lightOrange := "#da8548" + lightYellow := "#c18401" + lightGreen := "#50a14f" + lightCyan := "#0184bc" + lightBlue := "#4078f2" + lightPurple := "#a626a4" + lightBorder := "#d3d3d3" + + theme := &OneDarkTheme{} + + // Base colors + theme.PrimaryColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.SecondaryColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.AccentColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + + // Status colors + theme.ErrorColor = lipgloss.AdaptiveColor{ + Dark: darkRed, + Light: lightRed, + } + theme.WarningColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + theme.SuccessColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.InfoColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + + // Text colors + theme.TextColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + theme.TextMutedColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.TextEmphasizedColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + + // Background colors + theme.BackgroundColor = lipgloss.AdaptiveColor{ + Dark: darkBackground, + Light: lightBackground, + } + theme.BackgroundSecondaryColor = lipgloss.AdaptiveColor{ + Dark: darkCurrentLine, + Light: lightCurrentLine, + } + theme.BackgroundDarkerColor = lipgloss.AdaptiveColor{ + Dark: "#21252b", // Slightly darker than background + Light: "#ffffff", // Slightly lighter than background + } + + // Border colors + theme.BorderNormalColor = lipgloss.AdaptiveColor{ + Dark: darkBorder, + Light: lightBorder, + } + theme.BorderFocusedColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.BorderDimColor = lipgloss.AdaptiveColor{ + Dark: darkSelection, + Light: lightSelection, + } + + // Diff view colors + theme.DiffAddedColor = lipgloss.AdaptiveColor{ + Dark: "#478247", + Light: "#2E7D32", + } + theme.DiffRemovedColor = lipgloss.AdaptiveColor{ + Dark: "#7C4444", + Light: "#C62828", + } + theme.DiffContextColor = lipgloss.AdaptiveColor{ + Dark: "#a0a0a0", + Light: "#757575", + } + theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{ + Dark: "#a0a0a0", + Light: "#757575", + } + theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{ + Dark: "#DAFADA", + Light: "#A5D6A7", + } + theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{ + Dark: "#FADADD", + Light: "#EF9A9A", + } + theme.DiffAddedBgColor = lipgloss.AdaptiveColor{ + Dark: "#303A30", + Light: "#E8F5E9", + } + theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{ + Dark: "#3A3030", + Light: "#FFEBEE", + } + theme.DiffContextBgColor = lipgloss.AdaptiveColor{ + Dark: darkBackground, + Light: lightBackground, + } + theme.DiffLineNumberColor = lipgloss.AdaptiveColor{ + Dark: "#888888", + Light: "#9E9E9E", + } + theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{ + Dark: "#293229", + Light: "#C8E6C9", + } + theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{ + Dark: "#332929", + Light: "#FFCDD2", + } + + // Markdown colors + theme.MarkdownTextColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.MarkdownLinkColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.MarkdownCodeColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + theme.MarkdownEmphColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + theme.MarkdownStrongColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.MarkdownListItemColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.MarkdownImageColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + + // Syntax highlighting colors + theme.SyntaxCommentColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.SyntaxVariableColor = lipgloss.AdaptiveColor{ + Dark: darkRed, + Light: lightRed, + } + theme.SyntaxStringColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.SyntaxNumberColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + theme.SyntaxTypeColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + + return theme +} + +func init() { + // Register the One Dark theme with the theme manager + RegisterTheme("onedark", NewOneDarkTheme()) +} diff --git a/pkg/tui/theme/theme.go b/pkg/tui/theme/theme.go new file mode 100644 index 000000000..c97b95478 --- /dev/null +++ b/pkg/tui/theme/theme.go @@ -0,0 +1,290 @@ +package theme + +import ( + "fmt" + "regexp" + + "github.com/charmbracelet/lipgloss" +) + +// Theme defines the interface for all UI themes in the application. +// All colors must be defined as lipgloss.AdaptiveColor to support +// both light and dark terminal backgrounds. +type Theme interface { + // Base colors + Primary() lipgloss.AdaptiveColor + Secondary() lipgloss.AdaptiveColor + Accent() lipgloss.AdaptiveColor + + // Status colors + Error() lipgloss.AdaptiveColor + Warning() lipgloss.AdaptiveColor + Success() lipgloss.AdaptiveColor + Info() lipgloss.AdaptiveColor + + // Text colors + Text() lipgloss.AdaptiveColor + TextMuted() lipgloss.AdaptiveColor + TextEmphasized() lipgloss.AdaptiveColor + + // Background colors + Background() lipgloss.AdaptiveColor + BackgroundSecondary() lipgloss.AdaptiveColor + BackgroundDarker() lipgloss.AdaptiveColor + + // Border colors + BorderNormal() lipgloss.AdaptiveColor + BorderFocused() lipgloss.AdaptiveColor + BorderDim() lipgloss.AdaptiveColor + + // Diff view colors + DiffAdded() lipgloss.AdaptiveColor + DiffRemoved() lipgloss.AdaptiveColor + DiffContext() lipgloss.AdaptiveColor + DiffHunkHeader() lipgloss.AdaptiveColor + DiffHighlightAdded() lipgloss.AdaptiveColor + DiffHighlightRemoved() lipgloss.AdaptiveColor + DiffAddedBg() lipgloss.AdaptiveColor + DiffRemovedBg() lipgloss.AdaptiveColor + DiffContextBg() lipgloss.AdaptiveColor + DiffLineNumber() lipgloss.AdaptiveColor + DiffAddedLineNumberBg() lipgloss.AdaptiveColor + DiffRemovedLineNumberBg() lipgloss.AdaptiveColor + + // Markdown colors + MarkdownText() lipgloss.AdaptiveColor + MarkdownHeading() lipgloss.AdaptiveColor + MarkdownLink() lipgloss.AdaptiveColor + MarkdownLinkText() lipgloss.AdaptiveColor + MarkdownCode() lipgloss.AdaptiveColor + MarkdownBlockQuote() lipgloss.AdaptiveColor + MarkdownEmph() lipgloss.AdaptiveColor + MarkdownStrong() lipgloss.AdaptiveColor + MarkdownHorizontalRule() lipgloss.AdaptiveColor + MarkdownListItem() lipgloss.AdaptiveColor + MarkdownListEnumeration() lipgloss.AdaptiveColor + MarkdownImage() lipgloss.AdaptiveColor + MarkdownImageText() lipgloss.AdaptiveColor + MarkdownCodeBlock() lipgloss.AdaptiveColor + + // Syntax highlighting colors + SyntaxComment() lipgloss.AdaptiveColor + SyntaxKeyword() lipgloss.AdaptiveColor + SyntaxFunction() lipgloss.AdaptiveColor + SyntaxVariable() lipgloss.AdaptiveColor + SyntaxString() lipgloss.AdaptiveColor + SyntaxNumber() lipgloss.AdaptiveColor + SyntaxType() lipgloss.AdaptiveColor + SyntaxOperator() lipgloss.AdaptiveColor + SyntaxPunctuation() lipgloss.AdaptiveColor +} + +// BaseTheme provides a default implementation of the Theme interface +// that can be embedded in concrete theme implementations. +type BaseTheme struct { + // Base colors + PrimaryColor lipgloss.AdaptiveColor + SecondaryColor lipgloss.AdaptiveColor + AccentColor lipgloss.AdaptiveColor + + // Status colors + ErrorColor lipgloss.AdaptiveColor + WarningColor lipgloss.AdaptiveColor + SuccessColor lipgloss.AdaptiveColor + InfoColor lipgloss.AdaptiveColor + + // Text colors + TextColor lipgloss.AdaptiveColor + TextMutedColor lipgloss.AdaptiveColor + TextEmphasizedColor lipgloss.AdaptiveColor + + // Background colors + BackgroundColor lipgloss.AdaptiveColor + BackgroundSecondaryColor lipgloss.AdaptiveColor + BackgroundDarkerColor lipgloss.AdaptiveColor + + // Border colors + BorderNormalColor lipgloss.AdaptiveColor + BorderFocusedColor lipgloss.AdaptiveColor + BorderDimColor lipgloss.AdaptiveColor + + // Diff view colors + DiffAddedColor lipgloss.AdaptiveColor + DiffRemovedColor lipgloss.AdaptiveColor + DiffContextColor lipgloss.AdaptiveColor + DiffHunkHeaderColor lipgloss.AdaptiveColor + DiffHighlightAddedColor lipgloss.AdaptiveColor + DiffHighlightRemovedColor lipgloss.AdaptiveColor + DiffAddedBgColor lipgloss.AdaptiveColor + DiffRemovedBgColor lipgloss.AdaptiveColor + DiffContextBgColor lipgloss.AdaptiveColor + DiffLineNumberColor lipgloss.AdaptiveColor + DiffAddedLineNumberBgColor lipgloss.AdaptiveColor + DiffRemovedLineNumberBgColor lipgloss.AdaptiveColor + + // Markdown colors + MarkdownTextColor lipgloss.AdaptiveColor + MarkdownHeadingColor lipgloss.AdaptiveColor + MarkdownLinkColor lipgloss.AdaptiveColor + MarkdownLinkTextColor lipgloss.AdaptiveColor + MarkdownCodeColor lipgloss.AdaptiveColor + MarkdownBlockQuoteColor lipgloss.AdaptiveColor + MarkdownEmphColor lipgloss.AdaptiveColor + MarkdownStrongColor lipgloss.AdaptiveColor + MarkdownHorizontalRuleColor lipgloss.AdaptiveColor + MarkdownListItemColor lipgloss.AdaptiveColor + MarkdownListEnumerationColor lipgloss.AdaptiveColor + MarkdownImageColor lipgloss.AdaptiveColor + MarkdownImageTextColor lipgloss.AdaptiveColor + MarkdownCodeBlockColor lipgloss.AdaptiveColor + + // Syntax highlighting colors + SyntaxCommentColor lipgloss.AdaptiveColor + SyntaxKeywordColor lipgloss.AdaptiveColor + SyntaxFunctionColor lipgloss.AdaptiveColor + SyntaxVariableColor lipgloss.AdaptiveColor + SyntaxStringColor lipgloss.AdaptiveColor + SyntaxNumberColor lipgloss.AdaptiveColor + SyntaxTypeColor lipgloss.AdaptiveColor + SyntaxOperatorColor lipgloss.AdaptiveColor + SyntaxPunctuationColor lipgloss.AdaptiveColor +} + +// Implement the Theme interface for BaseTheme +func (t *BaseTheme) Primary() lipgloss.AdaptiveColor { return t.PrimaryColor } +func (t *BaseTheme) Secondary() lipgloss.AdaptiveColor { return t.SecondaryColor } +func (t *BaseTheme) Accent() lipgloss.AdaptiveColor { return t.AccentColor } + +func (t *BaseTheme) Error() lipgloss.AdaptiveColor { return t.ErrorColor } +func (t *BaseTheme) Warning() lipgloss.AdaptiveColor { return t.WarningColor } +func (t *BaseTheme) Success() lipgloss.AdaptiveColor { return t.SuccessColor } +func (t *BaseTheme) Info() lipgloss.AdaptiveColor { return t.InfoColor } + +func (t *BaseTheme) Text() lipgloss.AdaptiveColor { return t.TextColor } +func (t *BaseTheme) TextMuted() lipgloss.AdaptiveColor { return t.TextMutedColor } +func (t *BaseTheme) TextEmphasized() lipgloss.AdaptiveColor { return t.TextEmphasizedColor } + +func (t *BaseTheme) Background() lipgloss.AdaptiveColor { return t.BackgroundColor } +func (t *BaseTheme) BackgroundSecondary() lipgloss.AdaptiveColor { return t.BackgroundSecondaryColor } +func (t *BaseTheme) BackgroundDarker() lipgloss.AdaptiveColor { return t.BackgroundDarkerColor } + +func (t *BaseTheme) BorderNormal() lipgloss.AdaptiveColor { return t.BorderNormalColor } +func (t *BaseTheme) BorderFocused() lipgloss.AdaptiveColor { return t.BorderFocusedColor } +func (t *BaseTheme) BorderDim() lipgloss.AdaptiveColor { return t.BorderDimColor } + +func (t *BaseTheme) DiffAdded() lipgloss.AdaptiveColor { return t.DiffAddedColor } +func (t *BaseTheme) DiffRemoved() lipgloss.AdaptiveColor { return t.DiffRemovedColor } +func (t *BaseTheme) DiffContext() lipgloss.AdaptiveColor { return t.DiffContextColor } +func (t *BaseTheme) DiffHunkHeader() lipgloss.AdaptiveColor { return t.DiffHunkHeaderColor } +func (t *BaseTheme) DiffHighlightAdded() lipgloss.AdaptiveColor { return t.DiffHighlightAddedColor } +func (t *BaseTheme) DiffHighlightRemoved() lipgloss.AdaptiveColor { return t.DiffHighlightRemovedColor } +func (t *BaseTheme) DiffAddedBg() lipgloss.AdaptiveColor { return t.DiffAddedBgColor } +func (t *BaseTheme) DiffRemovedBg() lipgloss.AdaptiveColor { return t.DiffRemovedBgColor } +func (t *BaseTheme) DiffContextBg() lipgloss.AdaptiveColor { return t.DiffContextBgColor } +func (t *BaseTheme) DiffLineNumber() lipgloss.AdaptiveColor { return t.DiffLineNumberColor } +func (t *BaseTheme) DiffAddedLineNumberBg() lipgloss.AdaptiveColor { + return t.DiffAddedLineNumberBgColor +} +func (t *BaseTheme) DiffRemovedLineNumberBg() lipgloss.AdaptiveColor { + return t.DiffRemovedLineNumberBgColor +} + +func (t *BaseTheme) MarkdownText() lipgloss.AdaptiveColor { return t.MarkdownTextColor } +func (t *BaseTheme) MarkdownHeading() lipgloss.AdaptiveColor { return t.MarkdownHeadingColor } +func (t *BaseTheme) MarkdownLink() lipgloss.AdaptiveColor { return t.MarkdownLinkColor } +func (t *BaseTheme) MarkdownLinkText() lipgloss.AdaptiveColor { return t.MarkdownLinkTextColor } +func (t *BaseTheme) MarkdownCode() lipgloss.AdaptiveColor { return t.MarkdownCodeColor } +func (t *BaseTheme) MarkdownBlockQuote() lipgloss.AdaptiveColor { return t.MarkdownBlockQuoteColor } +func (t *BaseTheme) MarkdownEmph() lipgloss.AdaptiveColor { return t.MarkdownEmphColor } +func (t *BaseTheme) MarkdownStrong() lipgloss.AdaptiveColor { return t.MarkdownStrongColor } +func (t *BaseTheme) MarkdownHorizontalRule() lipgloss.AdaptiveColor { + return t.MarkdownHorizontalRuleColor +} +func (t *BaseTheme) MarkdownListItem() lipgloss.AdaptiveColor { return t.MarkdownListItemColor } +func (t *BaseTheme) MarkdownListEnumeration() lipgloss.AdaptiveColor { + return t.MarkdownListEnumerationColor +} +func (t *BaseTheme) MarkdownImage() lipgloss.AdaptiveColor { return t.MarkdownImageColor } +func (t *BaseTheme) MarkdownImageText() lipgloss.AdaptiveColor { return t.MarkdownImageTextColor } +func (t *BaseTheme) MarkdownCodeBlock() lipgloss.AdaptiveColor { return t.MarkdownCodeBlockColor } + +func (t *BaseTheme) SyntaxComment() lipgloss.AdaptiveColor { return t.SyntaxCommentColor } +func (t *BaseTheme) SyntaxKeyword() lipgloss.AdaptiveColor { return t.SyntaxKeywordColor } +func (t *BaseTheme) SyntaxFunction() lipgloss.AdaptiveColor { return t.SyntaxFunctionColor } +func (t *BaseTheme) SyntaxVariable() lipgloss.AdaptiveColor { return t.SyntaxVariableColor } +func (t *BaseTheme) SyntaxString() lipgloss.AdaptiveColor { return t.SyntaxStringColor } +func (t *BaseTheme) SyntaxNumber() lipgloss.AdaptiveColor { return t.SyntaxNumberColor } +func (t *BaseTheme) SyntaxType() lipgloss.AdaptiveColor { return t.SyntaxTypeColor } +func (t *BaseTheme) SyntaxOperator() lipgloss.AdaptiveColor { return t.SyntaxOperatorColor } +func (t *BaseTheme) SyntaxPunctuation() lipgloss.AdaptiveColor { return t.SyntaxPunctuationColor } + +// ParseAdaptiveColor parses a color value from the config file into a lipgloss.AdaptiveColor. +// It accepts either a string (hex color) or a map with "dark" and "light" keys. +func ParseAdaptiveColor(value any) (lipgloss.AdaptiveColor, error) { + // Regular expression to validate hex color format + hexColorRegex := regexp.MustCompile(`^#[0-9a-fA-F]{6}$`) + + // Case 1: String value (same color for both dark and light modes) + if hexColor, ok := value.(string); ok { + if !hexColorRegex.MatchString(hexColor) { + return lipgloss.AdaptiveColor{}, fmt.Errorf("invalid hex color format: %s", hexColor) + } + return lipgloss.AdaptiveColor{ + Dark: hexColor, + Light: hexColor, + }, nil + } + + // Case 2: Int value between 0 and 255 + if numericVal, ok := value.(float64); ok { + intVal := int(numericVal) + if intVal < 0 || intVal > 255 { + return lipgloss.AdaptiveColor{}, fmt.Errorf("invalid int color value (must be between 0 and 255): %d", intVal) + } + return lipgloss.AdaptiveColor{ + Dark: fmt.Sprintf("%d", intVal), + Light: fmt.Sprintf("%d", intVal), + }, nil + } + + // Case 3: Map with dark and light keys + if colorMap, ok := value.(map[string]any); ok { + darkVal, darkOk := colorMap["dark"] + lightVal, lightOk := colorMap["light"] + + if !darkOk || !lightOk { + return lipgloss.AdaptiveColor{}, fmt.Errorf("color map must contain both 'dark' and 'light' keys") + } + + darkHex, darkIsString := darkVal.(string) + lightHex, lightIsString := lightVal.(string) + + if !darkIsString || !lightIsString { + darkVal, darkIsNumber := darkVal.(float64) + lightVal, lightIsNumber := lightVal.(float64) + + if !darkIsNumber || !lightIsNumber { + return lipgloss.AdaptiveColor{}, fmt.Errorf("color map values must be strings or ints") + } + + darkInt := int(darkVal) + lightInt := int(lightVal) + + return lipgloss.AdaptiveColor{ + Dark: fmt.Sprintf("%d", darkInt), + Light: fmt.Sprintf("%d", lightInt), + }, nil + } + + if !hexColorRegex.MatchString(darkHex) || !hexColorRegex.MatchString(lightHex) { + return lipgloss.AdaptiveColor{}, fmt.Errorf("invalid hex color format") + } + + return lipgloss.AdaptiveColor{ + Dark: darkHex, + Light: lightHex, + }, nil + } + + return lipgloss.AdaptiveColor{}, fmt.Errorf("color must be either a hex string or an object with dark/light keys") +} diff --git a/pkg/tui/theme/theme_test.go b/pkg/tui/theme/theme_test.go new file mode 100644 index 000000000..790ee3aa8 --- /dev/null +++ b/pkg/tui/theme/theme_test.go @@ -0,0 +1,89 @@ +package theme + +import ( + "testing" +) + +func TestThemeRegistration(t *testing.T) { + // Get list of available themes + availableThemes := AvailableThemes() + + // Check if "catppuccin" theme is registered + catppuccinFound := false + for _, themeName := range availableThemes { + if themeName == "catppuccin" { + catppuccinFound = true + break + } + } + + if !catppuccinFound { + t.Errorf("Catppuccin theme is not registered") + } + + // Check if "gruvbox" theme is registered + gruvboxFound := false + for _, themeName := range availableThemes { + if themeName == "gruvbox" { + gruvboxFound = true + break + } + } + + if !gruvboxFound { + t.Errorf("Gruvbox theme is not registered") + } + + // Check if "monokai" theme is registered + monokaiFound := false + for _, themeName := range availableThemes { + if themeName == "monokai" { + monokaiFound = true + break + } + } + + if !monokaiFound { + t.Errorf("Monokai theme is not registered") + } + + // Try to get the themes and make sure they're not nil + catppuccin := GetTheme("catppuccin") + if catppuccin == nil { + t.Errorf("Catppuccin theme is nil") + } + + gruvbox := GetTheme("gruvbox") + if gruvbox == nil { + t.Errorf("Gruvbox theme is nil") + } + + monokai := GetTheme("monokai") + if monokai == nil { + t.Errorf("Monokai theme is nil") + } + + // Test switching theme + originalTheme := CurrentThemeName() + + err := SetTheme("gruvbox") + if err != nil { + t.Errorf("Failed to set theme to gruvbox: %v", err) + } + + if CurrentThemeName() != "gruvbox" { + t.Errorf("Theme not properly switched to gruvbox") + } + + err = SetTheme("monokai") + if err != nil { + t.Errorf("Failed to set theme to monokai: %v", err) + } + + if CurrentThemeName() != "monokai" { + t.Errorf("Theme not properly switched to monokai") + } + + // Switch back to original theme + _ = SetTheme(originalTheme) +} diff --git a/pkg/tui/theme/tokyonight.go b/pkg/tui/theme/tokyonight.go new file mode 100644 index 000000000..a6499a25d --- /dev/null +++ b/pkg/tui/theme/tokyonight.go @@ -0,0 +1,274 @@ +package theme + +import ( + "github.com/charmbracelet/lipgloss" +) + +// TokyoNightTheme implements the Theme interface with Tokyo Night colors. +// It provides both dark and light variants. +type TokyoNightTheme struct { + BaseTheme +} + +// NewTokyoNightTheme creates a new instance of the Tokyo Night theme. +func NewTokyoNightTheme() *TokyoNightTheme { + // Tokyo Night color palette + // Dark mode colors + darkBackground := "#222436" + darkCurrentLine := "#1e2030" + darkSelection := "#2f334d" + darkForeground := "#c8d3f5" + darkComment := "#636da6" + darkRed := "#ff757f" + darkOrange := "#ff966c" + darkYellow := "#ffc777" + darkGreen := "#c3e88d" + darkCyan := "#86e1fc" + darkBlue := "#82aaff" + darkPurple := "#c099ff" + darkBorder := "#3b4261" + + // Light mode colors (Tokyo Night Day) + lightBackground := "#e1e2e7" + lightCurrentLine := "#d5d6db" + lightSelection := "#c8c9ce" + lightForeground := "#3760bf" + lightComment := "#848cb5" + lightRed := "#f52a65" + lightOrange := "#b15c00" + lightYellow := "#8c6c3e" + lightGreen := "#587539" + lightCyan := "#007197" + lightBlue := "#2e7de9" + lightPurple := "#9854f1" + lightBorder := "#a8aecb" + + theme := &TokyoNightTheme{} + + // Base colors + theme.PrimaryColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.SecondaryColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.AccentColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + + // Status colors + theme.ErrorColor = lipgloss.AdaptiveColor{ + Dark: darkRed, + Light: lightRed, + } + theme.WarningColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + theme.SuccessColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.InfoColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + + // Text colors + theme.TextColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + theme.TextMutedColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.TextEmphasizedColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + + // Background colors + theme.BackgroundColor = lipgloss.AdaptiveColor{ + Dark: darkBackground, + Light: lightBackground, + } + theme.BackgroundSecondaryColor = lipgloss.AdaptiveColor{ + Dark: darkCurrentLine, + Light: lightCurrentLine, + } + theme.BackgroundDarkerColor = lipgloss.AdaptiveColor{ + Dark: "#191B29", // Darker background from palette + Light: "#f0f0f5", // Slightly lighter than background + } + + // Border colors + theme.BorderNormalColor = lipgloss.AdaptiveColor{ + Dark: darkBorder, + Light: lightBorder, + } + theme.BorderFocusedColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.BorderDimColor = lipgloss.AdaptiveColor{ + Dark: darkSelection, + Light: lightSelection, + } + + // Diff view colors + theme.DiffAddedColor = lipgloss.AdaptiveColor{ + Dark: "#4fd6be", // teal from palette + Light: "#1e725c", + } + theme.DiffRemovedColor = lipgloss.AdaptiveColor{ + Dark: "#c53b53", // red1 from palette + Light: "#c53b53", + } + theme.DiffContextColor = lipgloss.AdaptiveColor{ + Dark: "#828bb8", // fg_dark from palette + Light: "#7086b5", + } + theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{ + Dark: "#828bb8", // fg_dark from palette + Light: "#7086b5", + } + theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{ + Dark: "#b8db87", // git.add from palette + Light: "#4db380", + } + theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{ + Dark: "#e26a75", // git.delete from palette + Light: "#f52a65", + } + theme.DiffAddedBgColor = lipgloss.AdaptiveColor{ + Dark: "#20303b", + Light: "#d5e5d5", + } + theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{ + Dark: "#37222c", + Light: "#f7d8db", + } + theme.DiffContextBgColor = lipgloss.AdaptiveColor{ + Dark: darkBackground, + Light: lightBackground, + } + theme.DiffLineNumberColor = lipgloss.AdaptiveColor{ + Dark: "#545c7e", // dark3 from palette + Light: "#848cb5", + } + theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{ + Dark: "#1b2b34", + Light: "#c5d5c5", + } + theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{ + Dark: "#2d1f26", + Light: "#e7c8cb", + } + + // Markdown colors + theme.MarkdownTextColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.MarkdownLinkColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.MarkdownCodeColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + theme.MarkdownEmphColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + theme.MarkdownStrongColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.MarkdownListItemColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.MarkdownImageColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + + // Syntax highlighting colors + theme.SyntaxCommentColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.SyntaxVariableColor = lipgloss.AdaptiveColor{ + Dark: darkRed, + Light: lightRed, + } + theme.SyntaxStringColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.SyntaxNumberColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + theme.SyntaxTypeColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + + return theme +} + +func init() { + // Register the Tokyo Night theme with the theme manager + RegisterTheme("tokyonight", NewTokyoNightTheme()) +} diff --git a/pkg/tui/theme/tron.go b/pkg/tui/theme/tron.go new file mode 100644 index 000000000..c4997a6d1 --- /dev/null +++ b/pkg/tui/theme/tron.go @@ -0,0 +1,276 @@ +package theme + +import ( + "github.com/charmbracelet/lipgloss" +) + +// TronTheme implements the Theme interface with Tron-inspired colors. +// It provides both dark and light variants, though Tron is primarily a dark theme. +type TronTheme struct { + BaseTheme +} + +// NewTronTheme creates a new instance of the Tron theme. +func NewTronTheme() *TronTheme { + // Tron color palette + // Inspired by the Tron movie's neon aesthetic + darkBackground := "#0c141f" + darkCurrentLine := "#1a2633" + darkSelection := "#1a2633" + darkForeground := "#caf0ff" + darkComment := "#4d6b87" + darkCyan := "#00d9ff" + darkBlue := "#007fff" + darkOrange := "#ff9000" + darkPink := "#ff00a0" + darkPurple := "#b73fff" + darkRed := "#ff3333" + darkYellow := "#ffcc00" + darkGreen := "#00ff8f" + darkBorder := "#1a2633" + + // Light mode approximation + lightBackground := "#f0f8ff" + lightCurrentLine := "#e0f0ff" + lightSelection := "#d0e8ff" + lightForeground := "#0c141f" + lightComment := "#4d6b87" + lightCyan := "#0097b3" + lightBlue := "#0066cc" + lightOrange := "#cc7300" + lightPink := "#cc0080" + lightPurple := "#9932cc" + lightRed := "#cc2929" + lightYellow := "#cc9900" + lightGreen := "#00cc72" + lightBorder := "#d0e8ff" + + theme := &TronTheme{} + + // Base colors + theme.PrimaryColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.SecondaryColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.AccentColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + + // Status colors + theme.ErrorColor = lipgloss.AdaptiveColor{ + Dark: darkRed, + Light: lightRed, + } + theme.WarningColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + theme.SuccessColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.InfoColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + + // Text colors + theme.TextColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + theme.TextMutedColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.TextEmphasizedColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + + // Background colors + theme.BackgroundColor = lipgloss.AdaptiveColor{ + Dark: darkBackground, + Light: lightBackground, + } + theme.BackgroundSecondaryColor = lipgloss.AdaptiveColor{ + Dark: darkCurrentLine, + Light: lightCurrentLine, + } + theme.BackgroundDarkerColor = lipgloss.AdaptiveColor{ + Dark: "#070d14", // Slightly darker than background + Light: "#ffffff", // Slightly lighter than background + } + + // Border colors + theme.BorderNormalColor = lipgloss.AdaptiveColor{ + Dark: darkBorder, + Light: lightBorder, + } + theme.BorderFocusedColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.BorderDimColor = lipgloss.AdaptiveColor{ + Dark: darkSelection, + Light: lightSelection, + } + + // Diff view colors + theme.DiffAddedColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.DiffRemovedColor = lipgloss.AdaptiveColor{ + Dark: darkRed, + Light: lightRed, + } + theme.DiffContextColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{ + Dark: "#00ff8f", + Light: "#a5d6a7", + } + theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{ + Dark: "#ff3333", + Light: "#ef9a9a", + } + theme.DiffAddedBgColor = lipgloss.AdaptiveColor{ + Dark: "#0a2a1a", + Light: "#e8f5e9", + } + theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{ + Dark: "#2a0a0a", + Light: "#ffebee", + } + theme.DiffContextBgColor = lipgloss.AdaptiveColor{ + Dark: darkBackground, + Light: lightBackground, + } + theme.DiffLineNumberColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{ + Dark: "#082015", + Light: "#c8e6c9", + } + theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{ + Dark: "#200808", + Light: "#ffcdd2", + } + + // Markdown colors + theme.MarkdownTextColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.MarkdownLinkColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.MarkdownCodeColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + theme.MarkdownEmphColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + theme.MarkdownStrongColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.MarkdownListItemColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.MarkdownImageColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + + // Syntax highlighting colors + theme.SyntaxCommentColor = lipgloss.AdaptiveColor{ + Dark: darkComment, + Light: lightComment, + } + theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{ + Dark: darkCyan, + Light: lightCyan, + } + theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{ + Dark: darkGreen, + Light: lightGreen, + } + theme.SyntaxVariableColor = lipgloss.AdaptiveColor{ + Dark: darkOrange, + Light: lightOrange, + } + theme.SyntaxStringColor = lipgloss.AdaptiveColor{ + Dark: darkYellow, + Light: lightYellow, + } + theme.SyntaxNumberColor = lipgloss.AdaptiveColor{ + Dark: darkBlue, + Light: lightBlue, + } + theme.SyntaxTypeColor = lipgloss.AdaptiveColor{ + Dark: darkPurple, + Light: lightPurple, + } + theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{ + Dark: darkPink, + Light: lightPink, + } + theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{ + Dark: darkForeground, + Light: lightForeground, + } + + return theme +} + +func init() { + // Register the Tron theme with the theme manager + RegisterTheme("tron", NewTronTheme()) +} |
