Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
20 changes: 19 additions & 1 deletion pkg/config/user_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,20 @@ type ThemeConfig struct {
MarkedBaseCommitFgColor []string `yaml:"markedBaseCommitFgColor"`
// Background color of marked base commit (for rebase)
MarkedBaseCommitBgColor []string `yaml:"markedBaseCommitBgColor"`
// Color for file with unstaged changes
// Color for file with unstaged changes (used as fallback when per-status colors are not set)
UnstagedChangesColor []string `yaml:"unstagedChangesColor" jsonschema:"minItems=1,uniqueItems=true"`
// Color for modified files. Defaults to unstagedChangesColor if empty.
ModifiedColor []string `yaml:"modifiedColor"`
// Color for deleted files. Defaults to unstagedChangesColor if empty.
DeletedColor []string `yaml:"deletedColor"`
// Color for untracked (new) files. Defaults to unstagedChangesColor if empty.
UntrackedColor []string `yaml:"untrackedColor"`
// Color for added (staged new) files. Defaults to green if empty.
AddedColor []string `yaml:"addedColor"`
// Color for renamed files. Defaults to unstagedChangesColor if empty.
RenamedColor []string `yaml:"renamedColor"`
// Color for copied files. Defaults to cyan if empty.
CopiedColor []string `yaml:"copiedColor"`
// Default text color
DefaultFgColor []string `yaml:"defaultFgColor" jsonschema:"minItems=1,uniqueItems=true"`
}
Expand Down Expand Up @@ -796,6 +808,12 @@ func GetDefaultConfig() *UserConfig {
MarkedBaseCommitBgColor: []string{"yellow"},
MarkedBaseCommitFgColor: []string{"blue"},
UnstagedChangesColor: []string{"red"},
ModifiedColor: []string{},
DeletedColor: []string{},
UntrackedColor: []string{},
AddedColor: []string{},
RenamedColor: []string{},
CopiedColor: []string{},
DefaultFgColor: []string{"default"},
},
CommitLength: CommitLengthConfig{Show: true},
Expand Down
51 changes: 38 additions & 13 deletions pkg/gui/presentation/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,23 +183,46 @@ func getFileLine(

func formatFileStatus(file *models.File, restColor style.TextStyle) string {
firstChar := file.ShortStatus[0:1]
firstCharCl := style.FgGreen
switch firstChar {
case "?":
firstCharCl = theme.UnstagedChangesColor
case " ":
firstCharCl := colorForStatusChar(firstChar, true)
if firstCharCl == (style.TextStyle{}) {
firstCharCl = restColor
}

secondChar := file.ShortStatus[1:2]
secondCharCl := theme.UnstagedChangesColor
if secondChar == " " {
secondCharCl := colorForStatusChar(secondChar, false)
if secondCharCl == (style.TextStyle{}) {
secondCharCl = restColor
}

return firstCharCl.Sprint(firstChar) + secondCharCl.Sprint(secondChar)
}

// colorForStatusChar returns the color for a single status character from git short status.
// isStagedColumn indicates whether this is the first (index/staged) or second (worktree) column.
func colorForStatusChar(ch string, isStagedColumn bool) style.TextStyle {
switch ch {
case "M":
return theme.ModifiedColor
case "D":
return theme.DeletedColor
case "?":
return theme.UntrackedColor
case "A":
return theme.AddedColor
case "R":
return theme.RenamedColor
case "C":
return theme.CopiedColor
case "T":
return theme.ModifiedColor
case " ":
// space means no change in this column — use rest/name color (caller handles this)
return style.TextStyle{}
default:
return theme.UnstagedChangesColor
}
}

func formatLineChanges(linesAdded, linesDeleted int) string {
output := ""

Expand Down Expand Up @@ -285,15 +308,17 @@ func getCommitFileLine(
func getColorForChangeStatus(changeStatus string) style.TextStyle {
switch changeStatus {
case "A":
return style.FgGreen
case "M", "R":
return style.FgYellow
return theme.AddedColor
case "M":
return theme.ModifiedColor
case "R":
return theme.RenamedColor
case "D":
return theme.UnstagedChangesColor
return theme.DeletedColor
case "C":
return style.FgCyan
return theme.CopiedColor
case "T":
return style.FgMagenta
return theme.ModifiedColor
default:
return theme.DefaultTextColor
}
Expand Down
39 changes: 39 additions & 0 deletions pkg/theme/theme.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ var (
DiffTerminalColor = style.FgMagenta

UnstagedChangesColor = style.New()

ModifiedColor = style.New()
DeletedColor = style.New()
UntrackedColor = style.New()
AddedColor = style.New()
RenamedColor = style.New()
CopiedColor = style.New()
)

// UpdateTheme updates all theme variables
Expand All @@ -66,6 +73,38 @@ func UpdateTheme(themeConfig config.ThemeConfig) {
unstagedChangesTextStyle := GetTextStyle(themeConfig.UnstagedChangesColor, false)
UnstagedChangesColor = unstagedChangesTextStyle

// Per-status colors — fall back to UnstagedChangesColor or hardcoded defaults if not set
if len(themeConfig.ModifiedColor) > 0 {
ModifiedColor = GetTextStyle(themeConfig.ModifiedColor, false)
} else {
ModifiedColor = UnstagedChangesColor
}
if len(themeConfig.DeletedColor) > 0 {
DeletedColor = GetTextStyle(themeConfig.DeletedColor, false)
} else {
DeletedColor = UnstagedChangesColor
}
if len(themeConfig.UntrackedColor) > 0 {
UntrackedColor = GetTextStyle(themeConfig.UntrackedColor, false)
} else {
UntrackedColor = UnstagedChangesColor
}
if len(themeConfig.AddedColor) > 0 {
AddedColor = GetTextStyle(themeConfig.AddedColor, false)
} else {
AddedColor = style.FgGreen
}
if len(themeConfig.RenamedColor) > 0 {
RenamedColor = GetTextStyle(themeConfig.RenamedColor, false)
} else {
RenamedColor = UnstagedChangesColor
}
if len(themeConfig.CopiedColor) > 0 {
CopiedColor = GetTextStyle(themeConfig.CopiedColor, false)
} else {
CopiedColor = style.FgCyan
}

GocuiSelectedLineBgColor = GetGocuiStyle(themeConfig.SelectedLineBgColor)
GocuiInactiveViewSelectedLineBgColor = GetGocuiStyle(themeConfig.InactiveViewSelectedLineBgColor)
OptionsColor = GetGocuiStyle(themeConfig.OptionsTextColor)
Expand Down