diff --git a/packages/tui/cmd/opencode/main.go b/packages/tui/cmd/opencode/main.go index 27e797e8..06c4554a 100644 --- a/packages/tui/cmd/opencode/main.go +++ b/packages/tui/cmd/opencode/main.go @@ -9,7 +9,7 @@ import ( "sync" "time" - tea "github.com/charmbracelet/bubbletea" + tea "github.com/charmbracelet/bubbletea/v2" zone "github.com/lrstanley/bubblezone" "github.com/sst/opencode/internal/app" "github.com/sst/opencode/internal/pubsub" @@ -65,6 +65,8 @@ func main() { zone.NewGlobal() program := tea.NewProgram( tui.NewModel(app_), + // tea.WithMouseCellMotion(), + tea.WithKeyboardEnhancements(), tea.WithAltScreen(), ) diff --git a/packages/tui/go.mod b/packages/tui/go.mod index 76d2d7bd..6dddd809 100644 --- a/packages/tui/go.mod +++ b/packages/tui/go.mod @@ -4,13 +4,12 @@ go 1.24.0 require ( github.com/BurntSushi/toml v1.5.0 - github.com/alecthomas/chroma/v2 v2.15.0 + github.com/alecthomas/chroma/v2 v2.18.0 github.com/bmatcuk/doublestar/v4 v4.8.1 - github.com/catppuccin/go v0.3.0 - github.com/charmbracelet/bubbles v0.21.0 - github.com/charmbracelet/bubbletea v1.3.4 - github.com/charmbracelet/glamour v0.9.1 - github.com/charmbracelet/lipgloss v1.1.0 + github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1 + github.com/charmbracelet/bubbletea/v2 v2.0.0-beta.3 + github.com/charmbracelet/glamour v0.10.0 + github.com/charmbracelet/lipgloss/v2 v2.0.0-beta1 github.com/charmbracelet/x/ansi v0.8.0 github.com/lithammer/fuzzysearch v1.1.8 github.com/lrstanley/bubblezone v0.0.0-20250315020633-c249a3fe1231 @@ -28,6 +27,11 @@ require ( dario.cat/mergo v1.0.2 // indirect github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/atombender/go-jsonschema v0.20.0 // indirect + github.com/charmbracelet/bubbletea v1.3.4 // indirect + github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 // indirect + github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf // indirect + github.com/charmbracelet/x/input v0.3.5-0.20250424101541-abb4d9a9b197 // indirect + github.com/charmbracelet/x/windows v0.2.1 // indirect github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/getkin/kin-openapi v0.127.0 // indirect @@ -57,11 +61,11 @@ require ( github.com/atotto/clipboard v0.1.4 github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect - github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect - github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect + github.com/charmbracelet/colorprofile v0.3.1 // indirect + github.com/charmbracelet/x/cellbuf v0.0.14-0.20250501183327-ad3bc78c6a81 // indirect github.com/charmbracelet/x/term v0.2.1 // indirect github.com/disintegration/imaging v1.6.2 - github.com/dlclark/regexp2 v1.11.4 // indirect + github.com/dlclark/regexp2 v1.11.5 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/gorilla/css v1.0.1 // indirect diff --git a/packages/tui/go.sum b/packages/tui/go.sum index 03689fe8..4021e9bf 100644 --- a/packages/tui/go.sum +++ b/packages/tui/go.sum @@ -7,8 +7,8 @@ github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6 github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= -github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc= -github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio= +github.com/alecthomas/chroma/v2 v2.18.0 h1:6h53Q4hW83SuF+jcsp7CVhLsMozzvQvO8HBbKQW+gn4= +github.com/alecthomas/chroma/v2 v2.18.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= @@ -26,26 +26,34 @@ github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd3 github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38= github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= -github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY= -github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= -github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs= -github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg= +github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1 h1:swACzss0FjnyPz1enfX56GKkLiuKg5FlyVmOLIlU2kE= +github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1/go.mod h1:6HamsBKWqEC/FVHuQMHgQL+knPyvHH55HwJDHl/adMw= github.com/charmbracelet/bubbletea v1.3.4 h1:kCg7B+jSCFPLYRA52SDZjr51kG/fMUEoPoZrkaDHyoI= github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo= -github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= -github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= -github.com/charmbracelet/glamour v0.9.1 h1:11dEfiGP8q1BEqvGoIjivuc2rBk+5qEXdPtaQ2WoiCM= -github.com/charmbracelet/glamour v0.9.1/go.mod h1:+SHvIS8qnwhgTpVMiXwn7OfGomSqff1cHBCI8jLOetk= -github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= -github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= +github.com/charmbracelet/bubbletea/v2 v2.0.0-beta.3 h1:5A2e3myxXMpCES+kjEWgGsaf9VgZXjZbLi5iMTH7j40= +github.com/charmbracelet/bubbletea/v2 v2.0.0-beta.3/go.mod h1:ZFDg5oPjyRYrPAa3iFrtP1DO8xy+LUQxd9JFHEcuwJY= +github.com/charmbracelet/colorprofile v0.3.1 h1:k8dTHMd7fgw4bnFd7jXTLZrSU/CQrKnL3m+AxCzDz40= +github.com/charmbracelet/colorprofile v0.3.1/go.mod h1:/GkGusxNs8VB/RSOh3fu0TJmQ4ICMMPApIIVn0KszZ0= +github.com/charmbracelet/glamour v0.10.0 h1:MtZvfwsYCx8jEPFJm3rIBFIMZUfUJ765oX8V6kXldcY= +github.com/charmbracelet/glamour v0.10.0/go.mod h1:f+uf+I/ChNmqo087elLnVdCiVgjSKWuXa/l6NU2ndYk= +github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 h1:ZR7e0ro+SZZiIZD7msJyA+NjkCNNavuiPBLgerbOziE= +github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834/go.mod h1:aKC/t2arECF6rNOnaKaVU6y4t4ZeHQzqfxedE/VkVhA= +github.com/charmbracelet/lipgloss/v2 v2.0.0-beta1 h1:SOylT6+BQzPHEjn15TIzawBPVD0QmhKXbcb3jY0ZIKU= +github.com/charmbracelet/lipgloss/v2 v2.0.0-beta1/go.mod h1:tRlx/Hu0lo/j9viunCN2H+Ze6JrmdjQlXUQvvArgaOc= github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE= github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q= -github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8= -github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= -github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ= -github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= +github.com/charmbracelet/x/cellbuf v0.0.14-0.20250501183327-ad3bc78c6a81 h1:iGrflaL5jQW6crML+pZx/ulWAVZQR3CQoRGvFsr2Tyg= +github.com/charmbracelet/x/cellbuf v0.0.14-0.20250501183327-ad3bc78c6a81/go.mod h1:poPFOXFTsJsnLbkV3H2KxAAXT7pdjxxLujLocWjkyzM= +github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a h1:FsHEJ52OC4VuTzU8t+n5frMjLvpYWEznSr/u8tnkCYw= +github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= +github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf h1:rLG0Yb6MQSDKdB52aGX55JT1oi0P0Kuaj7wi1bLUpnI= +github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf/go.mod h1:B3UgsnsBZS/eX42BlaNiJkD1pPOUa+oF1IYC6Yd2CEU= +github.com/charmbracelet/x/input v0.3.5-0.20250424101541-abb4d9a9b197 h1:fsWj8NF5njyMVzELc7++HsvRDvgz3VcgGAUgWBDWWWM= +github.com/charmbracelet/x/input v0.3.5-0.20250424101541-abb4d9a9b197/go.mod h1:xseGeVftoP9rVI+/8WKYrJFH6ior6iERGvklwwHz5+s= github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= +github.com/charmbracelet/x/windows v0.2.1 h1:3x7vnbpQrjpuq/4L+I4gNsG5htYoCiA5oe9hLjAij5I= +github.com/charmbracelet/x/windows v0.2.1/go.mod h1:ptZp16h40gDYqs5TSawSVW+yiLB13j4kSMA0lSCHL0M= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -56,8 +64,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= -github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= -github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= +github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58= github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w= github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q= diff --git a/packages/tui/internal/app/app.go b/packages/tui/internal/app/app.go index cffc4b1c..3917330e 100644 --- a/packages/tui/internal/app/app.go +++ b/packages/tui/internal/app/app.go @@ -8,7 +8,7 @@ import ( "log/slog" - tea "github.com/charmbracelet/bubbletea" + tea "github.com/charmbracelet/bubbletea/v2" "github.com/sst/opencode/internal/config" "github.com/sst/opencode/internal/fileutil" "github.com/sst/opencode/internal/state" diff --git a/packages/tui/internal/components/chat/editor.go b/packages/tui/internal/components/chat/editor.go index 52f19849..198958b0 100644 --- a/packages/tui/internal/components/chat/editor.go +++ b/packages/tui/internal/components/chat/editor.go @@ -5,15 +5,13 @@ import ( "log/slog" "os" "os/exec" - "slices" "strings" - "unicode" - "github.com/charmbracelet/bubbles/key" - "github.com/charmbracelet/bubbles/spinner" - "github.com/charmbracelet/bubbles/textarea" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/key" + "github.com/charmbracelet/bubbles/v2/spinner" + "github.com/charmbracelet/bubbles/v2/textarea" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode/internal/app" "github.com/sst/opencode/internal/components/dialog" "github.com/sst/opencode/internal/image" @@ -129,18 +127,18 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.attachments = nil return m, nil } - if m.deleteMode && len(msg.Runes) > 0 && unicode.IsDigit(msg.Runes[0]) { - num := int(msg.Runes[0] - '0') - m.deleteMode = false - if num < 10 && len(m.attachments) > num { - if num == 0 { - m.attachments = m.attachments[num+1:] - } else { - m.attachments = slices.Delete(m.attachments, num, num+1) - } - return m, nil - } - } + // if m.deleteMode && len(msg.Runes) > 0 && unicode.IsDigit(msg.Runes[0]) { + // num := int(msg.Runes[0] - '0') + // m.deleteMode = false + // if num < 10 && len(m.attachments) > num { + // if num == 0 { + // m.attachments = m.attachments[num+1:] + // } else { + // m.attachments = slices.Delete(m.attachments, num, num+1) + // } + // return m, nil + // } + // } if key.Matches(msg, messageKeys.PageUp) || key.Matches(msg, messageKeys.PageDown) || key.Matches(msg, messageKeys.HalfPageUp) || key.Matches(msg, messageKeys.HalfPageDown) { return m, nil @@ -258,7 +256,7 @@ func (m *editorComponent) View() string { m.textarea.View(), ) textarea = styles.BaseStyle(). - Width(m.width-2). + Width(m.width). // -2). Border(lipgloss.NormalBorder(), true, true). BorderForeground(t.Border()). Render(textarea) @@ -286,10 +284,7 @@ func (m *editorComponent) View() string { info, ) - return styles.ForceReplaceBackgroundWithLipgloss( - content, - t.Background(), - ) + return content } func (m *editorComponent) SetSize(width, height int) tea.Cmd { @@ -414,14 +409,14 @@ func createTextArea(existing *textarea.Model) textarea.Model { ta := textarea.New() ta.Placeholder = "It's prompting time..." - ta.BlurredStyle.Base = styles.BaseStyle().Background(bgColor).Foreground(textColor) - ta.BlurredStyle.CursorLine = styles.BaseStyle().Background(bgColor) - ta.BlurredStyle.Placeholder = styles.BaseStyle().Background(bgColor).Foreground(textMutedColor) - ta.BlurredStyle.Text = styles.BaseStyle().Background(bgColor).Foreground(textColor) - ta.FocusedStyle.Base = styles.BaseStyle().Background(bgColor).Foreground(textColor) - ta.FocusedStyle.CursorLine = styles.BaseStyle().Background(bgColor) - ta.FocusedStyle.Placeholder = styles.BaseStyle().Background(bgColor).Foreground(textMutedColor) - ta.FocusedStyle.Text = styles.BaseStyle().Background(bgColor).Foreground(textColor) + ta.Styles.Blurred.Base = styles.BaseStyle().Background(bgColor).Foreground(textColor) + ta.Styles.Blurred.CursorLine = styles.BaseStyle().Background(bgColor) + ta.Styles.Blurred.Placeholder = styles.BaseStyle().Background(bgColor).Foreground(textMutedColor) + ta.Styles.Blurred.Text = styles.BaseStyle().Background(bgColor).Foreground(textColor) + ta.Styles.Focused.Base = styles.BaseStyle().Background(bgColor).Foreground(textColor) + ta.Styles.Focused.CursorLine = styles.BaseStyle().Background(bgColor) + ta.Styles.Focused.Placeholder = styles.BaseStyle().Background(bgColor).Foreground(textMutedColor) + ta.Styles.Focused.Text = styles.BaseStyle().Background(bgColor).Foreground(textColor) ta.Prompt = " " ta.ShowLineNumbers = false @@ -437,7 +432,7 @@ func createTextArea(existing *textarea.Model) textarea.Model { return ta } -func NewEditorComponent(app *app.App) tea.Model { +func NewEditorComponent(app *app.App) layout.ModelWithView { s := spinner.New(spinner.WithSpinner(spinner.Ellipsis), spinner.WithStyle(styles.Muted().Width(3))) ta := createTextArea(nil) diff --git a/packages/tui/internal/components/chat/message.go b/packages/tui/internal/components/chat/message.go index 131898c8..199b4a07 100644 --- a/packages/tui/internal/components/chat/message.go +++ b/packages/tui/internal/components/chat/message.go @@ -9,7 +9,8 @@ import ( "time" "unicode" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/v2" + "github.com/charmbracelet/lipgloss/v2/compat" "github.com/charmbracelet/x/ansi" "github.com/sst/opencode/internal/app" "github.com/sst/opencode/internal/components/diff" @@ -21,8 +22,8 @@ import ( "golang.org/x/text/language" ) -func toMarkdown(content string, width int) string { - r := styles.GetMarkdownRenderer(width) +func toMarkdown(content string, width int, backgroundColor compat.AdaptiveColor) string { + r := styles.GetMarkdownRenderer(width, backgroundColor) content = strings.ReplaceAll(content, app.Info.Path.Root+"/", "") rendered, _ := r.Render(content) lines := strings.Split(rendered, "\n") @@ -50,7 +51,7 @@ func toMarkdown(content string, width int) string { type blockRenderer struct { align *lipgloss.Position - borderColor *lipgloss.AdaptiveColor + borderColor *compat.AdaptiveColor fullWidth bool paddingTop int paddingBottom int @@ -70,7 +71,7 @@ func WithAlign(align lipgloss.Position) renderingOption { } } -func WithBorderColor(color lipgloss.AdaptiveColor) renderingOption { +func WithBorderColor(color compat.AdaptiveColor) renderingOption { return func(c *blockRenderer) { c.borderColor = &color } @@ -137,9 +138,8 @@ func renderContentBlock(content string, options ...renderingOption) string { BorderLeftBackground(t.Background()) } - content = styles.ForceReplaceBackgroundWithLipgloss(content, t.BackgroundSubtle()) if renderer.fullWidth { - style = style.Width(layout.Current.Container.Width - 2) + style = style.Width(layout.Current.Container.Width) } content = style.Render(content) if renderer.paddingTop > 0 { @@ -152,13 +152,11 @@ func renderContentBlock(content string, options ...renderingOption) string { layout.Current.Container.Width, align, content, - lipgloss.WithWhitespaceBackground(t.Background()), ) content = lipgloss.PlaceHorizontal( layout.Current.Viewport.Width, lipgloss.Center, content, - lipgloss.WithWhitespaceBackground(t.Background()), ) return content } @@ -181,9 +179,7 @@ func renderText(message client.MessageInfo, text string, author string) string { // don't show the date if it's today timestamp = timestamp[12:] } - info := styles.BaseStyle(). - Foreground(t.TextMuted()). - Render(fmt.Sprintf("%s (%s)", author, timestamp)) + info := fmt.Sprintf("%s (%s)", author, timestamp) align := lipgloss.Left switch message.Role { @@ -195,7 +191,7 @@ func renderText(message client.MessageInfo, text string, author string) string { textWidth := lipgloss.Width(text) markdownWidth := min(textWidth, width-padding-4) // -4 for the border and padding - content := toMarkdown(text, markdownWidth) + content := toMarkdown(text, markdownWidth, t.BackgroundSubtle()) content = lipgloss.JoinVertical(align, content, info) switch message.Role { @@ -313,7 +309,7 @@ func renderToolInvocation( lipgloss.Center, lipgloss.Center, body, - lipgloss.WithWhitespaceBackground(t.Background()), + lipgloss.WithWhitespaceStyle(lipgloss.NewStyle().Background(t.Background())), ) } case "opencode_write": @@ -328,7 +324,7 @@ func renderToolInvocation( command := toolArgsMap["command"].(string) stdout := metadata["stdout"].(string) body = fmt.Sprintf("```console\n> %s\n%s```", command, stdout) - body = toMarkdown(body, innerWidth) + body = toMarkdown(body, innerWidth, t.BackgroundSubtle()) body = renderContentBlock(body, WithFullWidth(), WithPaddingTop(1), WithPaddingBottom(1)) } case "opencode_webfetch": @@ -336,7 +332,7 @@ func renderToolInvocation( format := toolArgsMap["format"].(string) body = truncateHeight(body, 10) if format == "html" || format == "markdown" { - body = toMarkdown(body, innerWidth) + body = toMarkdown(body, innerWidth, t.BackgroundSubtle()) } body = renderContentBlock(body, WithFullWidth(), WithPaddingTop(1), WithPaddingBottom(1)) case "opencode_todowrite": @@ -356,7 +352,7 @@ func renderToolInvocation( body += fmt.Sprintf("- [ ] %s\n", content) } } - body = toMarkdown(body, innerWidth) + body = toMarkdown(body, innerWidth, t.BackgroundSubtle()) body = renderContentBlock(body, WithFullWidth(), WithPaddingTop(1), WithPaddingBottom(1)) } default: @@ -368,7 +364,7 @@ func renderToolInvocation( content := style.Render(title) content = lipgloss.PlaceHorizontal(layout.Current.Viewport.Width, lipgloss.Center, content) - content = styles.ForceReplaceBackgroundWithLipgloss(content, t.Background()) + // content = styles.ForceReplaceBackgroundWithLipgloss(content, t.Background()) if showResult && body != "" { content += "\n" + body } @@ -411,6 +407,7 @@ func WithTruncate(height int) fileRenderingOption { } func renderFile(filename string, content string, options ...fileRenderingOption) string { + t := theme.CurrentTheme() renderer := &fileRenderer{ filename: filename, content: content, @@ -419,7 +416,6 @@ func renderFile(filename string, content string, options ...fileRenderingOption) option(renderer) } - // TODO: is this even needed? lines := []string{} for line := range strings.SplitSeq(content, "\n") { line = strings.TrimRightFunc(line, unicode.IsSpace) @@ -428,23 +424,12 @@ func renderFile(filename string, content string, options ...fileRenderingOption) } content = strings.Join(lines, "\n") - width := layout.Current.Container.Width - 6 + width := layout.Current.Container.Width - 8 if renderer.height > 0 { content = truncateHeight(content, renderer.height) } content = fmt.Sprintf("```%s\n%s\n```", extension(renderer.filename), content) - content = toMarkdown(content, width) - - // ensure no line is wider than the width - // truncated := []string{} - // for line := range strings.SplitSeq(content, "\n") { - // line = strings.TrimRightFunc(line, unicode.IsSpace) - // // if lipgloss.Width(line) > width-3 { - // line = ansi.Truncate(line, width-3, "") - // // } - // truncated = append(truncated, line) - // } - // content = strings.Join(truncated, "\n") + content = toMarkdown(content, width, t.BackgroundSubtle()) return renderContentBlock(content, WithFullWidth(), WithPaddingTop(1), WithPaddingBottom(1)) } diff --git a/packages/tui/internal/components/chat/messages.go b/packages/tui/internal/components/chat/messages.go index 093c8cf9..0036d066 100644 --- a/packages/tui/internal/components/chat/messages.go +++ b/packages/tui/internal/components/chat/messages.go @@ -4,11 +4,11 @@ import ( "strings" "time" - "github.com/charmbracelet/bubbles/key" - "github.com/charmbracelet/bubbles/spinner" - "github.com/charmbracelet/bubbles/viewport" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/key" + "github.com/charmbracelet/bubbles/v2/spinner" + "github.com/charmbracelet/bubbles/v2/viewport" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode/internal/app" "github.com/sst/opencode/internal/components/dialog" "github.com/sst/opencode/internal/layout" @@ -220,11 +220,11 @@ func (m *messagesComponent) renderView() { m.width, lipgloss.Center, block, - lipgloss.WithWhitespaceBackground(t.Background()), + lipgloss.WithWhitespaceStyle(lipgloss.NewStyle().Background(t.Background())), )) } - m.viewport.Height = m.height - lipgloss.Height(m.header()) + m.viewport.SetHeight(m.height - lipgloss.Height(m.header())) m.viewport.SetContent(strings.Join(centered, "\n")) } @@ -238,7 +238,7 @@ func (m *messagesComponent) header() string { base := styles.BaseStyle().Render muted := styles.Muted().Render headerLines := []string{} - headerLines = append(headerLines, toMarkdown("# "+m.app.Session.Title, width)) + headerLines = append(headerLines, toMarkdown("# "+m.app.Session.Title, width, t.Background())) if m.app.Session.Share != nil && m.app.Session.Share.Url != "" { headerLines = append(headerLines, muted(m.app.Session.Share.Url)) } else { @@ -255,7 +255,7 @@ func (m *messagesComponent) header() string { Background(t.Background()). Render(header) - return styles.ForceReplaceBackgroundWithLipgloss(header, t.Background()) + return header } func (m *messagesComponent) View() string { @@ -269,73 +269,8 @@ func (m *messagesComponent) View() string { ) } -// func hasToolsWithoutResponse(messages []message.Message) bool { -// toolCalls := make([]message.ToolCall, 0) -// toolResults := make([]message.ToolResult, 0) -// for _, m := range messages { -// toolCalls = append(toolCalls, m.ToolCalls()...) -// toolResults = append(toolResults, m.ToolResults()...) -// } -// -// for _, v := range toolCalls { -// found := false -// for _, r := range toolResults { -// if v.ID == r.ToolCallID { -// found = true -// break -// } -// } -// if !found && v.Finished { -// return true -// } -// } -// return false -// } - -// func hasUnfinishedToolCalls(messages []message.Message) bool { -// toolCalls := make([]message.ToolCall, 0) -// for _, m := range messages { -// toolCalls = append(toolCalls, m.ToolCalls()...) -// } -// for _, v := range toolCalls { -// if !v.Finished { -// return true -// } -// } -// return false -// } - -func (m *messagesComponent) help() string { - t := theme.CurrentTheme() - baseStyle := styles.BaseStyle() - - text := "" - - if m.app.IsBusy() { - text += lipgloss.JoinHorizontal( - lipgloss.Left, - baseStyle.Foreground(t.TextMuted()).Bold(true).Render("press "), - baseStyle.Foreground(t.Text()).Bold(true).Render("esc"), - baseStyle.Foreground(t.TextMuted()).Bold(true).Render(" to interrupt"), - ) - } else { - text += lipgloss.JoinHorizontal( - lipgloss.Left, - baseStyle.Foreground(t.Text()).Bold(true).Render("enter"), - baseStyle.Foreground(t.TextMuted()).Bold(true).Render(" to send,"), - baseStyle.Foreground(t.Text()).Bold(true).Render(" \\"), - baseStyle.Foreground(t.TextMuted()).Bold(true).Render("+"), - baseStyle.Foreground(t.Text()).Bold(true).Render("enter"), - baseStyle.Foreground(t.TextMuted()).Bold(true).Render(" for newline"), - ) - } - return baseStyle. - Width(m.width). - Render(text) -} - func (m *messagesComponent) home() string { - t := theme.CurrentTheme() + // t := theme.CurrentTheme() baseStyle := styles.BaseStyle() base := baseStyle.Render muted := styles.Muted().Render @@ -398,16 +333,13 @@ func (m *messagesComponent) home() string { lines = append(lines, "") } - return styles.ForceReplaceBackgroundWithLipgloss( - lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, - baseStyle.Width(lipgloss.Width(logoAndVersion)).Render( - lipgloss.JoinVertical( - lipgloss.Top, - lines..., - ), - )), - t.Background(), - ) + return lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, + baseStyle.Width(lipgloss.Width(logoAndVersion)).Render( + lipgloss.JoinVertical( + lipgloss.Top, + lines..., + ), + )) } func (m *messagesComponent) SetSize(width, height int) tea.Cmd { @@ -420,10 +352,10 @@ func (m *messagesComponent) SetSize(width, height int) tea.Cmd { } m.width = width m.height = height - m.viewport.Width = width - m.viewport.Height = height - lipgloss.Height(m.header()) - m.attachments.Width = width + 40 - m.attachments.Height = 3 + m.viewport.SetWidth(width) + m.viewport.SetHeight(height - lipgloss.Height(m.header())) + m.attachments.SetWidth(width + 40) + m.attachments.SetHeight(3) m.renderView() return nil } @@ -449,15 +381,15 @@ func (m *messagesComponent) BindingKeys() []key.Binding { } } -func NewMessagesComponent(app *app.App) tea.Model { +func NewMessagesComponent(app *app.App) layout.ModelWithView { customSpinner := spinner.Spinner{ Frames: []string{" ", "┃", "┃"}, FPS: time.Second / 3, } s := spinner.New(spinner.WithSpinner(customSpinner)) - vp := viewport.New(0, 0) - attachments := viewport.New(0, 0) + vp := viewport.New() //(0, 0) + attachments := viewport.New() //(0, 0) vp.KeyMap.PageUp = messageKeys.PageUp vp.KeyMap.PageDown = messageKeys.PageDown vp.KeyMap.HalfPageUp = messageKeys.HalfPageUp diff --git a/packages/tui/internal/components/core/status.go b/packages/tui/internal/components/core/status.go index 10a123f0..2b992922 100644 --- a/packages/tui/internal/components/core/status.go +++ b/packages/tui/internal/components/core/status.go @@ -5,20 +5,21 @@ import ( "strings" "time" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode/internal/app" + "github.com/sst/opencode/internal/layout" "github.com/sst/opencode/internal/pubsub" "github.com/sst/opencode/internal/status" "github.com/sst/opencode/internal/styles" "github.com/sst/opencode/internal/theme" ) -type StatusCmp interface { - tea.Model +type StatusComponent interface { + layout.ModelWithView } -type statusCmp struct { +type statusComponent struct { app *app.App queue []status.StatusMessage width int @@ -27,7 +28,7 @@ type statusCmp struct { } // clearMessageCmd is a command that clears status messages after a timeout -func (m statusCmp) clearMessageCmd() tea.Cmd { +func (m statusComponent) clearMessageCmd() tea.Cmd { return tea.Tick(time.Second, func(t time.Time) tea.Msg { return statusCleanupMsg{time: t} }) @@ -38,11 +39,11 @@ type statusCleanupMsg struct { time time.Time } -func (m statusCmp) Init() tea.Cmd { +func (m statusComponent) Init() tea.Cmd { return m.clearMessageCmd() } -func (m statusCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (m statusComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.WindowSizeMsg: m.width = msg.Width @@ -104,10 +105,9 @@ func logo() string { open := styles.Muted().Render("open") code := styles.BaseStyle().Bold(true).Render("code") version := styles.Muted().Render(app.Info.Version) - return styles.ForceReplaceBackgroundWithLipgloss( - styles.Padded().Render(mark+open+code+" "+version), - t.BackgroundElement(), - ) + return styles.Padded(). + Background(t.BackgroundElement()). + Render(mark + open + code + " " + version) } func formatTokensAndCost(tokens float32, contextWindow float32, cost float32) string { @@ -137,7 +137,7 @@ func formatTokensAndCost(tokens float32, contextWindow float32, cost float32) st return fmt.Sprintf("Tokens: %s (%d%%), Cost: %s", formattedTokens, int(percentage), formattedCost) } -func (m statusCmp) View() string { +func (m statusComponent) View() string { if m.app.Session.Id == "" { return styles.BaseStyle(). Width(m.width). @@ -250,107 +250,8 @@ func (m statusCmp) View() string { // } } -func (m *statusCmp) projectDiagnostics() string { - t := theme.CurrentTheme() - - // Check if any LSP server is still initializing - initializing := false - // for _, client := range m.app.LSPClients { - // if client.GetServerState() == lsp.StateStarting { - // initializing = true - // break - // } - // } - - // If any server is initializing, show that status - if initializing { - return lipgloss.NewStyle(). - Foreground(t.Warning()). - Render(fmt.Sprintf("%s Initializing LSP...", styles.SpinnerIcon)) - } - - // errorDiagnostics := []protocol.Diagnostic{} - // warnDiagnostics := []protocol.Diagnostic{} - // hintDiagnostics := []protocol.Diagnostic{} - // infoDiagnostics := []protocol.Diagnostic{} - // for _, client := range m.app.LSPClients { - // for _, d := range client.GetDiagnostics() { - // for _, diag := range d { - // switch diag.Severity { - // case protocol.SeverityError: - // errorDiagnostics = append(errorDiagnostics, diag) - // case protocol.SeverityWarning: - // warnDiagnostics = append(warnDiagnostics, diag) - // case protocol.SeverityHint: - // hintDiagnostics = append(hintDiagnostics, diag) - // case protocol.SeverityInformation: - // infoDiagnostics = append(infoDiagnostics, diag) - // } - // } - // } - // } - return styles.ForceReplaceBackgroundWithLipgloss( - styles.Padded().Render("No diagnostics"), - t.BackgroundElement(), - ) - - // if len(errorDiagnostics) == 0 && - // len(warnDiagnostics) == 0 && - // len(infoDiagnostics) == 0 && - // len(hintDiagnostics) == 0 { - // return styles.ForceReplaceBackgroundWithLipgloss( - // styles.Padded().Render("No diagnostics"), - // t.BackgroundDarker(), - // ) - // } - - // diagnostics := []string{} - // - // errStr := lipgloss.NewStyle(). - // Background(t.BackgroundDarker()). - // Foreground(t.Error()). - // Render(fmt.Sprintf("%s %d", styles.ErrorIcon, len(errorDiagnostics))) - // diagnostics = append(diagnostics, errStr) - // - // warnStr := lipgloss.NewStyle(). - // Background(t.BackgroundDarker()). - // Foreground(t.Warning()). - // Render(fmt.Sprintf("%s %d", styles.WarningIcon, len(warnDiagnostics))) - // diagnostics = append(diagnostics, warnStr) - // - // infoStr := lipgloss.NewStyle(). - // Background(t.BackgroundDarker()). - // Foreground(t.Info()). - // Render(fmt.Sprintf("%s %d", styles.InfoIcon, len(infoDiagnostics))) - // diagnostics = append(diagnostics, infoStr) - // - // hintStr := lipgloss.NewStyle(). - // Background(t.BackgroundDarker()). - // Foreground(t.Text()). - // Render(fmt.Sprintf("%s %d", styles.HintIcon, len(hintDiagnostics))) - // diagnostics = append(diagnostics, hintStr) - // - // return styles.ForceReplaceBackgroundWithLipgloss( - // styles.Padded().Render(strings.Join(diagnostics, " ")), - // t.BackgroundDarker(), - // ) -} - -func (m statusCmp) model() string { - t := theme.CurrentTheme() - model := "None" - if m.app.Model != nil { - model = *m.app.Model.Name - } - - return styles.Padded(). - Background(t.Secondary()). - Foreground(t.Background()). - Render(model) -} - -func NewStatusCmp(app *app.App) StatusCmp { - statusComponent := &statusCmp{ +func NewStatusCmp(app *app.App) StatusComponent { + statusComponent := &statusComponent{ app: app, queue: []status.StatusMessage{}, messageTTL: 4 * time.Second, diff --git a/packages/tui/internal/components/dialog/arguments.go b/packages/tui/internal/components/dialog/arguments.go index 2faa3607..4ef21fcf 100644 --- a/packages/tui/internal/components/dialog/arguments.go +++ b/packages/tui/internal/components/dialog/arguments.go @@ -2,10 +2,10 @@ package dialog import ( "fmt" - "github.com/charmbracelet/bubbles/key" - "github.com/charmbracelet/bubbles/textinput" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/key" + "github.com/charmbracelet/bubbles/v2/textinput" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode/internal/styles" "github.com/sst/opencode/internal/theme" @@ -70,17 +70,24 @@ func NewMultiArgumentsDialogCmp(commandID, content string, argNames []string) Mu for i, name := range argNames { ti := textinput.New() ti.Placeholder = fmt.Sprintf("Enter value for %s...", name) - ti.Width = 40 + ti.SetWidth(40) ti.Prompt = "" - ti.PlaceholderStyle = ti.PlaceholderStyle.Background(t.Background()) - ti.PromptStyle = ti.PromptStyle.Background(t.Background()) - ti.TextStyle = ti.TextStyle.Background(t.Background()) + ti.Styles.Blurred.Placeholder = ti.Styles.Blurred.Placeholder.Background(t.Background()) + ti.Styles.Blurred.Text = ti.Styles.Blurred.Text.Background(t.Background()) + ti.Styles.Blurred.Prompt = ti.Styles.Blurred.Prompt.Foreground(t.Primary()) + + ti.Styles.Focused.Placeholder = ti.Styles.Focused.Placeholder.Background(t.Background()) + ti.Styles.Focused.Text = ti.Styles.Focused.Text.Background(t.Background()) + ti.Styles.Focused.Prompt = ti.Styles.Focused.Prompt.Foreground(t.Primary()) + + // ti.PromptStyle = ti.PromptStyle.Background(t.Background()) + // ti.TextStyle = ti.TextStyle.Background(t.Background()) // Only focus the first input initially if i == 0 { ti.Focus() - ti.PromptStyle = ti.PromptStyle.Foreground(t.Primary()) - ti.TextStyle = ti.TextStyle.Foreground(t.Primary()) + // ti.PromptStyle = ti.PromptStyle.Foreground(t.Primary()) + // ti.TextStyle = ti.TextStyle.Foreground(t.Primary()) } else { ti.Blur() } @@ -115,7 +122,7 @@ func (m MultiArgumentsDialogCmp) Init() tea.Cmd { // Update implements tea.Model. func (m MultiArgumentsDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmds []tea.Cmd - t := theme.CurrentTheme() + // t := theme.CurrentTheme() switch msg := msg.(type) { case tea.KeyMsg: @@ -145,22 +152,22 @@ func (m MultiArgumentsDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.inputs[m.focusIndex].Blur() m.focusIndex++ m.inputs[m.focusIndex].Focus() - m.inputs[m.focusIndex].PromptStyle = m.inputs[m.focusIndex].PromptStyle.Foreground(t.Primary()) - m.inputs[m.focusIndex].TextStyle = m.inputs[m.focusIndex].TextStyle.Foreground(t.Primary()) + // m.inputs[m.focusIndex].PromptStyle = m.inputs[m.focusIndex].PromptStyle.Foreground(t.Primary()) + // m.inputs[m.focusIndex].TextStyle = m.inputs[m.focusIndex].TextStyle.Foreground(t.Primary()) case key.Matches(msg, key.NewBinding(key.WithKeys("tab"))): // Move to the next input m.inputs[m.focusIndex].Blur() m.focusIndex = (m.focusIndex + 1) % len(m.inputs) m.inputs[m.focusIndex].Focus() - m.inputs[m.focusIndex].PromptStyle = m.inputs[m.focusIndex].PromptStyle.Foreground(t.Primary()) - m.inputs[m.focusIndex].TextStyle = m.inputs[m.focusIndex].TextStyle.Foreground(t.Primary()) + // m.inputs[m.focusIndex].PromptStyle = m.inputs[m.focusIndex].PromptStyle.Foreground(t.Primary()) + // m.inputs[m.focusIndex].TextStyle = m.inputs[m.focusIndex].TextStyle.Foreground(t.Primary()) case key.Matches(msg, key.NewBinding(key.WithKeys("shift+tab"))): // Move to the previous input m.inputs[m.focusIndex].Blur() m.focusIndex = (m.focusIndex - 1 + len(m.inputs)) % len(m.inputs) m.inputs[m.focusIndex].Focus() - m.inputs[m.focusIndex].PromptStyle = m.inputs[m.focusIndex].PromptStyle.Foreground(t.Primary()) - m.inputs[m.focusIndex].TextStyle = m.inputs[m.focusIndex].TextStyle.Foreground(t.Primary()) + // m.inputs[m.focusIndex].PromptStyle = m.inputs[m.focusIndex].PromptStyle.Foreground(t.Primary()) + // m.inputs[m.focusIndex].TextStyle = m.inputs[m.focusIndex].TextStyle.Foreground(t.Primary()) } case tea.WindowSizeMsg: m.width = msg.Width diff --git a/packages/tui/internal/components/dialog/commands.go b/packages/tui/internal/components/dialog/commands.go index 1e99c09e..39fe793d 100644 --- a/packages/tui/internal/components/dialog/commands.go +++ b/packages/tui/internal/components/dialog/commands.go @@ -1,9 +1,9 @@ package dialog import ( - "github.com/charmbracelet/bubbles/key" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/key" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" utilComponents "github.com/sst/opencode/internal/components/util" "github.com/sst/opencode/internal/layout" "github.com/sst/opencode/internal/styles" @@ -56,12 +56,12 @@ type CloseCommandDialogMsg struct{} // CommandDialog interface for the command selection dialog type CommandDialog interface { - tea.Model + layout.ModelWithView layout.Bindings SetCommands(commands []Command) } -type commandDialogCmp struct { +type commandDialogComponent struct { listView utilComponents.SimpleList[Command] width int height int @@ -83,11 +83,11 @@ var commandKeys = commandKeyMap{ ), } -func (c *commandDialogCmp) Init() tea.Cmd { +func (c *commandDialogComponent) Init() tea.Cmd { return c.listView.Init() } -func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (c *commandDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmds []tea.Cmd switch msg := msg.(type) { case tea.KeyMsg: @@ -114,7 +114,7 @@ func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return c, tea.Batch(cmds...) } -func (c *commandDialogCmp) View() string { +func (c *commandDialogComponent) View() string { t := theme.CurrentTheme() baseStyle := styles.BaseStyle() @@ -158,11 +158,11 @@ func (c *commandDialogCmp) View() string { Render(content) } -func (c *commandDialogCmp) BindingKeys() []key.Binding { +func (c *commandDialogComponent) BindingKeys() []key.Binding { return layout.KeyMapToSlice(commandKeys) } -func (c *commandDialogCmp) SetCommands(commands []Command) { +func (c *commandDialogComponent) SetCommands(commands []Command) { c.listView.SetItems(commands) } @@ -174,7 +174,7 @@ func NewCommandDialogCmp() CommandDialog { "No commands available", true, ) - return &commandDialogCmp{ + return &commandDialogComponent{ listView: listView, } } diff --git a/packages/tui/internal/components/dialog/complete.go b/packages/tui/internal/components/dialog/complete.go index ca209014..91ac8f7b 100644 --- a/packages/tui/internal/components/dialog/complete.go +++ b/packages/tui/internal/components/dialog/complete.go @@ -1,13 +1,13 @@ package dialog import ( - "github.com/charmbracelet/bubbles/key" - "github.com/charmbracelet/bubbles/textarea" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" - "github.com/sst/opencode/internal/status" + "github.com/charmbracelet/bubbles/v2/key" + "github.com/charmbracelet/bubbles/v2/textarea" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" utilComponents "github.com/sst/opencode/internal/components/util" "github.com/sst/opencode/internal/layout" + "github.com/sst/opencode/internal/status" "github.com/sst/opencode/internal/styles" "github.com/sst/opencode/internal/theme" "github.com/sst/opencode/internal/util" @@ -77,7 +77,7 @@ type CompletionDialogCompleteItemMsg struct { type CompletionDialogCloseMsg struct{} type CompletionDialog interface { - tea.Model + layout.ModelWithView layout.Bindings SetWidth(width int) } diff --git a/packages/tui/internal/components/dialog/custom_commands.go b/packages/tui/internal/components/dialog/custom_commands.go index c0115ad7..5e0671b8 100644 --- a/packages/tui/internal/components/dialog/custom_commands.go +++ b/packages/tui/internal/components/dialog/custom_commands.go @@ -7,7 +7,7 @@ import ( "regexp" "strings" - tea "github.com/charmbracelet/bubbletea" + tea "github.com/charmbracelet/bubbletea/v2" "github.com/sst/opencode/internal/app" "github.com/sst/opencode/internal/util" ) diff --git a/packages/tui/internal/components/dialog/filepicker.go b/packages/tui/internal/components/dialog/filepicker.go index 3fad90e3..408b9cc0 100644 --- a/packages/tui/internal/components/dialog/filepicker.go +++ b/packages/tui/internal/components/dialog/filepicker.go @@ -12,13 +12,14 @@ import ( "log/slog" "github.com/atotto/clipboard" - "github.com/charmbracelet/bubbles/key" - "github.com/charmbracelet/bubbles/textinput" - "github.com/charmbracelet/bubbles/viewport" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/key" + "github.com/charmbracelet/bubbles/v2/textinput" + "github.com/charmbracelet/bubbles/v2/viewport" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode/internal/app" "github.com/sst/opencode/internal/image" + "github.com/sst/opencode/internal/layout" "github.com/sst/opencode/internal/status" "github.com/sst/opencode/internal/styles" "github.com/sst/opencode/internal/theme" @@ -82,7 +83,7 @@ var filePickerKeyMap = FilePrickerKeyMap{ ), } -type filepickerCmp struct { +type filepickerComponent struct { basePath string width int height int @@ -118,18 +119,18 @@ type AttachmentAddedMsg struct { Attachment app.Attachment } -func (f *filepickerCmp) Init() tea.Cmd { +func (f *filepickerComponent) Init() tea.Cmd { return nil } -func (f *filepickerCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (f *filepickerComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd switch msg := msg.(type) { case tea.WindowSizeMsg: f.width = 60 f.height = 20 - f.viewport.Width = 80 - f.viewport.Height = 22 + f.viewport.SetWidth(80) + f.viewport.SetHeight(22) f.cursor = 0 f.getCurrentFileBelowCursor() case tea.KeyMsg: @@ -236,7 +237,7 @@ func (f *filepickerCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return f, cmd } -func (f *filepickerCmp) addAttachmentToMessage() (tea.Model, tea.Cmd) { +func (f *filepickerComponent) addAttachmentToMessage() (tea.Model, tea.Cmd) { // modeInfo := GetSelectedModel(config.Get()) // if !modeInfo.SupportsAttachments { // status.Error(fmt.Sprintf("Model %s doesn't support attachments", modeInfo.Name)) @@ -273,7 +274,7 @@ func (f *filepickerCmp) addAttachmentToMessage() (tea.Model, tea.Cmd) { return f, util.CmdHandler(AttachmentAddedMsg{attachment}) } -func (f *filepickerCmp) View() string { +func (f *filepickerComponent) View() string { t := theme.CurrentTheme() const maxVisibleDirs = 20 const maxWidth = 80 @@ -333,7 +334,7 @@ func (f *filepickerCmp) View() string { Render(f.cwd.View()) viewportstyle := lipgloss.NewStyle(). - Width(f.viewport.Width). + Width(f.viewport.Width()). Background(t.Background()). Border(lipgloss.RoundedBorder()). BorderForeground(t.TextMuted()). @@ -366,21 +367,21 @@ func (f *filepickerCmp) View() string { return lipgloss.JoinHorizontal(lipgloss.Center, contentStyle.Render(content), viewportstyle) } -type FilepickerCmp interface { - tea.Model +type FilepickerComponent interface { + layout.ModelWithView ToggleFilepicker(showFilepicker bool) IsCWDFocused() bool } -func (f *filepickerCmp) ToggleFilepicker(showFilepicker bool) { +func (f *filepickerComponent) ToggleFilepicker(showFilepicker bool) { f.ShowFilePicker = showFilepicker } -func (f *filepickerCmp) IsCWDFocused() bool { +func (f *filepickerComponent) IsCWDFocused() bool { return f.cwd.Focused() } -func NewFilepickerCmp(app *app.App) FilepickerCmp { +func NewFilepickerCmp(app *app.App) FilepickerComponent { homepath, err := os.UserHomeDir() if err != nil { slog.Error("error loading user files") @@ -388,16 +389,16 @@ func NewFilepickerCmp(app *app.App) FilepickerCmp { } baseDir := DirNode{parent: nil, directory: homepath} dirs := readDir(homepath, false) - viewport := viewport.New(0, 0) + viewport := viewport.New() // viewport.New(0, 0) currentDirectory := textinput.New() currentDirectory.CharLimit = 200 - currentDirectory.Width = 44 - currentDirectory.Cursor.Blink = true + currentDirectory.SetWidth(44) + // currentDirectory.Cursor.Blink = true currentDirectory.SetValue(baseDir.directory) - return &filepickerCmp{cwdDetails: &baseDir, dirs: dirs, cursorChain: make(stack, 0), viewport: viewport, cwd: currentDirectory, app: app} + return &filepickerComponent{cwdDetails: &baseDir, dirs: dirs, cursorChain: make(stack, 0), viewport: viewport, cwd: currentDirectory, app: app} } -func (f *filepickerCmp) getCurrentFileBelowCursor() { +func (f *filepickerComponent) getCurrentFileBelowCursor() { if len(f.dirs) == 0 || f.cursor < 0 || f.cursor >= len(f.dirs) { slog.Error(fmt.Sprintf("Invalid cursor position. Dirs length: %d, Cursor: %d", len(f.dirs), f.cursor)) f.viewport.SetContent("Preview unavailable") @@ -410,7 +411,7 @@ func (f *filepickerCmp) getCurrentFileBelowCursor() { fullPath := f.cwdDetails.directory + "/" + dir.Name() go func() { - imageString, err := image.ImagePreview(f.viewport.Width-4, fullPath) + imageString, err := image.ImagePreview(f.viewport.Width()-4, fullPath) if err != nil { slog.Error(err.Error()) f.viewport.SetContent("Preview unavailable") diff --git a/packages/tui/internal/components/dialog/help.go b/packages/tui/internal/components/dialog/help.go index a55e39e7..6ceeb40b 100644 --- a/packages/tui/internal/components/dialog/help.go +++ b/packages/tui/internal/components/dialog/help.go @@ -3,28 +3,29 @@ package dialog import ( "strings" - "github.com/charmbracelet/bubbles/key" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/key" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" + "github.com/sst/opencode/internal/layout" "github.com/sst/opencode/internal/styles" "github.com/sst/opencode/internal/theme" ) -type helpCmp struct { +type helpComponent struct { width int height int keys []key.Binding } -func (h *helpCmp) Init() tea.Cmd { +func (h *helpComponent) Init() tea.Cmd { return nil } -func (h *helpCmp) SetBindings(k []key.Binding) { +func (h *helpComponent) SetBindings(k []key.Binding) { h.keys = k } -func (h *helpCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (h *helpComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.WindowSizeMsg: h.width = 90 @@ -53,7 +54,7 @@ func removeDuplicateBindings(bindings []key.Binding) []key.Binding { return result } -func (h *helpCmp) render() string { +func (h *helpComponent) render() string { t := theme.CurrentTheme() baseStyle := styles.BaseStyle() @@ -134,7 +135,7 @@ func (h *helpCmp) render() string { pairs = append(pairs, pair) } - // https://github.com/charmbracelet/lipgloss/issues/209 + // https://github.com/charmbracelet/lipgloss/v2/issues/209 if len(pairs) > 1 { prefix := pairs[:len(pairs)-1] lastPair := pairs[len(pairs)-1] @@ -144,7 +145,7 @@ func (h *helpCmp) render() string { lipgloss.Left, // x lipgloss.Top, // y lastPair, // content - lipgloss.WithWhitespaceBackground(t.Background()), + // lipgloss.WithWhitespaceBackground(t.Background()), )) content := baseStyle.Width(h.width).Render( lipgloss.JoinHorizontal( @@ -165,7 +166,7 @@ func (h *helpCmp) render() string { return content } -func (h *helpCmp) View() string { +func (h *helpComponent) View() string { t := theme.CurrentTheme() baseStyle := styles.BaseStyle() @@ -190,11 +191,11 @@ func (h *helpCmp) View() string { ) } -type HelpCmp interface { - tea.Model +type HelpComponent interface { + layout.ModelWithView SetBindings([]key.Binding) } -func NewHelpCmp() HelpCmp { - return &helpCmp{} +func NewHelpCmp() HelpComponent { + return &helpComponent{} } diff --git a/packages/tui/internal/components/dialog/init.go b/packages/tui/internal/components/dialog/init.go index 01bdbe57..d939427c 100644 --- a/packages/tui/internal/components/dialog/init.go +++ b/packages/tui/internal/components/dialog/init.go @@ -1,9 +1,9 @@ package dialog import ( - "github.com/charmbracelet/bubbles/key" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/key" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode/internal/styles" "github.com/sst/opencode/internal/theme" diff --git a/packages/tui/internal/components/dialog/models.go b/packages/tui/internal/components/dialog/models.go index 5d0ee772..50d1791c 100644 --- a/packages/tui/internal/components/dialog/models.go +++ b/packages/tui/internal/components/dialog/models.go @@ -7,9 +7,9 @@ import ( "slices" "strings" - "github.com/charmbracelet/bubbles/key" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/key" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode/internal/app" "github.com/sst/opencode/internal/layout" "github.com/sst/opencode/internal/styles" @@ -31,13 +31,13 @@ type CloseModelDialogMsg struct { // ModelDialog interface for the model selection dialog type ModelDialog interface { - tea.Model + layout.ModelWithView layout.Bindings SetProviders(providers []client.ProviderInfo) } -type modelDialogCmp struct { +type modelDialogComponent struct { app *app.App availableProviders []client.ProviderInfo provider client.ProviderInfo @@ -106,7 +106,7 @@ var modelKeys = modelKeyMap{ ), } -func (m *modelDialogCmp) Init() tea.Cmd { +func (m *modelDialogComponent) Init() tea.Cmd { // cfg := config.Get() // modelInfo := GetSelectedModel(cfg) // m.availableProviders = getEnabledProviders(cfg) @@ -125,11 +125,11 @@ func (m *modelDialogCmp) Init() tea.Cmd { return nil } -func (m *modelDialogCmp) SetProviders(providers []client.ProviderInfo) { +func (m *modelDialogComponent) SetProviders(providers []client.ProviderInfo) { m.availableProviders = providers } -func (m *modelDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (m *modelDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyMsg: switch { @@ -159,7 +159,7 @@ func (m *modelDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil } -func (m *modelDialogCmp) models() []client.ProviderModel { +func (m *modelDialogComponent) models() []client.ProviderModel { models := slices.SortedFunc(maps.Values(m.provider.Models), func(a, b client.ProviderModel) int { return strings.Compare(*a.Name, *b.Name) }) @@ -167,7 +167,7 @@ func (m *modelDialogCmp) models() []client.ProviderModel { } // moveSelectionUp moves the selection up or wraps to bottom -func (m *modelDialogCmp) moveSelectionUp() { +func (m *modelDialogComponent) moveSelectionUp() { if m.selectedIdx > 0 { m.selectedIdx-- } else { @@ -182,7 +182,7 @@ func (m *modelDialogCmp) moveSelectionUp() { } // moveSelectionDown moves the selection down or wraps to top -func (m *modelDialogCmp) moveSelectionDown() { +func (m *modelDialogComponent) moveSelectionDown() { if m.selectedIdx < len(m.provider.Models)-1 { m.selectedIdx++ } else { @@ -196,7 +196,7 @@ func (m *modelDialogCmp) moveSelectionDown() { } } -func (m *modelDialogCmp) switchProvider(offset int) { +func (m *modelDialogComponent) switchProvider(offset int) { newOffset := m.hScrollOffset + offset // Ensure we stay within bounds @@ -212,7 +212,7 @@ func (m *modelDialogCmp) switchProvider(offset int) { m.setupModelsForProvider(m.provider.Id) } -func (m *modelDialogCmp) View() string { +func (m *modelDialogComponent) View() string { t := theme.CurrentTheme() baseStyle := styles.BaseStyle() @@ -255,7 +255,7 @@ func (m *modelDialogCmp) View() string { Render(content) } -func (m *modelDialogCmp) getScrollIndicators(maxWidth int) string { +func (m *modelDialogComponent) getScrollIndicators(maxWidth int) string { var indicator string if len(m.provider.Models) > numVisibleModels { @@ -291,7 +291,7 @@ func (m *modelDialogCmp) getScrollIndicators(maxWidth int) string { Render(indicator) } -func (m *modelDialogCmp) BindingKeys() []key.Binding { +func (m *modelDialogComponent) BindingKeys() []key.Binding { return layout.KeyMapToSlice(modelKeys) } @@ -305,7 +305,7 @@ func (m *modelDialogCmp) BindingKeys() []key.Binding { // return -1 // } -func (m *modelDialogCmp) setupModelsForProvider(_ string) { +func (m *modelDialogComponent) setupModelsForProvider(_ string) { m.selectedIdx = 0 m.scrollOffset = 0 @@ -332,7 +332,7 @@ func (m *modelDialogCmp) setupModelsForProvider(_ string) { } func NewModelDialogCmp(app *app.App) ModelDialog { - return &modelDialogCmp{ + return &modelDialogComponent{ app: app, } } diff --git a/packages/tui/internal/components/dialog/permission.go b/packages/tui/internal/components/dialog/permission.go index bb71fc35..526e0348 100644 --- a/packages/tui/internal/components/dialog/permission.go +++ b/packages/tui/internal/components/dialog/permission.go @@ -2,10 +2,10 @@ package dialog import ( "fmt" - "github.com/charmbracelet/bubbles/key" - "github.com/charmbracelet/bubbles/viewport" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/key" + "github.com/charmbracelet/bubbles/v2/viewport" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode/internal/layout" "github.com/sst/opencode/internal/styles" "github.com/sst/opencode/internal/theme" @@ -28,9 +28,9 @@ type PermissionResponseMsg struct { Action PermissionAction } -// PermissionDialogCmp interface for permission dialog component -type PermissionDialogCmp interface { - tea.Model +// PermissionDialogComponent interface for permission dialog component +type PermissionDialogComponent interface { + layout.ModelWithView layout.Bindings // SetPermissions(permission permission.PermissionRequest) tea.Cmd } @@ -76,8 +76,8 @@ var permissionsKeys = permissionsMapping{ ), } -// permissionDialogCmp is the implementation of PermissionDialog -type permissionDialogCmp struct { +// permissionDialogComponent is the implementation of PermissionDialog +type permissionDialogComponent struct { width int height int // permission permission.PermissionRequest @@ -89,11 +89,11 @@ type permissionDialogCmp struct { markdownCache map[string]string } -func (p *permissionDialogCmp) Init() tea.Cmd { +func (p *permissionDialogComponent) Init() tea.Cmd { return p.contentViewPort.Init() } -func (p *permissionDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (p *permissionDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmds []tea.Cmd switch msg := msg.(type) { @@ -129,7 +129,7 @@ func (p *permissionDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return p, tea.Batch(cmds...) } -func (p *permissionDialogCmp) selectCurrentOption() tea.Cmd { +func (p *permissionDialogComponent) selectCurrentOption() tea.Cmd { var action PermissionAction switch p.selectedOption { @@ -144,7 +144,7 @@ func (p *permissionDialogCmp) selectCurrentOption() tea.Cmd { return util.CmdHandler(PermissionResponseMsg{Action: action}) // , Permission: p.permission}) } -func (p *permissionDialogCmp) renderButtons() string { +func (p *permissionDialogComponent) renderButtons() string { t := theme.CurrentTheme() baseStyle := styles.BaseStyle() @@ -190,7 +190,7 @@ func (p *permissionDialogCmp) renderButtons() string { return content } -func (p *permissionDialogCmp) renderHeader() string { +func (p *permissionDialogComponent) renderHeader() string { return "NOT IMPLEMENTED" // t := theme.CurrentTheme() // baseStyle := styles.BaseStyle() @@ -246,7 +246,7 @@ func (p *permissionDialogCmp) renderHeader() string { // return lipgloss.NewStyle().Background(t.Background()).Render(lipgloss.JoinVertical(lipgloss.Left, headerParts...)) } -func (p *permissionDialogCmp) renderBashContent() string { +func (p *permissionDialogComponent) renderBashContent() string { // t := theme.CurrentTheme() // baseStyle := styles.BaseStyle() // @@ -269,7 +269,7 @@ func (p *permissionDialogCmp) renderBashContent() string { return "" } -func (p *permissionDialogCmp) renderEditContent() string { +func (p *permissionDialogComponent) renderEditContent() string { // if pr, ok := p.permission.Params.(tools.EditPermissionsParams); ok { // diff := p.GetOrSetDiff(p.permission.ID, func() (string, error) { // return diff.FormatDiff(pr.Diff, diff.WithTotalWidth(p.contentViewPort.Width)) @@ -281,7 +281,7 @@ func (p *permissionDialogCmp) renderEditContent() string { return "" } -func (p *permissionDialogCmp) renderPatchContent() string { +func (p *permissionDialogComponent) renderPatchContent() string { // if pr, ok := p.permission.Params.(tools.EditPermissionsParams); ok { // diff := p.GetOrSetDiff(p.permission.ID, func() (string, error) { // return diff.FormatDiff(pr.Diff, diff.WithTotalWidth(p.contentViewPort.Width)) @@ -293,7 +293,7 @@ func (p *permissionDialogCmp) renderPatchContent() string { return "" } -func (p *permissionDialogCmp) renderWriteContent() string { +func (p *permissionDialogComponent) renderWriteContent() string { // if pr, ok := p.permission.Params.(tools.WritePermissionsParams); ok { // // Use the cache for diff rendering // diff := p.GetOrSetDiff(p.permission.ID, func() (string, error) { @@ -306,7 +306,7 @@ func (p *permissionDialogCmp) renderWriteContent() string { return "" } -func (p *permissionDialogCmp) renderFetchContent() string { +func (p *permissionDialogComponent) renderFetchContent() string { // t := theme.CurrentTheme() // baseStyle := styles.BaseStyle() // @@ -329,7 +329,7 @@ func (p *permissionDialogCmp) renderFetchContent() string { return "" } -func (p *permissionDialogCmp) renderDefaultContent() string { +func (p *permissionDialogComponent) renderDefaultContent() string { // t := theme.CurrentTheme() // baseStyle := styles.BaseStyle() // @@ -354,7 +354,7 @@ func (p *permissionDialogCmp) renderDefaultContent() string { return p.styleViewport() } -func (p *permissionDialogCmp) styleViewport() string { +func (p *permissionDialogComponent) styleViewport() string { t := theme.CurrentTheme() contentStyle := lipgloss.NewStyle(). Background(t.Background()) @@ -362,7 +362,7 @@ func (p *permissionDialogCmp) styleViewport() string { return contentStyle.Render(p.contentViewPort.View()) } -func (p *permissionDialogCmp) render() string { +func (p *permissionDialogComponent) render() string { return "NOT IMPLEMENTED" // t := theme.CurrentTheme() // baseStyle := styles.BaseStyle() @@ -420,15 +420,15 @@ func (p *permissionDialogCmp) render() string { // ) } -func (p *permissionDialogCmp) View() string { +func (p *permissionDialogComponent) View() string { return p.render() } -func (p *permissionDialogCmp) BindingKeys() []key.Binding { +func (p *permissionDialogComponent) BindingKeys() []key.Binding { return layout.KeyMapToSlice(permissionsKeys) } -func (p *permissionDialogCmp) SetSize() tea.Cmd { +func (p *permissionDialogComponent) SetSize() tea.Cmd { // if p.permission.ID == "" { // return nil // } @@ -458,7 +458,7 @@ func (p *permissionDialogCmp) SetSize() tea.Cmd { // } // Helper to get or set cached diff content -func (c *permissionDialogCmp) GetOrSetDiff(key string, generator func() (string, error)) string { +func (c *permissionDialogComponent) GetOrSetDiff(key string, generator func() (string, error)) string { if cached, ok := c.diffCache[key]; ok { return cached } @@ -474,7 +474,7 @@ func (c *permissionDialogCmp) GetOrSetDiff(key string, generator func() (string, } // Helper to get or set cached markdown content -func (c *permissionDialogCmp) GetOrSetMarkdown(key string, generator func() (string, error)) string { +func (c *permissionDialogComponent) GetOrSetMarkdown(key string, generator func() (string, error)) string { if cached, ok := c.markdownCache[key]; ok { return cached } @@ -489,11 +489,11 @@ func (c *permissionDialogCmp) GetOrSetMarkdown(key string, generator func() (str return content } -func NewPermissionDialogCmp() PermissionDialogCmp { +func NewPermissionDialogCmp() PermissionDialogComponent { // Create viewport for content - contentViewport := viewport.New(0, 0) + contentViewport := viewport.New() // (0, 0) - return &permissionDialogCmp{ + return &permissionDialogComponent{ contentViewPort: contentViewport, selectedOption: 0, // Default to "Allow" diffCache: make(map[string]string), diff --git a/packages/tui/internal/components/dialog/quit.go b/packages/tui/internal/components/dialog/quit.go index 78034c71..8362e767 100644 --- a/packages/tui/internal/components/dialog/quit.go +++ b/packages/tui/internal/components/dialog/quit.go @@ -3,9 +3,9 @@ package dialog import ( "strings" - "github.com/charmbracelet/bubbles/key" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/key" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode/internal/layout" "github.com/sst/opencode/internal/styles" "github.com/sst/opencode/internal/theme" @@ -17,11 +17,11 @@ const question = "Are you sure you want to quit?" type CloseQuitMsg struct{} type QuitDialog interface { - tea.Model + layout.ModelWithView layout.Bindings } -type quitDialogCmp struct { +type quitDialogComponent struct { selectedNo bool } @@ -56,11 +56,11 @@ var helpKeys = helpMapping{ ), } -func (q *quitDialogCmp) Init() tea.Cmd { +func (q *quitDialogComponent) Init() tea.Cmd { return nil } -func (q *quitDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (q *quitDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyMsg: switch { @@ -81,7 +81,7 @@ func (q *quitDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return q, nil } -func (q *quitDialogCmp) View() string { +func (q *quitDialogComponent) View() string { t := theme.CurrentTheme() baseStyle := styles.BaseStyle() @@ -125,12 +125,12 @@ func (q *quitDialogCmp) View() string { Render(content) } -func (q *quitDialogCmp) BindingKeys() []key.Binding { +func (q *quitDialogComponent) BindingKeys() []key.Binding { return layout.KeyMapToSlice(helpKeys) } func NewQuitCmp() QuitDialog { - return &quitDialogCmp{ + return &quitDialogComponent{ selectedNo: true, } } diff --git a/packages/tui/internal/components/dialog/session.go b/packages/tui/internal/components/dialog/session.go index 2d234529..8ef9a701 100644 --- a/packages/tui/internal/components/dialog/session.go +++ b/packages/tui/internal/components/dialog/session.go @@ -1,9 +1,9 @@ package dialog import ( - "github.com/charmbracelet/bubbles/key" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/key" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode/internal/layout" "github.com/sst/opencode/internal/styles" "github.com/sst/opencode/internal/theme" @@ -18,13 +18,13 @@ type CloseSessionDialogMsg struct { // SessionDialog interface for the session switching dialog type SessionDialog interface { - tea.Model + layout.ModelWithView layout.Bindings SetSessions(sessions []client.SessionInfo) SetSelectedSession(sessionID string) } -type sessionDialogCmp struct { +type sessionDialogComponent struct { sessions []client.SessionInfo selectedIdx int width int @@ -68,11 +68,11 @@ var sessionKeys = sessionKeyMap{ ), } -func (s *sessionDialogCmp) Init() tea.Cmd { +func (s *sessionDialogComponent) Init() tea.Cmd { return nil } -func (s *sessionDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (s *sessionDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.WindowSizeMsg: s.width = msg.Width @@ -105,7 +105,7 @@ func (s *sessionDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return s, nil } -func (s *sessionDialogCmp) View() string { +func (s *sessionDialogComponent) View() string { t := theme.CurrentTheme() baseStyle := styles.BaseStyle() @@ -185,11 +185,11 @@ func (s *sessionDialogCmp) View() string { Render(content) } -func (s *sessionDialogCmp) BindingKeys() []key.Binding { +func (s *sessionDialogComponent) BindingKeys() []key.Binding { return layout.KeyMapToSlice(sessionKeys) } -func (s *sessionDialogCmp) SetSessions(sessions []client.SessionInfo) { +func (s *sessionDialogComponent) SetSessions(sessions []client.SessionInfo) { s.sessions = sessions // If we have a selected session ID, find its index @@ -206,7 +206,7 @@ func (s *sessionDialogCmp) SetSessions(sessions []client.SessionInfo) { s.selectedIdx = 0 } -func (s *sessionDialogCmp) SetSelectedSession(sessionID string) { +func (s *sessionDialogComponent) SetSelectedSession(sessionID string) { s.selectedSessionID = sessionID // Update the selected index if sessions are already loaded @@ -222,7 +222,7 @@ func (s *sessionDialogCmp) SetSelectedSession(sessionID string) { // NewSessionDialogCmp creates a new session switching dialog func NewSessionDialogCmp() SessionDialog { - return &sessionDialogCmp{ + return &sessionDialogComponent{ sessions: []client.SessionInfo{}, selectedIdx: 0, selectedSessionID: "", diff --git a/packages/tui/internal/components/dialog/theme.go b/packages/tui/internal/components/dialog/theme.go index 42c777c4..4704cb42 100644 --- a/packages/tui/internal/components/dialog/theme.go +++ b/packages/tui/internal/components/dialog/theme.go @@ -1,9 +1,9 @@ package dialog import ( - "github.com/charmbracelet/bubbles/key" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/key" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode/internal/layout" "github.com/sst/opencode/internal/status" "github.com/sst/opencode/internal/styles" @@ -21,11 +21,11 @@ type CloseThemeDialogMsg struct{} // ThemeDialog interface for the theme switching dialog type ThemeDialog interface { - tea.Model + layout.ModelWithView layout.Bindings } -type themeDialogCmp struct { +type themeDialogComponent struct { themes []string selectedIdx int width int @@ -69,7 +69,7 @@ var themeKeys = themeKeyMap{ ), } -func (t *themeDialogCmp) Init() tea.Cmd { +func (t *themeDialogComponent) Init() tea.Cmd { // Load available themes and update selectedIdx based on current theme t.themes = theme.AvailableThemes() t.currentTheme = theme.CurrentThemeName() @@ -85,7 +85,7 @@ func (t *themeDialogCmp) Init() tea.Cmd { return nil } -func (t *themeDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (t *themeDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyMsg: switch { @@ -124,7 +124,7 @@ func (t *themeDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return t, nil } -func (t *themeDialogCmp) View() string { +func (t *themeDialogComponent) View() string { currentTheme := theme.CurrentTheme() baseStyle := styles.BaseStyle() @@ -185,13 +185,13 @@ func (t *themeDialogCmp) View() string { Render(content) } -func (t *themeDialogCmp) BindingKeys() []key.Binding { +func (t *themeDialogComponent) BindingKeys() []key.Binding { return layout.KeyMapToSlice(themeKeys) } // NewThemeDialogCmp creates a new theme switching dialog func NewThemeDialogCmp() ThemeDialog { - return &themeDialogCmp{ + return &themeDialogComponent{ themes: []string{}, selectedIdx: 0, currentTheme: "", diff --git a/packages/tui/internal/components/dialog/tools.go b/packages/tui/internal/components/dialog/tools.go index a01d1911..c91dfef9 100644 --- a/packages/tui/internal/components/dialog/tools.go +++ b/packages/tui/internal/components/dialog/tools.go @@ -1,9 +1,9 @@ package dialog import ( - "github.com/charmbracelet/bubbles/key" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/key" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" utilComponents "github.com/sst/opencode/internal/components/util" "github.com/sst/opencode/internal/layout" "github.com/sst/opencode/internal/styles" @@ -17,7 +17,7 @@ const ( // ToolsDialog interface for the tools list dialog type ToolsDialog interface { - tea.Model + layout.ModelWithView layout.Bindings SetTools(tools []string) } @@ -39,7 +39,7 @@ func (t toolItem) Render(selected bool, width int) string { baseStyle := styles.BaseStyle(). Width(width). Background(th.Background()) - + if selected { baseStyle = baseStyle. Background(th.Primary()). @@ -49,15 +49,15 @@ func (t toolItem) Render(selected bool, width int) string { baseStyle = baseStyle. Foreground(th.Text()) } - + return baseStyle.Render(t.name) } -type toolsDialogCmp struct { - tools []toolItem - width int - height int - list utilComponents.SimpleList[toolItem] +type toolsDialogComponent struct { + tools []toolItem + width int + height int + list utilComponents.SimpleList[toolItem] } type toolsKeyMap struct { @@ -91,21 +91,21 @@ var toolsKeys = toolsKeyMap{ ), } -func (m *toolsDialogCmp) Init() tea.Cmd { +func (m *toolsDialogComponent) Init() tea.Cmd { return nil } -func (m *toolsDialogCmp) SetTools(tools []string) { +func (m *toolsDialogComponent) SetTools(tools []string) { var toolItems []toolItem for _, name := range tools { toolItems = append(toolItems, toolItem{name: name}) } - + m.tools = toolItems m.list.SetItems(toolItems) } -func (m *toolsDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (m *toolsDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyMsg: switch { @@ -130,7 +130,7 @@ func (m *toolsDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, cmd } -func (m *toolsDialogCmp) View() string { +func (m *toolsDialogComponent) View() string { t := theme.CurrentTheme() baseStyle := styles.BaseStyle().Background(t.Background()) @@ -144,7 +144,7 @@ func (m *toolsDialogCmp) View() string { // Calculate dialog width based on content dialogWidth := min(maxToolsDialogWidth, m.width/2) m.list.SetMaxWidth(dialogWidth) - + content := lipgloss.JoinVertical( lipgloss.Left, title, @@ -160,7 +160,7 @@ func (m *toolsDialogCmp) View() string { Render(content) } -func (m *toolsDialogCmp) BindingKeys() []key.Binding { +func (m *toolsDialogComponent) BindingKeys() []key.Binding { return layout.KeyMapToSlice(toolsKeys) } @@ -171,8 +171,8 @@ func NewToolsDialogCmp() ToolsDialog { "No tools available", true, ) - - return &toolsDialogCmp{ + + return &toolsDialogComponent{ list: list, } } diff --git a/packages/tui/internal/components/diff/diff.go b/packages/tui/internal/components/diff/diff.go index 65874ebb..4551cf73 100644 --- a/packages/tui/internal/components/diff/diff.go +++ b/packages/tui/internal/components/diff/diff.go @@ -3,6 +3,7 @@ package diff import ( "bytes" "fmt" + "image/color" "io" "regexp" "strconv" @@ -12,9 +13,11 @@ import ( "github.com/alecthomas/chroma/v2/formatters" "github.com/alecthomas/chroma/v2/lexers" "github.com/alecthomas/chroma/v2/styles" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/v2" + "github.com/charmbracelet/lipgloss/v2/compat" "github.com/charmbracelet/x/ansi" "github.com/sergi/go-diff/diffmatchpatch" + stylesi "github.com/sst/opencode/internal/styles" "github.com/sst/opencode/internal/theme" ) @@ -300,7 +303,7 @@ func pairLines(lines []DiffLine) []linePair { // ------------------------------------------------------------------------- // SyntaxHighlight applies syntax highlighting to text based on file extension -func SyntaxHighlight(w io.Writer, source, fileName, formatter string, bg lipgloss.TerminalColor) error { +func SyntaxHighlight(w io.Writer, source, fileName, formatter string, bg color.Color) error { t := theme.CurrentTheme() // Determine the language lexer to use @@ -509,15 +512,12 @@ func SyntaxHighlight(w io.Writer, source, fileName, formatter string, bg lipglos } // getColor returns the appropriate hex color string based on terminal background -func getColor(adaptiveColor lipgloss.AdaptiveColor) string { - if lipgloss.HasDarkBackground() { - return adaptiveColor.Dark - } - return adaptiveColor.Light +func getColor(adaptiveColor compat.AdaptiveColor) string { + return stylesi.AdaptiveColorToString(adaptiveColor) } // highlightLine applies syntax highlighting to a single line -func highlightLine(fileName string, line string, bg lipgloss.TerminalColor) string { +func highlightLine(fileName string, line string, bg color.Color) string { var buf bytes.Buffer err := SyntaxHighlight(&buf, line, fileName, "terminal16m", bg) if err != nil { @@ -540,7 +540,7 @@ func createStyles(t theme.Theme) (removedLineStyle, addedLineStyle, contextLineS // ------------------------------------------------------------------------- // applyHighlighting applies intra-line highlighting to a piece of text -func applyHighlighting(content string, segments []Segment, segmentType LineType, highlightBg lipgloss.AdaptiveColor) string { +func applyHighlighting(content string, segments []Segment, segmentType LineType, highlightBg compat.AdaptiveColor) string { // Find all ANSI sequences in the content ansiRegex := regexp.MustCompile(`\x1b(?:[@-Z\\-_]|\[[0-9?]*(?:;[0-9?]*)*[@-~])`) ansiMatches := ansiRegex.FindAllStringIndex(content, -1) @@ -662,7 +662,7 @@ func renderDiffColumnLine( var bgStyle lipgloss.Style var lineNum string var highlightType LineType - var highlightColor lipgloss.AdaptiveColor + var highlightColor compat.AdaptiveColor if isLeftColumn { // Left column logic diff --git a/packages/tui/internal/components/qr/qr.go b/packages/tui/internal/components/qr/qr.go index df51a644..82d597a3 100644 --- a/packages/tui/internal/components/qr/qr.go +++ b/packages/tui/internal/components/qr/qr.go @@ -3,7 +3,7 @@ package qr import ( "strings" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode/internal/theme" "rsc.io/qr" ) diff --git a/packages/tui/internal/components/util/simple-list.go b/packages/tui/internal/components/util/simple-list.go index 0c0bb655..d6e27db1 100644 --- a/packages/tui/internal/components/util/simple-list.go +++ b/packages/tui/internal/components/util/simple-list.go @@ -1,9 +1,9 @@ package utilComponents import ( - "github.com/charmbracelet/bubbles/key" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/key" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode/internal/layout" "github.com/sst/opencode/internal/styles" "github.com/sst/opencode/internal/theme" @@ -14,7 +14,7 @@ type SimpleListItem interface { } type SimpleList[T SimpleListItem] interface { - tea.Model + layout.ModelWithView layout.Bindings SetMaxWidth(maxWidth int) GetSelectedItem() (item T, idx int) diff --git a/packages/tui/internal/image/images.go b/packages/tui/internal/image/images.go index f476b201..742eb30a 100644 --- a/packages/tui/internal/image/images.go +++ b/packages/tui/internal/image/images.go @@ -4,11 +4,12 @@ import ( "bytes" "fmt" "image" + "image/color" "image/png" "os" "strings" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/v2" "github.com/disintegration/imaging" "github.com/lucasb-eyer/go-colorful" _ "golang.org/x/image/webp" @@ -39,7 +40,7 @@ func ToString(width int, img image.Image) string { c1, _ := colorful.MakeColor(img.At(x, heightCounter)) color1 := lipgloss.Color(c1.Hex()) - var color2 lipgloss.Color + var color2 color.Color if heightCounter+1 < h { c2, _ := colorful.MakeColor(img.At(x, heightCounter+1)) color2 = lipgloss.Color(c2.Hex()) @@ -76,10 +77,10 @@ func ImagePreview(width int, filename string) (string, error) { func ImageToBytes(image image.Image) ([]byte, error) { buf := new(bytes.Buffer) - err := png.Encode(buf, image) - if err != nil { - return nil, err - } - - return buf.Bytes(), nil + err := png.Encode(buf, image) + if err != nil { + return nil, err + } + + return buf.Bytes(), nil } diff --git a/packages/tui/internal/layout/container.go b/packages/tui/internal/layout/container.go index 1c12ef6a..2bed6708 100644 --- a/packages/tui/internal/layout/container.go +++ b/packages/tui/internal/layout/container.go @@ -1,14 +1,19 @@ package layout import ( - "github.com/charmbracelet/bubbles/key" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/key" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode/internal/theme" ) -type Container interface { +type ModelWithView interface { tea.Model + tea.ViewModel +} + +type Container interface { + ModelWithView Sizeable Bindings Focus() @@ -21,7 +26,7 @@ type container struct { width int height int - content tea.Model + content ModelWithView paddingTop int paddingRight int @@ -46,7 +51,7 @@ func (c *container) Init() tea.Cmd { func (c *container) Update(msg tea.Msg) (tea.Model, tea.Cmd) { u, cmd := c.content.Update(msg) - c.content = u + c.content = u.(ModelWithView) return c, cmd } @@ -175,7 +180,7 @@ func (c *container) Blur() { type ContainerOption func(*container) -func NewContainer(content tea.Model, options ...ContainerOption) Container { +func NewContainer(content ModelWithView, options ...ContainerOption) Container { c := &container{ content: content, borderStyle: lipgloss.NormalBorder(), diff --git a/packages/tui/internal/layout/flex.go b/packages/tui/internal/layout/flex.go index a0882196..292cfcb0 100644 --- a/packages/tui/internal/layout/flex.go +++ b/packages/tui/internal/layout/flex.go @@ -1,10 +1,9 @@ package layout import ( - "github.com/charmbracelet/bubbles/key" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" - "github.com/sst/opencode/internal/theme" + "github.com/charmbracelet/bubbles/v2/key" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" ) type FlexDirection int @@ -26,7 +25,7 @@ func FlexPaneSizeFixed(size int) FlexPaneSize { } type FlexLayout interface { - tea.Model + ModelWithView Sizeable Bindings SetPanes(panes []Container) tea.Cmd @@ -75,8 +74,6 @@ func (f *flexLayout) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } func (f *flexLayout) View() string { - t := theme.CurrentTheme() - if len(f.panes) == 0 { return "" } @@ -94,7 +91,6 @@ func (f *flexLayout) View() string { paneWidth, pane.Alignment(), pane.View(), - lipgloss.WithWhitespaceBackground(t.Background()), ) views = append(views, view) } else { @@ -105,7 +101,6 @@ func (f *flexLayout) View() string { lipgloss.Center, pane.Alignment(), pane.View(), - lipgloss.WithWhitespaceBackground(t.Background()), ) views = append(views, view) } @@ -245,4 +240,3 @@ func WithPaneSizes(sizes ...FlexPaneSize) FlexLayoutOption { f.sizes = sizes } } - diff --git a/packages/tui/internal/layout/layout.go b/packages/tui/internal/layout/layout.go index 05f07f1a..9a7fefca 100644 --- a/packages/tui/internal/layout/layout.go +++ b/packages/tui/internal/layout/layout.go @@ -3,8 +3,8 @@ package layout import ( "reflect" - "github.com/charmbracelet/bubbles/key" - tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/bubbles/v2/key" + tea "github.com/charmbracelet/bubbletea/v2" ) var Current *LayoutInfo diff --git a/packages/tui/internal/layout/overlay.go b/packages/tui/internal/layout/overlay.go index bc349096..c2cd54b1 100644 --- a/packages/tui/internal/layout/overlay.go +++ b/packages/tui/internal/layout/overlay.go @@ -3,7 +3,7 @@ package layout import ( "strings" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/v2" chAnsi "github.com/charmbracelet/x/ansi" "github.com/muesli/ansi" "github.com/muesli/reflow/truncate" @@ -14,7 +14,7 @@ import ( ) // Most of this code is borrowed from -// https://github.com/charmbracelet/lipgloss/pull/102 +// https://github.com/charmbracelet/lipgloss/v2/pull/102 // as well as the lipgloss library, with some modification for what I needed. // Split a string into lines, additionally returning the size of the widest line. diff --git a/packages/tui/internal/page/chat.go b/packages/tui/internal/page/chat.go index 6c422767..906dc70a 100644 --- a/packages/tui/internal/page/chat.go +++ b/packages/tui/internal/page/chat.go @@ -4,9 +4,9 @@ import ( "context" "strings" - "github.com/charmbracelet/bubbles/key" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/key" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode/internal/app" "github.com/sst/opencode/internal/completions" "github.com/sst/opencode/internal/components/chat" @@ -187,7 +187,7 @@ func (p *chatPage) BindingKeys() []key.Binding { return bindings } -func NewChatPage(app *app.App) tea.Model { +func NewChatPage(app *app.App) layout.ModelWithView { cg := completions.NewFileAndFolderContextGroup() completionDialog := dialog.NewCompletionDialogCmp(cg) messagesContainer := layout.NewContainer( diff --git a/packages/tui/internal/styles/background.go b/packages/tui/internal/styles/background.go index 2fbb34ef..6db130c0 100644 --- a/packages/tui/internal/styles/background.go +++ b/packages/tui/internal/styles/background.go @@ -1,123 +1,13 @@ package styles -import ( - "fmt" - "regexp" - "strings" +type TerminalInfo struct { + BackgroundIsDark bool +} - "github.com/charmbracelet/lipgloss" -) +var Terminal *TerminalInfo -var ansiEscape = regexp.MustCompile("\x1b\\[[0-9;]*m") - -func getColorRGB(c lipgloss.TerminalColor) (uint8, uint8, uint8) { - r, g, b, a := c.RGBA() - - // Un-premultiply alpha if needed - if a > 0 && a < 0xffff { - r = (r * 0xffff) / a - g = (g * 0xffff) / a - b = (b * 0xffff) / a +func init() { + Terminal = &TerminalInfo{ + BackgroundIsDark: false, } - - // Convert from 16-bit to 8-bit color - return uint8(r >> 8), uint8(g >> 8), uint8(b >> 8) -} - -// ForceReplaceBackgroundWithLipgloss replaces any ANSI background color codes -// in `input` with a single 24‑bit background (48;2;R;G;B). -func ForceReplaceBackgroundWithLipgloss(input string, newBgColor lipgloss.TerminalColor) string { - // Precompute our new-bg sequence once - r, g, b := getColorRGB(newBgColor) - newBg := fmt.Sprintf("48;2;%d;%d;%d", r, g, b) - - return ansiEscape.ReplaceAllStringFunc(input, func(seq string) string { - const ( - escPrefixLen = 2 // "\x1b[" - escSuffixLen = 1 // "m" - ) - - raw := seq - start := escPrefixLen - end := len(raw) - escSuffixLen - - var sb strings.Builder - // reserve enough space: original content minus bg codes + our newBg - sb.Grow((end - start) + len(newBg) + 2) - - // scan from start..end, token by token - for i := start; i < end; { - // find the next ';' or end - j := i - for j < end && raw[j] != ';' { - j++ - } - token := raw[i:j] - - // fast‑path: skip "48;5;N" or "48;2;R;G;B" - if len(token) == 2 && token[0] == '4' && token[1] == '8' { - k := j + 1 - if k < end { - // find next token - l := k - for l < end && raw[l] != ';' { - l++ - } - next := raw[k:l] - if next == "5" { - // skip "48;5;N" - m := l + 1 - for m < end && raw[m] != ';' { - m++ - } - i = m + 1 - continue - } else if next == "2" { - // skip "48;2;R;G;B" - m := l + 1 - for count := 0; count < 3 && m < end; count++ { - for m < end && raw[m] != ';' { - m++ - } - m++ - } - i = m - continue - } - } - } - - // decide whether to keep this token - // manually parse ASCII digits to int - isNum := true - val := 0 - for p := i; p < j; p++ { - c := raw[p] - if c < '0' || c > '9' { - isNum = false - break - } - val = val*10 + int(c-'0') - } - keep := !isNum || - ((val < 40 || val > 47) && (val < 100 || val > 107) && val != 49) - - if keep { - if sb.Len() > 0 { - sb.WriteByte(';') - } - sb.WriteString(token) - } - // advance past this token (and the semicolon) - i = j + 1 - } - - // append our new background - if sb.Len() > 0 { - sb.WriteByte(';') - } - sb.WriteString(newBg) - - return "\x1b[" + sb.String() + "m" - }) } diff --git a/packages/tui/internal/styles/markdown.go b/packages/tui/internal/styles/markdown.go index bacd063c..a8681e19 100644 --- a/packages/tui/internal/styles/markdown.go +++ b/packages/tui/internal/styles/markdown.go @@ -3,7 +3,8 @@ package styles import ( "github.com/charmbracelet/glamour" "github.com/charmbracelet/glamour/ansi" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/v2/compat" + "github.com/lucasb-eyer/go-colorful" "github.com/sst/opencode/internal/theme" ) @@ -15,117 +16,120 @@ func stringPtr(s string) *string { return &s } func uintPtr(u uint) *uint { return &u } // returns a glamour TermRenderer configured with the current theme -func GetMarkdownRenderer(width int) *glamour.TermRenderer { +func GetMarkdownRenderer(width int, backgroundColor compat.AdaptiveColor) *glamour.TermRenderer { r, _ := glamour.NewTermRenderer( - glamour.WithStyles(generateMarkdownStyleConfig()), + glamour.WithStyles(generateMarkdownStyleConfig(backgroundColor)), glamour.WithWordWrap(width), + glamour.WithChromaFormatter("terminal16m"), ) return r } // creates an ansi.StyleConfig for markdown rendering // using adaptive colors from the provided theme. -func generateMarkdownStyleConfig() ansi.StyleConfig { +func generateMarkdownStyleConfig(backgroundColor compat.AdaptiveColor) ansi.StyleConfig { t := theme.CurrentTheme() + background := stringPtr(AdaptiveColorToString(backgroundColor)) return ansi.StyleConfig{ Document: ansi.StyleBlock{ StylePrimitive: ansi.StylePrimitive{ - BlockPrefix: "", - BlockSuffix: "", - Color: stringPtr(adaptiveColorToString(t.MarkdownText())), + BlockPrefix: "", + BlockSuffix: "", + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.MarkdownText())), }, }, BlockQuote: ansi.StyleBlock{ StylePrimitive: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.MarkdownBlockQuote())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownBlockQuote())), Italic: boolPtr(true), Prefix: "┃ ", }, Indent: uintPtr(1), - IndentToken: stringPtr(BaseStyle().Render(" ")), + IndentToken: stringPtr(" "), }, List: ansi.StyleList{ LevelIndent: defaultMargin, StyleBlock: ansi.StyleBlock{ - IndentToken: stringPtr(BaseStyle().Render(" ")), + IndentToken: stringPtr(" "), StylePrimitive: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.MarkdownText())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownText())), }, }, }, Heading: ansi.StyleBlock{ StylePrimitive: ansi.StylePrimitive{ BlockSuffix: "\n", - Color: stringPtr(adaptiveColorToString(t.MarkdownHeading())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownHeading())), Bold: boolPtr(true), }, }, H1: ansi.StyleBlock{ StylePrimitive: ansi.StylePrimitive{ Prefix: "# ", - Color: stringPtr(adaptiveColorToString(t.MarkdownHeading())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownHeading())), Bold: boolPtr(true), }, }, H2: ansi.StyleBlock{ StylePrimitive: ansi.StylePrimitive{ Prefix: "## ", - Color: stringPtr(adaptiveColorToString(t.MarkdownHeading())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownHeading())), Bold: boolPtr(true), }, }, H3: ansi.StyleBlock{ StylePrimitive: ansi.StylePrimitive{ Prefix: "### ", - Color: stringPtr(adaptiveColorToString(t.MarkdownHeading())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownHeading())), Bold: boolPtr(true), }, }, H4: ansi.StyleBlock{ StylePrimitive: ansi.StylePrimitive{ Prefix: "#### ", - Color: stringPtr(adaptiveColorToString(t.MarkdownHeading())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownHeading())), Bold: boolPtr(true), }, }, H5: ansi.StyleBlock{ StylePrimitive: ansi.StylePrimitive{ Prefix: "##### ", - Color: stringPtr(adaptiveColorToString(t.MarkdownHeading())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownHeading())), Bold: boolPtr(true), }, }, H6: ansi.StyleBlock{ StylePrimitive: ansi.StylePrimitive{ Prefix: "###### ", - Color: stringPtr(adaptiveColorToString(t.MarkdownHeading())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownHeading())), Bold: boolPtr(true), }, }, Strikethrough: ansi.StylePrimitive{ CrossedOut: boolPtr(true), - Color: stringPtr(adaptiveColorToString(t.TextMuted())), + Color: stringPtr(AdaptiveColorToString(t.TextMuted())), }, Emph: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.MarkdownEmph())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownEmph())), Italic: boolPtr(true), }, Strong: ansi.StylePrimitive{ Bold: boolPtr(true), - Color: stringPtr(adaptiveColorToString(t.MarkdownStrong())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownStrong())), }, HorizontalRule: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.MarkdownHorizontalRule())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownHorizontalRule())), Format: "\n─────────────────────────────────────────\n", }, Item: ansi.StylePrimitive{ BlockPrefix: "• ", - Color: stringPtr(adaptiveColorToString(t.MarkdownListItem())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownListItem())), }, Enumeration: ansi.StylePrimitive{ BlockPrefix: ". ", - Color: stringPtr(adaptiveColorToString(t.MarkdownListEnumeration())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownListEnumeration())), }, Task: ansi.StyleTask{ StylePrimitive: ansi.StylePrimitive{}, @@ -133,116 +137,147 @@ func generateMarkdownStyleConfig() ansi.StyleConfig { Unticked: "[ ] ", }, Link: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.MarkdownLink())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownLink())), Underline: boolPtr(true), }, LinkText: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.MarkdownLinkText())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownLinkText())), Bold: boolPtr(true), }, Image: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.MarkdownImage())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownImage())), Underline: boolPtr(true), Format: "🖼 {{.text}}", }, ImageText: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.MarkdownImageText())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownImageText())), Format: "{{.text}}", }, Code: ansi.StyleBlock{ StylePrimitive: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.MarkdownCode())), - Prefix: "", - Suffix: "", + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.MarkdownCode())), + Prefix: "", + Suffix: "", }, }, CodeBlock: ansi.StyleCodeBlock{ StyleBlock: ansi.StyleBlock{ StylePrimitive: ansi.StylePrimitive{ - Prefix: " ", - Color: stringPtr(adaptiveColorToString(t.MarkdownCodeBlock())), + BackgroundColor: background, + Prefix: " ", + Color: stringPtr(AdaptiveColorToString(t.MarkdownCodeBlock())), }, }, Chroma: &ansi.Chroma{ + Background: ansi.StylePrimitive{ + BackgroundColor: background, + }, Text: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.MarkdownText())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.MarkdownText())), }, Error: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.Error())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.Error())), }, Comment: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxComment())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxComment())), }, CommentPreproc: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxKeyword())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxKeyword())), }, Keyword: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxKeyword())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxKeyword())), }, KeywordReserved: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxKeyword())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxKeyword())), }, KeywordNamespace: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxKeyword())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxKeyword())), }, KeywordType: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxType())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxType())), }, Operator: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxOperator())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxOperator())), }, Punctuation: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxPunctuation())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxPunctuation())), }, Name: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxVariable())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxVariable())), }, NameBuiltin: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxVariable())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxVariable())), }, NameTag: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxKeyword())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxKeyword())), }, NameAttribute: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxFunction())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxFunction())), }, NameClass: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxType())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxType())), }, NameConstant: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxVariable())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxVariable())), }, NameDecorator: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxFunction())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxFunction())), }, NameFunction: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxFunction())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxFunction())), }, LiteralNumber: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxNumber())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxNumber())), }, LiteralString: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxString())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxString())), }, LiteralStringEscape: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.SyntaxKeyword())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.SyntaxKeyword())), }, GenericDeleted: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.DiffRemoved())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.DiffRemoved())), }, GenericEmph: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.MarkdownEmph())), - Italic: boolPtr(true), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.MarkdownEmph())), + Italic: boolPtr(true), }, GenericInserted: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.DiffAdded())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.DiffAdded())), }, GenericStrong: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.MarkdownStrong())), - Bold: boolPtr(true), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.MarkdownStrong())), + Bold: boolPtr(true), }, GenericSubheading: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.MarkdownHeading())), + BackgroundColor: background, + Color: stringPtr(AdaptiveColorToString(t.MarkdownHeading())), }, }, }, @@ -259,24 +294,26 @@ func generateMarkdownStyleConfig() ansi.StyleConfig { }, DefinitionDescription: ansi.StylePrimitive{ BlockPrefix: "\n ❯ ", - Color: stringPtr(adaptiveColorToString(t.MarkdownLinkText())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownLinkText())), }, Text: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.MarkdownText())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownText())), }, Paragraph: ansi.StyleBlock{ StylePrimitive: ansi.StylePrimitive{ - Color: stringPtr(adaptiveColorToString(t.MarkdownText())), + Color: stringPtr(AdaptiveColorToString(t.MarkdownText())), }, }, } } -// adaptiveColorToString converts a lipgloss.AdaptiveColor to the appropriate +// AdaptiveColorToString converts a compat.AdaptiveColor to the appropriate // hex color string based on the current terminal background -func adaptiveColorToString(color lipgloss.AdaptiveColor) string { - if lipgloss.HasDarkBackground() { - return color.Dark +func AdaptiveColorToString(color compat.AdaptiveColor) string { + if Terminal.BackgroundIsDark { + c1, _ := colorful.MakeColor(color.Dark) + return c1.Hex() } - return color.Light + c1, _ := colorful.MakeColor(color.Light) + return c1.Hex() } diff --git a/packages/tui/internal/styles/styles.go b/packages/tui/internal/styles/styles.go index 3916ea12..4b29091c 100644 --- a/packages/tui/internal/styles/styles.go +++ b/packages/tui/internal/styles/styles.go @@ -1,7 +1,8 @@ package styles import ( - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/v2" + "github.com/charmbracelet/lipgloss/v2/compat" "github.com/sst/opencode/internal/theme" ) @@ -83,76 +84,76 @@ func DimBorder() lipgloss.Style { } // PrimaryColor returns the primary color from the current theme -func PrimaryColor() lipgloss.AdaptiveColor { +func PrimaryColor() compat.AdaptiveColor { return theme.CurrentTheme().Primary() } // SecondaryColor returns the secondary color from the current theme -func SecondaryColor() lipgloss.AdaptiveColor { +func SecondaryColor() compat.AdaptiveColor { return theme.CurrentTheme().Secondary() } // AccentColor returns the accent color from the current theme -func AccentColor() lipgloss.AdaptiveColor { +func AccentColor() compat.AdaptiveColor { return theme.CurrentTheme().Accent() } // ErrorColor returns the error color from the current theme -func ErrorColor() lipgloss.AdaptiveColor { +func ErrorColor() compat.AdaptiveColor { return theme.CurrentTheme().Error() } // WarningColor returns the warning color from the current theme -func WarningColor() lipgloss.AdaptiveColor { +func WarningColor() compat.AdaptiveColor { return theme.CurrentTheme().Warning() } // SuccessColor returns the success color from the current theme -func SuccessColor() lipgloss.AdaptiveColor { +func SuccessColor() compat.AdaptiveColor { return theme.CurrentTheme().Success() } // InfoColor returns the info color from the current theme -func InfoColor() lipgloss.AdaptiveColor { +func InfoColor() compat.AdaptiveColor { return theme.CurrentTheme().Info() } // TextColor returns the text color from the current theme -func TextColor() lipgloss.AdaptiveColor { +func TextColor() compat.AdaptiveColor { return theme.CurrentTheme().Text() } // TextMutedColor returns the muted text color from the current theme -func TextMutedColor() lipgloss.AdaptiveColor { +func TextMutedColor() compat.AdaptiveColor { return theme.CurrentTheme().TextMuted() } // BackgroundColor returns the background color from the current theme -func BackgroundColor() lipgloss.AdaptiveColor { +func BackgroundColor() compat.AdaptiveColor { return theme.CurrentTheme().Background() } // BackgroundSubtleColor returns the subtle background color from the current theme -func BackgroundSubtleColor() lipgloss.AdaptiveColor { +func BackgroundSubtleColor() compat.AdaptiveColor { return theme.CurrentTheme().BackgroundSubtle() } // BackgroundElementColor returns the darker background color from the current theme -func BackgroundElementColor() lipgloss.AdaptiveColor { +func BackgroundElementColor() compat.AdaptiveColor { return theme.CurrentTheme().BackgroundElement() } // BorderColor returns the border color from the current theme -func BorderColor() lipgloss.AdaptiveColor { +func BorderColor() compat.AdaptiveColor { return theme.CurrentTheme().Border() } // BorderActiveColor returns the active border color from the current theme -func BorderActiveColor() lipgloss.AdaptiveColor { +func BorderActiveColor() compat.AdaptiveColor { return theme.CurrentTheme().BorderActive() } // BorderSubtleColor returns the subtle border color from the current theme -func BorderSubtleColor() lipgloss.AdaptiveColor { +func BorderSubtleColor() compat.AdaptiveColor { return theme.CurrentTheme().BorderSubtle() } diff --git a/packages/tui/internal/theme/ayu.go b/packages/tui/internal/theme/ayu.go deleted file mode 100644 index 947e41e5..00000000 --- a/packages/tui/internal/theme/ayu.go +++ /dev/null @@ -1,276 +0,0 @@ -package theme - -import ( - "github.com/charmbracelet/lipgloss" -) - -// AyuDarkTheme implements the Theme interface with Ayu Dark colors. -type AyuDarkTheme struct { - BaseTheme -} - -// AyuLightTheme implements the Theme interface with Ayu Light colors. -type AyuLightTheme struct { - BaseTheme -} - -// AyuMirageTheme implements the Theme interface with Ayu Mirage colors. -type AyuMirageTheme struct { - BaseTheme -} - -// NewAyuDarkTheme creates a new instance of the Ayu Dark theme. -func NewAyuDarkTheme() *AyuDarkTheme { - // Ayu Dark color palette - darkBackground := "#0f1419" - darkCurrentLine := "#191f26" - darkSelection := "#253340" - darkForeground := "#b3b1ad" - darkComment := "#5c6773" - darkBlue := "#53bdfa" - darkCyan := "#90e1c6" - darkGreen := "#91b362" - darkOrange := "#f9af4f" - darkPurple := "#fae994" - darkRed := "#ea6c73" - darkBorder := "#253340" - - // Light mode approximation for terminal compatibility - lightBackground := "#fafafa" - lightCurrentLine := "#f0f0f0" - lightSelection := "#d1d1d1" - lightForeground := "#5c6773" - lightComment := "#828c99" - lightBlue := "#3199e1" - lightCyan := "#46ba94" - lightGreen := "#7c9f32" - lightOrange := "#f29718" - lightPurple := "#9e75c7" - lightRed := "#f07171" - lightBorder := "#d1d1d1" - - theme := &AyuDarkTheme{} - - // Base colors - theme.PrimaryColor = lipgloss.AdaptiveColor{ - Dark: darkBlue, - Light: lightBlue, - } - theme.SecondaryColor = lipgloss.AdaptiveColor{ - Dark: darkCyan, - Light: lightCyan, - } - 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, - } - - // Background colors - theme.BackgroundColor = lipgloss.AdaptiveColor{ - Dark: darkBackground, - Light: lightBackground, - } - theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{ - Dark: darkCurrentLine, - Light: lightCurrentLine, - } - theme.BackgroundElementColor = lipgloss.AdaptiveColor{ - Dark: "#0b0e14", // Darker than background - Light: "#ffffff", // Lighter than background - } - - // Border colors - theme.BorderColor = lipgloss.AdaptiveColor{ - Dark: darkBorder, - Light: lightBorder, - } - theme.BorderActiveColor = lipgloss.AdaptiveColor{ - Dark: darkBlue, - Light: lightBlue, - } - theme.BorderSubtleColor = 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: "#91b362", - Light: "#a5d6a7", - } - theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{ - Dark: "#ea6c73", - Light: "#ef9a9a", - } - theme.DiffAddedBgColor = lipgloss.AdaptiveColor{ - Dark: "#1f2c1f", - Light: "#e8f5e9", - } - theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{ - Dark: "#2c1f1f", - Light: "#ffebee", - } - theme.DiffContextBgColor = lipgloss.AdaptiveColor{ - Dark: darkBackground, - Light: lightBackground, - } - theme.DiffLineNumberColor = lipgloss.AdaptiveColor{ - Dark: darkComment, - Light: lightComment, - } - theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{ - Dark: "#1a261a", - Light: "#c8e6c9", - } - theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{ - Dark: "#261a1a", - Light: "#ffcdd2", - } - - // Markdown colors - theme.MarkdownTextColor = lipgloss.AdaptiveColor{ - Dark: darkForeground, - Light: lightForeground, - } - theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{ - Dark: darkBlue, - Light: lightBlue, - } - 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: darkComment, - Light: lightComment, - } - theme.MarkdownEmphColor = lipgloss.AdaptiveColor{ - Dark: darkPurple, - Light: lightPurple, - } - 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: darkForeground, - Light: lightForeground, - } - theme.SyntaxStringColor = lipgloss.AdaptiveColor{ - Dark: darkGreen, - Light: lightGreen, - } - theme.SyntaxNumberColor = lipgloss.AdaptiveColor{ - Dark: darkPurple, - Light: lightPurple, - } - theme.SyntaxTypeColor = lipgloss.AdaptiveColor{ - Dark: darkCyan, - Light: lightCyan, - } - theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{ - Dark: darkOrange, - Light: lightOrange, - } - theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{ - Dark: darkForeground, - Light: lightForeground, - } - - return theme -} - -func init() { - // Register all three Ayu theme variants with the theme manager - RegisterTheme("ayu", NewAyuDarkTheme()) -} diff --git a/packages/tui/internal/theme/catppuccin.go b/packages/tui/internal/theme/catppuccin.go deleted file mode 100644 index 976eb7fb..00000000 --- a/packages/tui/internal/theme/catppuccin.go +++ /dev/null @@ -1,244 +0,0 @@ -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, - } - - // Background colors - theme.BackgroundColor = lipgloss.AdaptiveColor{ - Dark: "#212121", // From existing styles - Light: "#EEEEEE", // Light equivalent - } - theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{ - Dark: "#2c2c2c", // From existing styles - Light: "#E0E0E0", // Light equivalent - } - theme.BackgroundElementColor = lipgloss.AdaptiveColor{ - Dark: "#181818", // From existing styles - Light: "#F5F5F5", // Light equivalent - } - - // Border colors - theme.BorderColor = lipgloss.AdaptiveColor{ - Dark: "#4b4c5c", // From existing styles - Light: "#BDBDBD", // Light equivalent - } - theme.BorderActiveColor = lipgloss.AdaptiveColor{ - Dark: mocha.Blue().Hex, - Light: latte.Blue().Hex, - } - theme.BorderSubtleColor = 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/packages/tui/internal/theme/dracula.go b/packages/tui/internal/theme/dracula.go deleted file mode 100644 index 7f14d629..00000000 --- a/packages/tui/internal/theme/dracula.go +++ /dev/null @@ -1,270 +0,0 @@ -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, - } - - // Background colors - theme.BackgroundElementColor = lipgloss.AdaptiveColor{ - Dark: darkBackground, - Light: lightBackground, - } - theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{ - Dark: darkCurrentLine, - Light: lightCurrentLine, - } - theme.BackgroundColor = lipgloss.AdaptiveColor{ - Dark: "#21222c", // Slightly darker than background - Light: "#ffffff", // Slightly lighter than background - } - - // Border colors - theme.BorderColor = lipgloss.AdaptiveColor{ - Dark: darkBorder, - Light: lightBorder, - } - theme.BorderActiveColor = lipgloss.AdaptiveColor{ - Dark: darkPurple, - Light: lightPurple, - } - theme.BorderSubtleColor = 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: darkCurrentLine, - Light: lightCurrentLine, - } - 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/packages/tui/internal/theme/flexoki.go b/packages/tui/internal/theme/flexoki.go deleted file mode 100644 index ad544386..00000000 --- a/packages/tui/internal/theme/flexoki.go +++ /dev/null @@ -1,278 +0,0 @@ -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, - } - - // Background colors - theme.BackgroundColor = lipgloss.AdaptiveColor{ - Dark: flexokiBlack, - Light: flexokiPaper, - } - theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{ - Dark: flexokiBase950, - Light: flexokiBase50, - } - theme.BackgroundElementColor = lipgloss.AdaptiveColor{ - Dark: flexokiBase900, - Light: flexokiBase100, - } - - // Border colors - theme.BorderColor = lipgloss.AdaptiveColor{ - Dark: flexokiBase900, - Light: flexokiBase100, - } - theme.BorderActiveColor = lipgloss.AdaptiveColor{ - Dark: flexokiBlue400, - Light: flexokiBlue600, - } - theme.BorderSubtleColor = 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/packages/tui/internal/theme/gruvbox.go b/packages/tui/internal/theme/gruvbox.go deleted file mode 100644 index da9aab50..00000000 --- a/packages/tui/internal/theme/gruvbox.go +++ /dev/null @@ -1,298 +0,0 @@ -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, - } - - // Background colors - theme.BackgroundColor = lipgloss.AdaptiveColor{ - Dark: gruvboxDarkBg0, - Light: gruvboxLightBg0, - } - theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{ - Dark: gruvboxDarkBg1, - Light: gruvboxLightBg1, - } - theme.BackgroundElementColor = lipgloss.AdaptiveColor{ - Dark: gruvboxDarkBg0Soft, - Light: gruvboxLightBg0Soft, - } - - // Border colors - theme.BorderColor = lipgloss.AdaptiveColor{ - Dark: gruvboxDarkBg2, - Light: gruvboxLightBg2, - } - theme.BorderActiveColor = lipgloss.AdaptiveColor{ - Dark: gruvboxDarkBlueBright, - Light: gruvboxLightBlueBright, - } - theme.BorderSubtleColor = 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/packages/tui/internal/theme/manager.go b/packages/tui/internal/theme/manager.go index 020e3e19..3e351f7f 100644 --- a/packages/tui/internal/theme/manager.go +++ b/packages/tui/internal/theme/manager.go @@ -6,8 +6,7 @@ import ( "slices" "strings" "sync" - - "github.com/alecthomas/chroma/v2/styles" + // "github.com/alecthomas/chroma/v2/styles" ) // Manager handles theme registration, selection, and retrieval. @@ -46,7 +45,7 @@ func RegisterTheme(name string, theme Theme) { func SetTheme(name string) error { globalManager.mu.Lock() defer globalManager.mu.Unlock() - delete(styles.Registry, "charm") + // delete(styles.Registry, "charm") // Handle custom theme // if name == "custom" { diff --git a/packages/tui/internal/theme/monokai.go b/packages/tui/internal/theme/monokai.go deleted file mode 100644 index 71234d02..00000000 --- a/packages/tui/internal/theme/monokai.go +++ /dev/null @@ -1,269 +0,0 @@ -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, - } - - // Background colors - theme.BackgroundColor = lipgloss.AdaptiveColor{ - Dark: darkBackground, - Light: lightBackground, - } - theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{ - Dark: darkCurrentLine, - Light: lightCurrentLine, - } - theme.BackgroundElementColor = lipgloss.AdaptiveColor{ - Dark: "#221f22", // Slightly darker than background - Light: "#ffffff", // Slightly lighter than background - } - - // Border colors - theme.BorderColor = lipgloss.AdaptiveColor{ - Dark: darkBorder, - Light: lightBorder, - } - theme.BorderActiveColor = lipgloss.AdaptiveColor{ - Dark: darkCyan, - Light: lightCyan, - } - theme.BorderSubtleColor = 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/packages/tui/internal/theme/onedark.go b/packages/tui/internal/theme/onedark.go deleted file mode 100644 index 21953c10..00000000 --- a/packages/tui/internal/theme/onedark.go +++ /dev/null @@ -1,270 +0,0 @@ -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, - } - - // Background colors - theme.BackgroundColor = lipgloss.AdaptiveColor{ - Dark: darkBackground, - Light: lightBackground, - } - theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{ - Dark: darkCurrentLine, - Light: lightCurrentLine, - } - theme.BackgroundElementColor = lipgloss.AdaptiveColor{ - Dark: "#21252b", // Slightly darker than background - Light: "#ffffff", // Slightly lighter than background - } - - // Border colors - theme.BorderColor = lipgloss.AdaptiveColor{ - Dark: darkBorder, - Light: lightBorder, - } - theme.BorderActiveColor = lipgloss.AdaptiveColor{ - Dark: darkBlue, - Light: lightBlue, - } - theme.BorderSubtleColor = 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/packages/tui/internal/theme/opencode.go b/packages/tui/internal/theme/opencode.go index 4de88ae4..8f188be3 100644 --- a/packages/tui/internal/theme/opencode.go +++ b/packages/tui/internal/theme/opencode.go @@ -1,7 +1,8 @@ package theme import ( - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/v2" + "github.com/charmbracelet/lipgloss/v2/compat" ) // OpenCodeTheme implements the Theme interface with OpenCode brand colors. @@ -72,219 +73,219 @@ func NewOpenCodeTheme() *OpenCodeTheme { theme := &OpenCodeTheme{} // Base colors - theme.PrimaryColor = lipgloss.AdaptiveColor{ - Dark: darkPrimary, - Light: lightPrimary, + theme.PrimaryColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkPrimary), + Light: lipgloss.Color(lightPrimary), } - theme.SecondaryColor = lipgloss.AdaptiveColor{ - Dark: darkSecondary, - Light: lightSecondary, + theme.SecondaryColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkSecondary), + Light: lipgloss.Color(lightSecondary), } - theme.AccentColor = lipgloss.AdaptiveColor{ - Dark: darkAccent, - Light: lightAccent, + theme.AccentColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkAccent), + Light: lipgloss.Color(lightAccent), } // Status colors - theme.ErrorColor = lipgloss.AdaptiveColor{ - Dark: darkRed, - Light: lightRed, + theme.ErrorColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkRed), + Light: lipgloss.Color(lightRed), } - theme.WarningColor = lipgloss.AdaptiveColor{ - Dark: darkOrange, - Light: lightOrange, + theme.WarningColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkOrange), + Light: lipgloss.Color(lightOrange), } - theme.SuccessColor = lipgloss.AdaptiveColor{ - Dark: darkGreen, - Light: lightGreen, + theme.SuccessColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkGreen), + Light: lipgloss.Color(lightGreen), } - theme.InfoColor = lipgloss.AdaptiveColor{ - Dark: darkCyan, - Light: lightCyan, + theme.InfoColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkCyan), + Light: lipgloss.Color(lightCyan), } // Text colors - theme.TextColor = lipgloss.AdaptiveColor{ - Dark: darkStep12, - Light: lightStep12, + theme.TextColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep12), + Light: lipgloss.Color(lightStep12), } - theme.TextMutedColor = lipgloss.AdaptiveColor{ - Dark: darkStep11, - Light: lightStep11, + theme.TextMutedColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep11), + Light: lipgloss.Color(lightStep11), } // Background colors - theme.BackgroundColor = lipgloss.AdaptiveColor{ - Dark: darkStep1, - Light: lightStep1, + theme.BackgroundColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep1), + Light: lipgloss.Color(lightStep1), } - theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{ - Dark: darkStep2, - Light: lightStep2, + theme.BackgroundSubtleColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep2), + Light: lipgloss.Color(lightStep2), } - theme.BackgroundElementColor = lipgloss.AdaptiveColor{ - Dark: darkStep3, - Light: lightStep3, + theme.BackgroundElementColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep3), + Light: lipgloss.Color(lightStep3), } // Border colors - theme.BorderColor = lipgloss.AdaptiveColor{ - Dark: darkStep7, - Light: lightStep7, + theme.BorderColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep7), + Light: lipgloss.Color(lightStep7), } - theme.BorderActiveColor = lipgloss.AdaptiveColor{ - Dark: darkStep8, - Light: lightStep8, + theme.BorderActiveColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep8), + Light: lipgloss.Color(lightStep8), } - theme.BorderSubtleColor = lipgloss.AdaptiveColor{ - Dark: darkStep6, - Light: lightStep6, + theme.BorderSubtleColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep6), + Light: lipgloss.Color(lightStep6), } // Diff view colors - theme.DiffAddedColor = lipgloss.AdaptiveColor{ - Dark: "#478247", - Light: "#2E7D32", + theme.DiffAddedColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#478247"), + Light: lipgloss.Color("#2E7D32"), } - theme.DiffRemovedColor = lipgloss.AdaptiveColor{ - Dark: "#7C4444", - Light: "#C62828", + theme.DiffRemovedColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#7C4444"), + Light: lipgloss.Color("#C62828"), } - theme.DiffContextColor = lipgloss.AdaptiveColor{ - Dark: "#a0a0a0", - Light: "#757575", + theme.DiffContextColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#a0a0a0"), + Light: lipgloss.Color("#757575"), } - theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{ - Dark: "#a0a0a0", - Light: "#757575", + theme.DiffHunkHeaderColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#a0a0a0"), + Light: lipgloss.Color("#757575"), } - theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{ - Dark: "#DAFADA", - Light: "#A5D6A7", + theme.DiffHighlightAddedColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#DAFADA"), + Light: lipgloss.Color("#A5D6A7"), } - theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{ - Dark: "#FADADD", - Light: "#EF9A9A", + theme.DiffHighlightRemovedColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#FADADD"), + Light: lipgloss.Color("#EF9A9A"), } - theme.DiffAddedBgColor = lipgloss.AdaptiveColor{ - Dark: "#303A30", - Light: "#E8F5E9", + theme.DiffAddedBgColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#303A30"), + Light: lipgloss.Color("#E8F5E9"), } - theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{ - Dark: "#3A3030", - Light: "#FFEBEE", + theme.DiffRemovedBgColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#3A3030"), + Light: lipgloss.Color("#FFEBEE"), } - theme.DiffContextBgColor = lipgloss.AdaptiveColor{ - Dark: darkStep2, - Light: lightStep2, + theme.DiffContextBgColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep2), + Light: lipgloss.Color(lightStep2), } - theme.DiffLineNumberColor = lipgloss.AdaptiveColor{ - Dark: darkStep3, - Light: lightStep3, + theme.DiffLineNumberColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep3), + Light: lipgloss.Color(lightStep3), } - theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{ - Dark: "#293229", - Light: "#C8E6C9", + theme.DiffAddedLineNumberBgColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#293229"), + Light: lipgloss.Color("#C8E6C9"), } - theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{ - Dark: "#332929", - Light: "#FFCDD2", + theme.DiffRemovedLineNumberBgColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#332929"), + Light: lipgloss.Color("#FFCDD2"), } // Markdown colors - theme.MarkdownTextColor = lipgloss.AdaptiveColor{ - Dark: darkStep12, - Light: lightStep12, + theme.MarkdownTextColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep12), + Light: lipgloss.Color(lightStep12), } - theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{ - Dark: darkSecondary, - Light: lightSecondary, + theme.MarkdownHeadingColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkSecondary), + Light: lipgloss.Color(lightSecondary), } - theme.MarkdownLinkColor = lipgloss.AdaptiveColor{ - Dark: darkPrimary, - Light: lightPrimary, + theme.MarkdownLinkColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkPrimary), + Light: lipgloss.Color(lightPrimary), } - theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{ - Dark: darkCyan, - Light: lightCyan, + theme.MarkdownLinkTextColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkCyan), + Light: lipgloss.Color(lightCyan), } - theme.MarkdownCodeColor = lipgloss.AdaptiveColor{ - Dark: darkGreen, - Light: lightGreen, + theme.MarkdownCodeColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkGreen), + Light: lipgloss.Color(lightGreen), } - theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{ - Dark: darkYellow, - Light: lightYellow, + theme.MarkdownBlockQuoteColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkYellow), + Light: lipgloss.Color(lightYellow), } - theme.MarkdownEmphColor = lipgloss.AdaptiveColor{ - Dark: darkYellow, - Light: lightYellow, + theme.MarkdownEmphColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkYellow), + Light: lipgloss.Color(lightYellow), } - theme.MarkdownStrongColor = lipgloss.AdaptiveColor{ - Dark: darkAccent, - Light: lightAccent, + theme.MarkdownStrongColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkAccent), + Light: lipgloss.Color(lightAccent), } - theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{ - Dark: darkStep11, - Light: lightStep11, + theme.MarkdownHorizontalRuleColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep11), + Light: lipgloss.Color(lightStep11), } - theme.MarkdownListItemColor = lipgloss.AdaptiveColor{ - Dark: darkPrimary, - Light: lightPrimary, + theme.MarkdownListItemColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkPrimary), + Light: lipgloss.Color(lightPrimary), } - theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{ - Dark: darkCyan, - Light: lightCyan, + theme.MarkdownListEnumerationColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkCyan), + Light: lipgloss.Color(lightCyan), } - theme.MarkdownImageColor = lipgloss.AdaptiveColor{ - Dark: darkPrimary, - Light: lightPrimary, + theme.MarkdownImageColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkPrimary), + Light: lipgloss.Color(lightPrimary), } - theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{ - Dark: darkCyan, - Light: lightCyan, + theme.MarkdownImageTextColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkCyan), + Light: lipgloss.Color(lightCyan), } - theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{ - Dark: darkStep12, - Light: lightStep12, + theme.MarkdownCodeBlockColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep12), + Light: lipgloss.Color(lightStep12), } // Syntax highlighting colors - theme.SyntaxCommentColor = lipgloss.AdaptiveColor{ - Dark: darkStep11, - Light: lightStep11, + theme.SyntaxCommentColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep11), + Light: lipgloss.Color(lightStep11), } - theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{ - Dark: darkSecondary, - Light: lightSecondary, + theme.SyntaxKeywordColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkPrimary), + Light: lipgloss.Color(lightPrimary), } - theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{ - Dark: darkPrimary, - Light: lightPrimary, + theme.SyntaxFunctionColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkPrimary), + Light: lipgloss.Color(lightPrimary), } - theme.SyntaxVariableColor = lipgloss.AdaptiveColor{ - Dark: darkRed, - Light: lightRed, + theme.SyntaxVariableColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkRed), + Light: lipgloss.Color(lightRed), } - theme.SyntaxStringColor = lipgloss.AdaptiveColor{ - Dark: darkGreen, - Light: lightGreen, + theme.SyntaxStringColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkGreen), + Light: lipgloss.Color(lightGreen), } - theme.SyntaxNumberColor = lipgloss.AdaptiveColor{ - Dark: darkAccent, - Light: lightAccent, + theme.SyntaxNumberColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkAccent), + Light: lipgloss.Color(lightAccent), } - theme.SyntaxTypeColor = lipgloss.AdaptiveColor{ - Dark: darkYellow, - Light: lightYellow, + theme.SyntaxTypeColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkYellow), + Light: lipgloss.Color(lightYellow), } - theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{ - Dark: darkCyan, - Light: lightCyan, + theme.SyntaxOperatorColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkCyan), + Light: lipgloss.Color(lightCyan), } - theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{ - Dark: darkStep12, - Light: lightStep12, + theme.SyntaxPunctuationColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep12), + Light: lipgloss.Color(lightStep12), } return theme diff --git a/packages/tui/internal/theme/theme.go b/packages/tui/internal/theme/theme.go index 8b2d926b..2769a172 100644 --- a/packages/tui/internal/theme/theme.go +++ b/packages/tui/internal/theme/theme.go @@ -4,231 +4,232 @@ import ( "fmt" "regexp" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/v2" + "github.com/charmbracelet/lipgloss/v2/compat" ) // Theme defines the interface for all UI themes in the application. -// All colors must be defined as lipgloss.AdaptiveColor to support +// All colors must be defined as compat.AdaptiveColor to support // both light and dark terminal backgrounds. type Theme interface { // Background colors - Background() lipgloss.AdaptiveColor // Radix 1 - BackgroundSubtle() lipgloss.AdaptiveColor // Radix 2 - BackgroundElement() lipgloss.AdaptiveColor // Radix 3 + Background() compat.AdaptiveColor // Radix 1 + BackgroundSubtle() compat.AdaptiveColor // Radix 2 + BackgroundElement() compat.AdaptiveColor // Radix 3 // Border colors - BorderSubtle() lipgloss.AdaptiveColor // Radix 6 - Border() lipgloss.AdaptiveColor // Radix 7 - BorderActive() lipgloss.AdaptiveColor // Radix 8 + BorderSubtle() compat.AdaptiveColor // Radix 6 + Border() compat.AdaptiveColor // Radix 7 + BorderActive() compat.AdaptiveColor // Radix 8 // Brand colors - Primary() lipgloss.AdaptiveColor // Radix 9 - Secondary() lipgloss.AdaptiveColor - Accent() lipgloss.AdaptiveColor + Primary() compat.AdaptiveColor // Radix 9 + Secondary() compat.AdaptiveColor + Accent() compat.AdaptiveColor // Text colors - TextMuted() lipgloss.AdaptiveColor // Radix 11 - Text() lipgloss.AdaptiveColor // Radix 12 + TextMuted() compat.AdaptiveColor // Radix 11 + Text() compat.AdaptiveColor // Radix 12 // Status colors - Error() lipgloss.AdaptiveColor - Warning() lipgloss.AdaptiveColor - Success() lipgloss.AdaptiveColor - Info() lipgloss.AdaptiveColor + Error() compat.AdaptiveColor + Warning() compat.AdaptiveColor + Success() compat.AdaptiveColor + Info() compat.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 + DiffAdded() compat.AdaptiveColor + DiffRemoved() compat.AdaptiveColor + DiffContext() compat.AdaptiveColor + DiffHunkHeader() compat.AdaptiveColor + DiffHighlightAdded() compat.AdaptiveColor + DiffHighlightRemoved() compat.AdaptiveColor + DiffAddedBg() compat.AdaptiveColor + DiffRemovedBg() compat.AdaptiveColor + DiffContextBg() compat.AdaptiveColor + DiffLineNumber() compat.AdaptiveColor + DiffAddedLineNumberBg() compat.AdaptiveColor + DiffRemovedLineNumberBg() compat.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 + MarkdownText() compat.AdaptiveColor + MarkdownHeading() compat.AdaptiveColor + MarkdownLink() compat.AdaptiveColor + MarkdownLinkText() compat.AdaptiveColor + MarkdownCode() compat.AdaptiveColor + MarkdownBlockQuote() compat.AdaptiveColor + MarkdownEmph() compat.AdaptiveColor + MarkdownStrong() compat.AdaptiveColor + MarkdownHorizontalRule() compat.AdaptiveColor + MarkdownListItem() compat.AdaptiveColor + MarkdownListEnumeration() compat.AdaptiveColor + MarkdownImage() compat.AdaptiveColor + MarkdownImageText() compat.AdaptiveColor + MarkdownCodeBlock() compat.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 + SyntaxComment() compat.AdaptiveColor + SyntaxKeyword() compat.AdaptiveColor + SyntaxFunction() compat.AdaptiveColor + SyntaxVariable() compat.AdaptiveColor + SyntaxString() compat.AdaptiveColor + SyntaxNumber() compat.AdaptiveColor + SyntaxType() compat.AdaptiveColor + SyntaxOperator() compat.AdaptiveColor + SyntaxPunctuation() compat.AdaptiveColor } // BaseTheme provides a default implementation of the Theme interface // that can be embedded in concrete theme implementations. type BaseTheme struct { // Background colors - BackgroundColor lipgloss.AdaptiveColor - BackgroundSubtleColor lipgloss.AdaptiveColor - BackgroundElementColor lipgloss.AdaptiveColor + BackgroundColor compat.AdaptiveColor + BackgroundSubtleColor compat.AdaptiveColor + BackgroundElementColor compat.AdaptiveColor // Border colors - BorderSubtleColor lipgloss.AdaptiveColor - BorderColor lipgloss.AdaptiveColor - BorderActiveColor lipgloss.AdaptiveColor + BorderSubtleColor compat.AdaptiveColor + BorderColor compat.AdaptiveColor + BorderActiveColor compat.AdaptiveColor // Brand colors - PrimaryColor lipgloss.AdaptiveColor - SecondaryColor lipgloss.AdaptiveColor - AccentColor lipgloss.AdaptiveColor + PrimaryColor compat.AdaptiveColor + SecondaryColor compat.AdaptiveColor + AccentColor compat.AdaptiveColor // Text colors - TextMutedColor lipgloss.AdaptiveColor - TextColor lipgloss.AdaptiveColor + TextMutedColor compat.AdaptiveColor + TextColor compat.AdaptiveColor // Status colors - ErrorColor lipgloss.AdaptiveColor - WarningColor lipgloss.AdaptiveColor - SuccessColor lipgloss.AdaptiveColor - InfoColor lipgloss.AdaptiveColor + ErrorColor compat.AdaptiveColor + WarningColor compat.AdaptiveColor + SuccessColor compat.AdaptiveColor + InfoColor compat.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 + DiffAddedColor compat.AdaptiveColor + DiffRemovedColor compat.AdaptiveColor + DiffContextColor compat.AdaptiveColor + DiffHunkHeaderColor compat.AdaptiveColor + DiffHighlightAddedColor compat.AdaptiveColor + DiffHighlightRemovedColor compat.AdaptiveColor + DiffAddedBgColor compat.AdaptiveColor + DiffRemovedBgColor compat.AdaptiveColor + DiffContextBgColor compat.AdaptiveColor + DiffLineNumberColor compat.AdaptiveColor + DiffAddedLineNumberBgColor compat.AdaptiveColor + DiffRemovedLineNumberBgColor compat.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 + MarkdownTextColor compat.AdaptiveColor + MarkdownHeadingColor compat.AdaptiveColor + MarkdownLinkColor compat.AdaptiveColor + MarkdownLinkTextColor compat.AdaptiveColor + MarkdownCodeColor compat.AdaptiveColor + MarkdownBlockQuoteColor compat.AdaptiveColor + MarkdownEmphColor compat.AdaptiveColor + MarkdownStrongColor compat.AdaptiveColor + MarkdownHorizontalRuleColor compat.AdaptiveColor + MarkdownListItemColor compat.AdaptiveColor + MarkdownListEnumerationColor compat.AdaptiveColor + MarkdownImageColor compat.AdaptiveColor + MarkdownImageTextColor compat.AdaptiveColor + MarkdownCodeBlockColor compat.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 + SyntaxCommentColor compat.AdaptiveColor + SyntaxKeywordColor compat.AdaptiveColor + SyntaxFunctionColor compat.AdaptiveColor + SyntaxVariableColor compat.AdaptiveColor + SyntaxStringColor compat.AdaptiveColor + SyntaxNumberColor compat.AdaptiveColor + SyntaxTypeColor compat.AdaptiveColor + SyntaxOperatorColor compat.AdaptiveColor + SyntaxPunctuationColor compat.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) Primary() compat.AdaptiveColor { return t.PrimaryColor } +func (t *BaseTheme) Secondary() compat.AdaptiveColor { return t.SecondaryColor } +func (t *BaseTheme) Accent() compat.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) Error() compat.AdaptiveColor { return t.ErrorColor } +func (t *BaseTheme) Warning() compat.AdaptiveColor { return t.WarningColor } +func (t *BaseTheme) Success() compat.AdaptiveColor { return t.SuccessColor } +func (t *BaseTheme) Info() compat.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) Text() compat.AdaptiveColor { return t.TextColor } +func (t *BaseTheme) TextMuted() compat.AdaptiveColor { return t.TextMutedColor } -func (t *BaseTheme) Background() lipgloss.AdaptiveColor { return t.BackgroundColor } -func (t *BaseTheme) BackgroundSubtle() lipgloss.AdaptiveColor { return t.BackgroundSubtleColor } -func (t *BaseTheme) BackgroundElement() lipgloss.AdaptiveColor { return t.BackgroundElementColor } +func (t *BaseTheme) Background() compat.AdaptiveColor { return t.BackgroundColor } +func (t *BaseTheme) BackgroundSubtle() compat.AdaptiveColor { return t.BackgroundSubtleColor } +func (t *BaseTheme) BackgroundElement() compat.AdaptiveColor { return t.BackgroundElementColor } -func (t *BaseTheme) Border() lipgloss.AdaptiveColor { return t.BorderColor } -func (t *BaseTheme) BorderActive() lipgloss.AdaptiveColor { return t.BorderActiveColor } -func (t *BaseTheme) BorderSubtle() lipgloss.AdaptiveColor { return t.BorderSubtleColor } +func (t *BaseTheme) Border() compat.AdaptiveColor { return t.BorderColor } +func (t *BaseTheme) BorderActive() compat.AdaptiveColor { return t.BorderActiveColor } +func (t *BaseTheme) BorderSubtle() compat.AdaptiveColor { return t.BorderSubtleColor } -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 { +func (t *BaseTheme) DiffAdded() compat.AdaptiveColor { return t.DiffAddedColor } +func (t *BaseTheme) DiffRemoved() compat.AdaptiveColor { return t.DiffRemovedColor } +func (t *BaseTheme) DiffContext() compat.AdaptiveColor { return t.DiffContextColor } +func (t *BaseTheme) DiffHunkHeader() compat.AdaptiveColor { return t.DiffHunkHeaderColor } +func (t *BaseTheme) DiffHighlightAdded() compat.AdaptiveColor { return t.DiffHighlightAddedColor } +func (t *BaseTheme) DiffHighlightRemoved() compat.AdaptiveColor { return t.DiffHighlightRemovedColor } +func (t *BaseTheme) DiffAddedBg() compat.AdaptiveColor { return t.DiffAddedBgColor } +func (t *BaseTheme) DiffRemovedBg() compat.AdaptiveColor { return t.DiffRemovedBgColor } +func (t *BaseTheme) DiffContextBg() compat.AdaptiveColor { return t.DiffContextBgColor } +func (t *BaseTheme) DiffLineNumber() compat.AdaptiveColor { return t.DiffLineNumberColor } +func (t *BaseTheme) DiffAddedLineNumberBg() compat.AdaptiveColor { return t.DiffAddedLineNumberBgColor } -func (t *BaseTheme) DiffRemovedLineNumberBg() lipgloss.AdaptiveColor { +func (t *BaseTheme) DiffRemovedLineNumberBg() compat.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 { +func (t *BaseTheme) MarkdownText() compat.AdaptiveColor { return t.MarkdownTextColor } +func (t *BaseTheme) MarkdownHeading() compat.AdaptiveColor { return t.MarkdownHeadingColor } +func (t *BaseTheme) MarkdownLink() compat.AdaptiveColor { return t.MarkdownLinkColor } +func (t *BaseTheme) MarkdownLinkText() compat.AdaptiveColor { return t.MarkdownLinkTextColor } +func (t *BaseTheme) MarkdownCode() compat.AdaptiveColor { return t.MarkdownCodeColor } +func (t *BaseTheme) MarkdownBlockQuote() compat.AdaptiveColor { return t.MarkdownBlockQuoteColor } +func (t *BaseTheme) MarkdownEmph() compat.AdaptiveColor { return t.MarkdownEmphColor } +func (t *BaseTheme) MarkdownStrong() compat.AdaptiveColor { return t.MarkdownStrongColor } +func (t *BaseTheme) MarkdownHorizontalRule() compat.AdaptiveColor { return t.MarkdownHorizontalRuleColor } -func (t *BaseTheme) MarkdownListItem() lipgloss.AdaptiveColor { return t.MarkdownListItemColor } -func (t *BaseTheme) MarkdownListEnumeration() lipgloss.AdaptiveColor { +func (t *BaseTheme) MarkdownListItem() compat.AdaptiveColor { return t.MarkdownListItemColor } +func (t *BaseTheme) MarkdownListEnumeration() compat.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) MarkdownImage() compat.AdaptiveColor { return t.MarkdownImageColor } +func (t *BaseTheme) MarkdownImageText() compat.AdaptiveColor { return t.MarkdownImageTextColor } +func (t *BaseTheme) MarkdownCodeBlock() compat.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 } +func (t *BaseTheme) SyntaxComment() compat.AdaptiveColor { return t.SyntaxCommentColor } +func (t *BaseTheme) SyntaxKeyword() compat.AdaptiveColor { return t.SyntaxKeywordColor } +func (t *BaseTheme) SyntaxFunction() compat.AdaptiveColor { return t.SyntaxFunctionColor } +func (t *BaseTheme) SyntaxVariable() compat.AdaptiveColor { return t.SyntaxVariableColor } +func (t *BaseTheme) SyntaxString() compat.AdaptiveColor { return t.SyntaxStringColor } +func (t *BaseTheme) SyntaxNumber() compat.AdaptiveColor { return t.SyntaxNumberColor } +func (t *BaseTheme) SyntaxType() compat.AdaptiveColor { return t.SyntaxTypeColor } +func (t *BaseTheme) SyntaxOperator() compat.AdaptiveColor { return t.SyntaxOperatorColor } +func (t *BaseTheme) SyntaxPunctuation() compat.AdaptiveColor { return t.SyntaxPunctuationColor } -// ParseAdaptiveColor parses a color value from the config file into a lipgloss.AdaptiveColor. +// ParseAdaptiveColor parses a color value from the config file into a compat.AdaptiveColor. // It accepts either a string (hex color) or a map with "dark" and "light" keys. -func ParseAdaptiveColor(value any) (lipgloss.AdaptiveColor, error) { +func ParseAdaptiveColor(value any) (compat.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 compat.AdaptiveColor{}, fmt.Errorf("invalid hex color format: %s", hexColor) } - return lipgloss.AdaptiveColor{ - Dark: hexColor, - Light: hexColor, + return compat.AdaptiveColor{ + Dark: lipgloss.Color(hexColor), + Light: lipgloss.Color(hexColor), }, nil } @@ -236,11 +237,11 @@ func ParseAdaptiveColor(value any) (lipgloss.AdaptiveColor, error) { 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 compat.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), + return compat.AdaptiveColor{ + Dark: lipgloss.Color(fmt.Sprintf("%d", intVal)), + Light: lipgloss.Color(fmt.Sprintf("%d", intVal)), }, nil } @@ -250,7 +251,7 @@ func ParseAdaptiveColor(value any) (lipgloss.AdaptiveColor, error) { lightVal, lightOk := colorMap["light"] if !darkOk || !lightOk { - return lipgloss.AdaptiveColor{}, fmt.Errorf("color map must contain both 'dark' and 'light' keys") + return compat.AdaptiveColor{}, fmt.Errorf("color map must contain both 'dark' and 'light' keys") } darkHex, darkIsString := darkVal.(string) @@ -261,27 +262,27 @@ func ParseAdaptiveColor(value any) (lipgloss.AdaptiveColor, error) { lightVal, lightIsNumber := lightVal.(float64) if !darkIsNumber || !lightIsNumber { - return lipgloss.AdaptiveColor{}, fmt.Errorf("color map values must be strings or ints") + return compat.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), + return compat.AdaptiveColor{ + Dark: lipgloss.Color(fmt.Sprintf("%d", darkInt)), + Light: lipgloss.Color(fmt.Sprintf("%d", lightInt)), }, nil } if !hexColorRegex.MatchString(darkHex) || !hexColorRegex.MatchString(lightHex) { - return lipgloss.AdaptiveColor{}, fmt.Errorf("invalid hex color format") + return compat.AdaptiveColor{}, fmt.Errorf("invalid hex color format") } - return lipgloss.AdaptiveColor{ - Dark: darkHex, - Light: lightHex, + return compat.AdaptiveColor{ + Dark: lipgloss.Color(darkHex), + Light: lipgloss.Color(lightHex), }, nil } - return lipgloss.AdaptiveColor{}, fmt.Errorf("color must be either a hex string or an object with dark/light keys") + return compat.AdaptiveColor{}, fmt.Errorf("color must be either a hex string or an object with dark/light keys") } diff --git a/packages/tui/internal/theme/tokyonight.go b/packages/tui/internal/theme/tokyonight.go index 7ae53abc..8bb32dce 100644 --- a/packages/tui/internal/theme/tokyonight.go +++ b/packages/tui/internal/theme/tokyonight.go @@ -1,7 +1,8 @@ package theme import ( - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/v2" + "github.com/charmbracelet/lipgloss/v2/compat" ) // TokyoNightTheme implements the Theme interface with Tokyo Night colors. @@ -70,219 +71,219 @@ func NewTokyoNightTheme() *TokyoNightTheme { theme := &TokyoNightTheme{} // Base colors - theme.PrimaryColor = lipgloss.AdaptiveColor{ - Dark: darkBlue, - Light: lightBlue, + theme.PrimaryColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkBlue), + Light: lipgloss.Color(lightBlue), } - theme.SecondaryColor = lipgloss.AdaptiveColor{ - Dark: darkPurple, - Light: lightPurple, + theme.SecondaryColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkPurple), + Light: lipgloss.Color(lightPurple), } - theme.AccentColor = lipgloss.AdaptiveColor{ - Dark: darkOrange, - Light: lightOrange, + theme.AccentColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkOrange), + Light: lipgloss.Color(lightOrange), } // Status colors - theme.ErrorColor = lipgloss.AdaptiveColor{ - Dark: darkRed, - Light: lightRed, + theme.ErrorColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkRed), + Light: lipgloss.Color(lightRed), } - theme.WarningColor = lipgloss.AdaptiveColor{ - Dark: darkOrange, - Light: lightOrange, + theme.WarningColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkOrange), + Light: lipgloss.Color(lightOrange), } - theme.SuccessColor = lipgloss.AdaptiveColor{ - Dark: darkGreen, - Light: lightGreen, + theme.SuccessColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkGreen), + Light: lipgloss.Color(lightGreen), } - theme.InfoColor = lipgloss.AdaptiveColor{ - Dark: darkBlue, - Light: lightBlue, + theme.InfoColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkBlue), + Light: lipgloss.Color(lightBlue), } // Text colors - theme.TextColor = lipgloss.AdaptiveColor{ - Dark: darkStep12, - Light: lightStep12, + theme.TextColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep12), + Light: lipgloss.Color(lightStep12), } - theme.TextMutedColor = lipgloss.AdaptiveColor{ - Dark: darkStep11, - Light: lightStep11, + theme.TextMutedColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep11), + Light: lipgloss.Color(lightStep11), } // Background colors - theme.BackgroundColor = lipgloss.AdaptiveColor{ - Dark: darkStep1, - Light: lightStep1, + theme.BackgroundColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep1), + Light: lipgloss.Color(lightStep1), } - theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{ - Dark: darkStep2, - Light: lightStep2, + theme.BackgroundSubtleColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep2), + Light: lipgloss.Color(lightStep2), } - theme.BackgroundElementColor = lipgloss.AdaptiveColor{ - Dark: darkStep3, - Light: lightStep3, + theme.BackgroundElementColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep3), + Light: lipgloss.Color(lightStep3), } // Border colors - theme.BorderColor = lipgloss.AdaptiveColor{ - Dark: darkStep7, - Light: lightStep7, + theme.BorderColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep7), + Light: lipgloss.Color(lightStep7), } - theme.BorderActiveColor = lipgloss.AdaptiveColor{ - Dark: darkStep8, - Light: lightStep8, + theme.BorderActiveColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep8), + Light: lipgloss.Color(lightStep8), } - theme.BorderSubtleColor = lipgloss.AdaptiveColor{ - Dark: darkStep6, - Light: lightStep6, + theme.BorderSubtleColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep6), + Light: lipgloss.Color(lightStep6), } // Diff view colors - theme.DiffAddedColor = lipgloss.AdaptiveColor{ - Dark: "#4fd6be", // teal from palette - Light: "#1e725c", + theme.DiffAddedColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#4fd6be"), // teal from palette + Light: lipgloss.Color("#1e725c"), } - theme.DiffRemovedColor = lipgloss.AdaptiveColor{ - Dark: "#c53b53", // red1 from palette - Light: "#c53b53", + theme.DiffRemovedColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#c53b53"), // red1 from palette + Light: lipgloss.Color("#c53b53"), } - theme.DiffContextColor = lipgloss.AdaptiveColor{ - Dark: "#828bb8", // fg_dark from palette - Light: "#7086b5", + theme.DiffContextColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#828bb8"), // fg_dark from palette + Light: lipgloss.Color("#7086b5"), } - theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{ - Dark: "#828bb8", // fg_dark from palette - Light: "#7086b5", + theme.DiffHunkHeaderColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#828bb8"), // fg_dark from palette + Light: lipgloss.Color("#7086b5"), } - theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{ - Dark: "#b8db87", // git.add from palette - Light: "#4db380", + theme.DiffHighlightAddedColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#b8db87"), // git.add from palette + Light: lipgloss.Color("#4db380"), } - theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{ - Dark: "#e26a75", // git.delete from palette - Light: "#f52a65", + theme.DiffHighlightRemovedColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#e26a75"), // git.delete from palette + Light: lipgloss.Color("#f52a65"), } - theme.DiffAddedBgColor = lipgloss.AdaptiveColor{ - Dark: "#20303b", - Light: "#d5e5d5", + theme.DiffAddedBgColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#20303b"), + Light: lipgloss.Color("#d5e5d5"), } - theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{ - Dark: "#37222c", - Light: "#f7d8db", + theme.DiffRemovedBgColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#37222c"), + Light: lipgloss.Color("#f7d8db"), } - theme.DiffContextBgColor = lipgloss.AdaptiveColor{ - Dark: darkStep2, - Light: lightStep2, + theme.DiffContextBgColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep2), + Light: lipgloss.Color(lightStep2), } - theme.DiffLineNumberColor = lipgloss.AdaptiveColor{ - Dark: darkStep3, // dark3 from palette - Light: lightStep3, + theme.DiffLineNumberColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep3), // dark3 from palette + Light: lipgloss.Color(lightStep3), } - theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{ - Dark: "#1b2b34", - Light: "#c5d5c5", + theme.DiffAddedLineNumberBgColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#1b2b34"), + Light: lipgloss.Color("#c5d5c5"), } - theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{ - Dark: "#2d1f26", - Light: "#e7c8cb", + theme.DiffRemovedLineNumberBgColor = compat.AdaptiveColor{ + Dark: lipgloss.Color("#2d1f26"), + Light: lipgloss.Color("#e7c8cb"), } // Markdown colors - theme.MarkdownTextColor = lipgloss.AdaptiveColor{ - Dark: darkStep12, - Light: lightStep12, + theme.MarkdownTextColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep12), + Light: lipgloss.Color(lightStep12), } - theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{ - Dark: darkPurple, - Light: lightPurple, + theme.MarkdownHeadingColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkPurple), + Light: lipgloss.Color(lightPurple), } - theme.MarkdownLinkColor = lipgloss.AdaptiveColor{ - Dark: darkBlue, - Light: lightBlue, + theme.MarkdownLinkColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkBlue), + Light: lipgloss.Color(lightBlue), } - theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{ - Dark: darkCyan, - Light: lightCyan, + theme.MarkdownLinkTextColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkCyan), + Light: lipgloss.Color(lightCyan), } - theme.MarkdownCodeColor = lipgloss.AdaptiveColor{ - Dark: darkGreen, - Light: lightGreen, + theme.MarkdownCodeColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkGreen), + Light: lipgloss.Color(lightGreen), } - theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{ - Dark: darkYellow, - Light: lightYellow, + theme.MarkdownBlockQuoteColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkYellow), + Light: lipgloss.Color(lightYellow), } - theme.MarkdownEmphColor = lipgloss.AdaptiveColor{ - Dark: darkYellow, - Light: lightYellow, + theme.MarkdownEmphColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkYellow), + Light: lipgloss.Color(lightYellow), } - theme.MarkdownStrongColor = lipgloss.AdaptiveColor{ - Dark: darkOrange, - Light: lightOrange, + theme.MarkdownStrongColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkOrange), + Light: lipgloss.Color(lightOrange), } - theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{ - Dark: darkStep11, - Light: lightStep11, + theme.MarkdownHorizontalRuleColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep11), + Light: lipgloss.Color(lightStep11), } - theme.MarkdownListItemColor = lipgloss.AdaptiveColor{ - Dark: darkBlue, - Light: lightBlue, + theme.MarkdownListItemColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkBlue), + Light: lipgloss.Color(lightBlue), } - theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{ - Dark: darkCyan, - Light: lightCyan, + theme.MarkdownListEnumerationColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkCyan), + Light: lipgloss.Color(lightCyan), } - theme.MarkdownImageColor = lipgloss.AdaptiveColor{ - Dark: darkBlue, - Light: lightBlue, + theme.MarkdownImageColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkBlue), + Light: lipgloss.Color(lightBlue), } - theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{ - Dark: darkCyan, - Light: lightCyan, + theme.MarkdownImageTextColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkCyan), + Light: lipgloss.Color(lightCyan), } - theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{ - Dark: darkStep12, - Light: lightStep12, + theme.MarkdownCodeBlockColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep12), + Light: lipgloss.Color(lightStep12), } // Syntax highlighting colors - theme.SyntaxCommentColor = lipgloss.AdaptiveColor{ - Dark: darkStep11, - Light: lightStep11, + theme.SyntaxCommentColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep11), + Light: lipgloss.Color(lightStep11), } - theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{ - Dark: darkPurple, - Light: lightPurple, + theme.SyntaxKeywordColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkPurple), + Light: lipgloss.Color(lightPurple), } - theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{ - Dark: darkBlue, - Light: lightBlue, + theme.SyntaxFunctionColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkBlue), + Light: lipgloss.Color(lightBlue), } - theme.SyntaxVariableColor = lipgloss.AdaptiveColor{ - Dark: darkRed, - Light: lightRed, + theme.SyntaxVariableColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkRed), + Light: lipgloss.Color(lightRed), } - theme.SyntaxStringColor = lipgloss.AdaptiveColor{ - Dark: darkGreen, - Light: lightGreen, + theme.SyntaxStringColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkGreen), + Light: lipgloss.Color(lightGreen), } - theme.SyntaxNumberColor = lipgloss.AdaptiveColor{ - Dark: darkOrange, - Light: lightOrange, + theme.SyntaxNumberColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkOrange), + Light: lipgloss.Color(lightOrange), } - theme.SyntaxTypeColor = lipgloss.AdaptiveColor{ - Dark: darkYellow, - Light: lightYellow, + theme.SyntaxTypeColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkYellow), + Light: lipgloss.Color(lightYellow), } - theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{ - Dark: darkCyan, - Light: lightCyan, + theme.SyntaxOperatorColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkCyan), + Light: lipgloss.Color(lightCyan), } - theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{ - Dark: darkStep12, - Light: lightStep12, + theme.SyntaxPunctuationColor = compat.AdaptiveColor{ + Dark: lipgloss.Color(darkStep12), + Light: lipgloss.Color(lightStep12), } return theme diff --git a/packages/tui/internal/theme/tron.go b/packages/tui/internal/theme/tron.go deleted file mode 100644 index ea975675..00000000 --- a/packages/tui/internal/theme/tron.go +++ /dev/null @@ -1,272 +0,0 @@ -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, - } - - // Background colors - theme.BackgroundColor = lipgloss.AdaptiveColor{ - Dark: darkBackground, - Light: lightBackground, - } - theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{ - Dark: darkCurrentLine, - Light: lightCurrentLine, - } - theme.BackgroundElementColor = lipgloss.AdaptiveColor{ - Dark: "#070d14", // Slightly darker than background - Light: "#ffffff", // Slightly lighter than background - } - - // Border colors - theme.BorderColor = lipgloss.AdaptiveColor{ - Dark: darkBorder, - Light: lightBorder, - } - theme.BorderActiveColor = lipgloss.AdaptiveColor{ - Dark: darkCyan, - Light: lightCyan, - } - theme.BorderSubtleColor = 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()) -} diff --git a/packages/tui/internal/tui/tui.go b/packages/tui/internal/tui/tui.go index e4fdb4ae..29ce635d 100644 --- a/packages/tui/internal/tui/tui.go +++ b/packages/tui/internal/tui/tui.go @@ -5,11 +5,11 @@ import ( "log/slog" "strings" - "github.com/charmbracelet/bubbles/cursor" - "github.com/charmbracelet/bubbles/key" - "github.com/charmbracelet/bubbles/spinner" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/bubbles/v2/cursor" + "github.com/charmbracelet/bubbles/v2/key" + "github.com/charmbracelet/bubbles/v2/spinner" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode/internal/app" "github.com/sst/opencode/internal/components/core" @@ -18,6 +18,8 @@ import ( "github.com/sst/opencode/internal/page" "github.com/sst/opencode/internal/state" "github.com/sst/opencode/internal/status" + "github.com/sst/opencode/internal/styles" + "github.com/sst/opencode/internal/theme" "github.com/sst/opencode/internal/util" "github.com/sst/opencode/pkg/client" ) @@ -90,16 +92,16 @@ type appModel struct { width, height int currentPage page.PageID previousPage page.PageID - pages map[page.PageID]tea.Model + pages map[page.PageID]layout.ModelWithView loadedPages map[page.PageID]bool - status core.StatusCmp + status core.StatusComponent app *app.App showPermissions bool - permissions dialog.PermissionDialogCmp + permissions dialog.PermissionDialogComponent showHelp bool - help dialog.HelpCmp + help dialog.HelpComponent showQuit bool quit dialog.QuitDialog @@ -118,7 +120,7 @@ type appModel struct { initDialog dialog.InitDialogCmp showFilepicker bool - filepicker dialog.FilepickerCmp + filepicker dialog.FilepickerComponent showThemeDialog bool themeDialog dialog.ThemeDialog @@ -131,7 +133,12 @@ type appModel struct { } func (a appModel) Init() tea.Cmd { + t := theme.CurrentTheme() var cmds []tea.Cmd + cmds = append(cmds, tea.SetBackgroundColor(t.Background())) + // cmds = append(cmds, tea.SetForegroundColor(t.Background())) + cmds = append(cmds, tea.RequestBackgroundColor) + cmd := a.pages[a.currentPage].Init() a.loadedPages[a.currentPage] = true cmds = append(cmds, cmd) @@ -170,13 +177,14 @@ func (a appModel) updateAllPages(msg tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd for id := range a.pages { - a.pages[id], cmd = a.pages[id].Update(msg) + updated, cmd := a.pages[id].Update(msg) + a.pages[id] = updated.(layout.ModelWithView) cmds = append(cmds, cmd) } s, cmd := a.status.Update(msg) cmds = append(cmds, cmd) - a.status = s.(core.StatusCmp) + a.status = s.(core.StatusComponent) return a, tea.Batch(cmds...) } @@ -185,6 +193,10 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmds []tea.Cmd var cmd tea.Cmd switch msg := msg.(type) { + case tea.BackgroundColorMsg: + styles.Terminal = &styles.TerminalInfo{ + BackgroundIsDark: msg.IsDark(), + } case cursor.BlinkMsg: return a.updateAllPages(msg) case spinner.TickMsg: @@ -234,16 +246,17 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } s, _ := a.status.Update(msg) - a.status = s.(core.StatusCmp) - a.pages[a.currentPage], cmd = a.pages[a.currentPage].Update(msg) + a.status = s.(core.StatusComponent) + updated, cmd := a.pages[a.currentPage].Update(msg) + a.pages[a.currentPage] = updated.(layout.ModelWithView) cmds = append(cmds, cmd) prm, permCmd := a.permissions.Update(msg) - a.permissions = prm.(dialog.PermissionDialogCmp) + a.permissions = prm.(dialog.PermissionDialogComponent) cmds = append(cmds, permCmd) help, helpCmd := a.help.Update(msg) - a.help = help.(dialog.HelpCmp) + a.help = help.(dialog.HelpComponent) cmds = append(cmds, helpCmd) session, sessionCmd := a.sessionDialog.Update(msg) @@ -255,7 +268,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cmds = append(cmds, commandCmd) filepicker, filepickerCmd := a.filepicker.Update(msg) - a.filepicker = filepicker.(dialog.FilepickerCmp) + a.filepicker = filepicker.(dialog.FilepickerComponent) cmds = append(cmds, filepickerCmd) a.initDialog.SetSize(msg.Width, msg.Height) @@ -342,10 +355,19 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { a.app.Config.Theme = msg.ThemeName a.app.SaveConfig() - a.pages[a.currentPage], cmd = a.pages[a.currentPage].Update(msg) + updated, cmd := a.pages[a.currentPage].Update(msg) + if cmd != nil { + cmds = append(cmds, cmd) + } + + t := theme.CurrentTheme() + cmds = append(cmds, tea.SetBackgroundColor(t.Background())) + // cmds = append(cmds, tea.RequestBackgroundColor) + + a.pages[a.currentPage] = updated.(layout.ModelWithView) a.showThemeDialog = false status.Info("Theme changed to: " + msg.ThemeName) - return a, cmd + return a, tea.Batch(cmds...) case dialog.ShowInitDialogMsg: a.showInitDialog = msg.Show @@ -597,13 +619,13 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { default: f, filepickerCmd := a.filepicker.Update(msg) - a.filepicker = f.(dialog.FilepickerCmp) + a.filepicker = f.(dialog.FilepickerComponent) cmds = append(cmds, filepickerCmd) } if a.showFilepicker { f, filepickerCmd := a.filepicker.Update(msg) - a.filepicker = f.(dialog.FilepickerCmp) + a.filepicker = f.(dialog.FilepickerComponent) cmds = append(cmds, filepickerCmd) // Only block key messages send all other messages down if _, ok := msg.(tea.KeyMsg); ok { @@ -623,7 +645,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if a.showPermissions { d, permissionsCmd := a.permissions.Update(msg) - a.permissions = d.(dialog.PermissionDialogCmp) + a.permissions = d.(dialog.PermissionDialogComponent) cmds = append(cmds, permissionsCmd) // Only block key messages send all other messages down if _, ok := msg.(tea.KeyMsg); ok { @@ -693,9 +715,10 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { s, cmd := a.status.Update(msg) cmds = append(cmds, cmd) - a.status = s.(core.StatusCmp) + a.status = s.(core.StatusComponent) - a.pages[a.currentPage], cmd = a.pages[a.currentPage].Update(msg) + updated, cmd := a.pages[a.currentPage].Update(msg) + a.pages[a.currentPage] = updated.(layout.ModelWithView) cmds = append(cmds, cmd) return a, tea.Batch(cmds...) } @@ -930,7 +953,7 @@ func NewModel(app *app.App) tea.Model { toolsDialog: dialog.NewToolsDialogCmp(), app: app, commands: []dialog.Command{}, - pages: map[page.PageID]tea.Model{ + pages: map[page.PageID]layout.ModelWithView{ page.ChatPage: page.NewChatPage(app), }, filepicker: dialog.NewFilepickerCmp(app), diff --git a/packages/tui/internal/util/util.go b/packages/tui/internal/util/util.go index fe2cf71e..537d852d 100644 --- a/packages/tui/internal/util/util.go +++ b/packages/tui/internal/util/util.go @@ -1,7 +1,7 @@ package util import ( - tea "github.com/charmbracelet/bubbletea" + tea "github.com/charmbracelet/bubbletea/v2" ) func CmdHandler(msg tea.Msg) tea.Cmd {