summaryrefslogtreecommitdiffhomepage
path: root/pkg/tui/theme
diff options
context:
space:
mode:
authorDax Raad <[email protected]>2025-05-18 22:30:41 -0400
committerDax Raad <[email protected]>2025-05-26 12:40:17 -0400
commit99af6146d5def31c59993636d60eb75a483a283b (patch)
treeeb57ed227c15cf9be54bc9f231c83895d812f881 /pkg/tui/theme
parent020e0ca039287b73fa33041fbd1bb214e6ccb396 (diff)
downloadopencode-99af6146d5def31c59993636d60eb75a483a283b.tar.gz
opencode-99af6146d5def31c59993636d60eb75a483a283b.zip
openapi
Diffstat (limited to 'pkg/tui/theme')
-rw-r--r--pkg/tui/theme/catppuccin.go248
-rw-r--r--pkg/tui/theme/dracula.go274
-rw-r--r--pkg/tui/theme/flexoki.go282
-rw-r--r--pkg/tui/theme/gruvbox.go302
-rw-r--r--pkg/tui/theme/manager.go265
-rw-r--r--pkg/tui/theme/monokai.go273
-rw-r--r--pkg/tui/theme/onedark.go274
-rw-r--r--pkg/tui/theme/theme.go290
-rw-r--r--pkg/tui/theme/theme_test.go89
-rw-r--r--pkg/tui/theme/tokyonight.go274
-rw-r--r--pkg/tui/theme/tron.go276
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())
+}