Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/bnema/zerowrap v1.4.0
github.com/charmbracelet/x/ansi v0.11.7
github.com/cli/go-gh/v2 v2.13.0
github.com/fsnotify/fsnotify v1.9.0
github.com/go-git/go-git/v5 v5.19.1
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/pelletier/go-toml/v2 v2.2.4
Expand Down Expand Up @@ -43,7 +44,6 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dlclark/regexp2 v1.12.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.9.0 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
Expand Down
9 changes: 9 additions & 0 deletions internal/adapters/in/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,15 @@ func NewRootCommand(cfg *viper.Viper, run RunFunc) (*cobra.Command, error) {
flags.Int("context-lines", 3, "Number of unchanged context lines to keep around changes")
flags.String("log-level", "info", "Log level (trace, debug, info, warn, error, disabled)")
flags.String("log-file", "", "Write logs to this file instead of the default XDG state log")
flags.String("theme", "auto", "Theme mode: auto, dark, or light")
flags.String("config", "", "Path to a config file (defaults to XDG config when present)")
flags.Duration("provider-sync-interval", 2*time.Minute, "Interval for active review provider background sync")
cfg.SetDefault("repo-path", ".")
cfg.SetDefault("context-lines", 3)
cfg.SetDefault("diff-mode", string(core.DiffModeBranch))
cfg.SetDefault("startup-detect", true)
cfg.SetDefault("log-level", "info")
cfg.SetDefault("theme", "auto")
cfg.SetDefault("provider-sync-interval", 2*time.Minute)
if err := cfg.BindPFlag("repo-path", flags.Lookup("repo-path")); err != nil {
return nil, fmt.Errorf("bind repo-path flag: %w", err)
Expand All @@ -63,6 +66,12 @@ func NewRootCommand(cfg *viper.Viper, run RunFunc) (*cobra.Command, error) {
if err := cfg.BindPFlag("log-file", flags.Lookup("log-file")); err != nil {
return nil, fmt.Errorf("bind log-file flag: %w", err)
}
if err := cfg.BindPFlag("theme", flags.Lookup("theme")); err != nil {
return nil, fmt.Errorf("bind theme flag: %w", err)
}
if err := cfg.BindPFlag("config", flags.Lookup("config")); err != nil {
return nil, fmt.Errorf("bind config flag: %w", err)
}
if err := cfg.BindPFlag("provider-sync-interval", flags.Lookup("provider-sync-interval")); err != nil {
return nil, fmt.Errorf("bind provider-sync-interval flag: %w", err)
}
Expand Down
7 changes: 5 additions & 2 deletions internal/adapters/in/cli/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ func TestNewRootCommandExecutesRunFuncAndBindsConfig(t *testing.T) {
args []string
expectRepo string
expectContext int
expectTheme string
}{
{
name: "binds repo path and context lines",
args: []string{"--repo-path", "/tmp/repo", "--context-lines", "2"},
name: "binds repo path, context lines, and theme",
args: []string{"--repo-path", "/tmp/repo", "--context-lines", "2", "--theme", "light"},
expectRepo: "/tmp/repo",
expectContext: 2,
expectTheme: "light",
},
}

Expand Down Expand Up @@ -52,6 +54,7 @@ func TestNewRootCommandExecutesRunFuncAndBindsConfig(t *testing.T) {
assert.True(t, called)
assert.Equal(t, tt.expectRepo, cfg.GetString("repo-path"))
assert.Equal(t, tt.expectContext, cfg.GetInt("context-lines"))
assert.Equal(t, tt.expectTheme, cfg.GetString("theme"))
assert.Equal(t, string(core.DiffModeBranch), cfg.GetString("diff-mode"))
})
}
Expand Down
17 changes: 11 additions & 6 deletions internal/adapters/in/tui/comment_editor.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@ import (
"charm.land/bubbles/v2/textarea"
tea "charm.land/bubbletea/v2"
"charm.land/lipgloss/v2"
)

var (
commentEditorStyle = lipgloss.NewStyle().Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color("62")).Padding(0, 1)
commentEditorTitleStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("81"))
"ero/internal/adapters/in/tui/theme"
)

func commentEditorStyle() lipgloss.Style {
return theme.SearchPaneStyle
}

func commentEditorTitleStyle() lipgloss.Style {
return theme.SearchPaneTitleStyle
}

type CommentEditorAction string

const (
Expand Down Expand Up @@ -76,9 +81,9 @@ func (e CommentEditor) ViewWithWidth(availableWidth int) string {
input := e.input
input.SetWidth(max(width-4, 20))
lines := []string{
commentEditorTitleStyle.Render("Add review comment"),
commentEditorTitleStyle().Render("Add review comment"),
input.View(),
renderKeyHints([]KeyHint{{Key: commentSubmitKeyLabel(), Label: "submit"}, {Key: "esc", Label: "cancel"}}),
}
return commentEditorStyle.Width(width).Render(strings.Join(lines, "\n"))
return commentEditorStyle().Width(width).Render(strings.Join(lines, "\n"))
}
14 changes: 7 additions & 7 deletions internal/adapters/in/tui/component/statusbar.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,12 +211,12 @@ func renderNerdFontProviderSync(model StatusModel) string {
}
var b strings.Builder
b.WriteString(theme.StatusBaseStyle.Render(" "))
b.WriteString(theme.StatusBaseStyle.Foreground(lipgloss.Color("248")).Render(providerGlyph(provider)))
b.WriteString(theme.StatusBaseStyle.Foreground(lipgloss.Color(theme.ColorStatusInfo)).Render(providerGlyph(provider)))
b.WriteString(theme.StatusBaseStyle.Render(" "))
b.WriteString(theme.StatusBaseStyle.Foreground(providerStatusDotColor(model.ProviderSync.Status)).Render(nerdFontSyncDot))
for _, part := range nerdFontProviderSyncTextParts(model) {
b.WriteString(theme.StatusBaseStyle.Render(" "))
b.WriteString(theme.StatusBaseStyle.Foreground(lipgloss.Color("248")).Render(part))
b.WriteString(theme.StatusBaseStyle.Foreground(lipgloss.Color(theme.ColorStatusInfo)).Render(part))
}
b.WriteString(theme.StatusBaseStyle.Render(" "))
return b.String()
Expand Down Expand Up @@ -250,15 +250,15 @@ func providerGlyph(provider string) string {
func providerStatusDotColor(status core.ProviderSyncStatus) color.Color {
switch status {
case core.ProviderSyncStatusSynced:
return lipgloss.Color("#3fb950")
return lipgloss.Color(theme.CurrentPalette().AddedMarkerFg)
case core.ProviderSyncStatusFailed:
return lipgloss.Color("#ff7b72")
return lipgloss.Color(theme.CurrentPalette().DeletedMarkerFg)
case core.ProviderSyncStatusBackingOff:
return lipgloss.Color("#ffa657")
return lipgloss.Color(theme.ColorWarning)
case core.ProviderSyncStatusLoadingCache, core.ProviderSyncStatusSyncing:
return lipgloss.Color("#58a6ff")
return lipgloss.Color(theme.ColorAccent)
default:
return lipgloss.Color("81")
return lipgloss.Color(theme.ColorAccent)
}
}

Expand Down
35 changes: 26 additions & 9 deletions internal/adapters/in/tui/markdown_renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
glamouransi "charm.land/glamour/v2/ansi"

"ero/internal/adapters/in/tui/theme"
"ero/internal/core"
)

type MarkdownTheme string
Expand All @@ -19,6 +20,13 @@ const (
MarkdownThemeLight MarkdownTheme = "light"
)

func markdownThemeForAppearance(appearance core.ThemeAppearance) MarkdownTheme {
if appearance == core.ThemeAppearanceLight {
return MarkdownThemeLight
}
return MarkdownThemeDark
}

type markdownTermRenderer interface {
Render(markdown string) (string, error)
}
Expand Down Expand Up @@ -57,6 +65,14 @@ func NewMarkdownRendererWithFactory(factory markdownRendererFactory) *MarkdownRe
}
}

func (r *MarkdownRenderer) Clear() {
if r == nil {
return
}
r.renderers = map[markdownRendererConfig]markdownTermRenderer{}
r.entries = map[markdownRendererCacheKey]string{}
}

func (r *MarkdownRenderer) Render(markdown string, width int, theme MarkdownTheme) string {
if r == nil {
return safeMarkdownFallback(markdown)
Expand Down Expand Up @@ -113,16 +129,17 @@ func newGlamourTermRenderer(width int, theme MarkdownTheme) (markdownTermRendere
}

func eroMarkdownStyle(markdownTheme MarkdownTheme) glamouransi.StyleConfig {
text := theme.ColorStatusInfo
muted := theme.ColorMutedText
heading := theme.ColorAccent
section := theme.ColorWarning
codeBackground := theme.ColorCodeBg
appearance := core.ThemeAppearanceDark
if markdownTheme == MarkdownThemeLight {
text = theme.ColorStatusBase
muted = "244"
codeBackground = "#f6f8fa"
appearance = core.ThemeAppearanceLight
}
palette := theme.PaletteForAppearance(appearance)
text := palette.ColorStatusInfo
muted := palette.ColorMutedText
heading := palette.ColorAccent
section := palette.ColorWarning
codeBackground := palette.ColorCodeBg
codeTheme := palette.MarkdownCodeTheme
bold := true
italic := true
underline := true
Expand All @@ -144,7 +161,7 @@ func eroMarkdownStyle(markdownTheme MarkdownTheme) glamouransi.StyleConfig {
Link: glamouransi.StylePrimitive{Color: &heading, Underline: &underline},
LinkText: glamouransi.StylePrimitive{Color: &heading, Underline: &underline},
Code: glamouransi.StyleBlock{StylePrimitive: glamouransi.StylePrimitive{Color: &section, BackgroundColor: &codeBackground}},
CodeBlock: glamouransi.StyleCodeBlock{StyleBlock: glamouransi.StyleBlock{StylePrimitive: glamouransi.StylePrimitive{Color: &text, BackgroundColor: &codeBackground}, Margin: &zeroIndent}, Theme: "github-dark"},
CodeBlock: glamouransi.StyleCodeBlock{StyleBlock: glamouransi.StyleBlock{StylePrimitive: glamouransi.StylePrimitive{Color: &text, BackgroundColor: &codeBackground}, Margin: &zeroIndent}, Theme: codeTheme},
BlockQuote: glamouransi.StyleBlock{StylePrimitive: glamouransi.StylePrimitive{Color: &muted}, Indent: &quoteIndent, IndentToken: &quoteToken},
}
}
Expand Down
16 changes: 16 additions & 0 deletions internal/adapters/in/tui/markdown_renderer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,22 @@ func TestMarkdownRendererColorsHeadingsAndFencedCodeBlocks(t *testing.T) {
}
}

func TestMarkdownRendererUsesLightCodeTheme(t *testing.T) {
renderer := NewMarkdownRenderer()

got := renderer.Render("```go\nfmt.Println(\"hi\")\n```", 80, MarkdownThemeLight)
plain := regexp.MustCompile(`\x1b\[[0-9;?]*[ -/]*[@-~]`).ReplaceAllString(got, "")

if !strings.Contains(plain, "fmt.Println") {
t.Fatalf("expected rendered fenced code block to include code, got %q", got)
}
// These ANSI colors come from the current light Chroma style; update them if
// the light palette's MarkdownCodeTheme changes.
if !strings.Contains(got, "38;5;61") || !strings.Contains(got, "38;5;23") {
t.Fatalf("expected light code highlighting in rendered markdown, got %q", got)
}
}

func TestMarkdownRendererRendersFencedCodeBlocks(t *testing.T) {
renderer := NewMarkdownRenderer()

Expand Down
Loading
Loading