Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
2 changes: 2 additions & 0 deletions .gitmux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,5 @@ tmux:
divergence_space: false
# Show flags symbols without counts.
flags_without_count: false
# Hide flag count when symbol is empty (default false shows count only).
hide_flag_count_if_empty_symbol: false
19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,15 +288,16 @@ layout: [branch, "|", flags, "|", stats]

This is the list of additional configuration `options`:

| Option | Description | Default |
| :------------------- | :------------------------------------------------------------------------------ | :----------------: |
| `branch_max_len` | Maximum displayed length for local and remote branch names | `0` (no limit) |
| `branch_trim` | Trim left, right or from the center of the branch (`right`, `left` or `center`) | `right` (trailing) |
| `ellipsis` | Character to show branch name has been truncated | `…` |
| `hide_clean` | Hides the clean flag entirely | `false` |
| `swap_divergence` | Swaps order of behind & ahead upstream counts | `false` |
| `divergence_space` | Add a space between behind & ahead upstream counts | `false` |
| `flags_without_count`| Show flags symbols without counts | `false` |
| Option | Description | Default |
| :------------------------------ | :------------------------------------------------------------------------------ | :----------------: |
| `branch_max_len` | Maximum displayed length for local and remote branch names | `0` (no limit) |
| `branch_trim` | Trim left, right or from the center of the branch (`right`, `left` or `center`) | `right` (trailing) |
| `ellipsis` | Character to show branch name has been truncated | `…` |
| `hide_clean` | Hides the clean flag entirely | `false` |
| `swap_divergence` | Swaps order of behind & ahead upstream counts | `false` |
| `divergence_space` | Add a space between behind & ahead upstream counts | `false` |
| `flags_without_count` | Show flags symbols without counts | `false` |
| `hide_flag_count_if_empty_symbol` | Hide flag count when symbol is empty (false shows count only) | `false` |
Comment thread
arl marked this conversation as resolved.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename the flag to:
hide_empty_flags

and realign the markdown table.
Rename variable in Go code


## Troubleshooting

Expand Down
76 changes: 55 additions & 21 deletions tmux/formater.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,14 @@ func (d *direction) UnmarshalYAML(value *yaml.Node) error {
}

type options struct {
BranchMaxLen int `yaml:"branch_max_len"`
BranchTrim direction `yaml:"branch_trim"`
Ellipsis string `yaml:"ellipsis"`
HideClean bool `yaml:"hide_clean"`
DivergenceSpace bool `yaml:"divergence_space"`
SwapDivergence bool `yaml:"swap_divergence"`
FlagsWithoutCount bool `yaml:"flags_without_count"`
BranchMaxLen int `yaml:"branch_max_len"`
BranchTrim direction `yaml:"branch_trim"`
Ellipsis string `yaml:"ellipsis"`
HideClean bool `yaml:"hide_clean"`
DivergenceSpace bool `yaml:"divergence_space"`
SwapDivergence bool `yaml:"swap_divergence"`
FlagsWithoutCount bool `yaml:"flags_without_count"`
HideFlagCountIfEmptySymbol bool `yaml:"hide_flag_count_if_empty_symbol"`
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename based on previous comment

}

// A Formater formats git status to a tmux style string.
Expand Down Expand Up @@ -297,6 +298,15 @@ func (f *Formater) currentRef() string {

// formatFlag formats a flag with or without count based on the flags_without_count option
func (f *Formater) formatFlag(style, symbol string, count int) string {
// Handle empty symbol case based on hide_flag_count_if_empty_symbol option
if symbol == "" {
if f.Options.HideFlagCountIfEmptySymbol {
return "" // Hide both symbol and count
}
// Show just the count without symbol
return fmt.Sprintf("%s%d", style, count)
}

if f.Options.FlagsWithoutCount {
return fmt.Sprintf("%s%s", style, symbol)
}
Expand All @@ -306,37 +316,61 @@ func (f *Formater) formatFlag(style, symbol string, count int) string {
func (f *Formater) flags() string {
var flags []string
if f.st.IsClean {
if f.st.NumStashed != 0 && f.Symbols.Stashed != "" {
flags = append(flags, f.formatFlag(f.Styles.Stashed, f.Symbols.Stashed, f.st.NumStashed))
if f.st.NumStashed != 0 {
flag := f.formatFlag(f.Styles.Stashed, f.Symbols.Stashed, f.st.NumStashed)
if flag != "" {
flags = append(flags, flag)
}
}

if !f.Options.HideClean && f.Symbols.Clean != "" {
flags = append(flags, fmt.Sprintf("%s%s", f.Styles.Clean, f.Symbols.Clean))
if !f.Options.HideClean {
// Handle clean symbol separately since it doesn't have a count
if f.Symbols.Clean != "" {
flags = append(flags, fmt.Sprintf("%s%s", f.Styles.Clean, f.Symbols.Clean))
} else if !f.Options.HideFlagCountIfEmptySymbol {
// When symbol is empty but we don't want to hide, there's no count to show for clean flag
// so we just skip it (nothing meaningful to display)
}
}

if len(flags) != 0 {
return f.Styles.Clear + strings.Join(flags, " ")
}
}

if f.st.NumStaged != 0 && f.Symbols.Staged != "" {
flags = append(flags, f.formatFlag(f.Styles.Staged, f.Symbols.Staged, f.st.NumStaged))
if f.st.NumStaged != 0 {
flag := f.formatFlag(f.Styles.Staged, f.Symbols.Staged, f.st.NumStaged)
if flag != "" {
flags = append(flags, flag)
}
}

if f.st.NumConflicts != 0 && f.Symbols.Conflict != "" {
flags = append(flags, f.formatFlag(f.Styles.Conflict, f.Symbols.Conflict, f.st.NumConflicts))
if f.st.NumConflicts != 0 {
flag := f.formatFlag(f.Styles.Conflict, f.Symbols.Conflict, f.st.NumConflicts)
if flag != "" {
flags = append(flags, flag)
}
}

if f.st.NumModified != 0 && f.Symbols.Modified != "" {
flags = append(flags, f.formatFlag(f.Styles.Modified, f.Symbols.Modified, f.st.NumModified))
if f.st.NumModified != 0 {
flag := f.formatFlag(f.Styles.Modified, f.Symbols.Modified, f.st.NumModified)
if flag != "" {
flags = append(flags, flag)
}
}

if f.st.NumStashed != 0 && f.Symbols.Stashed != "" {
flags = append(flags, f.formatFlag(f.Styles.Stashed, f.Symbols.Stashed, f.st.NumStashed))
if f.st.NumStashed != 0 {
flag := f.formatFlag(f.Styles.Stashed, f.Symbols.Stashed, f.st.NumStashed)
if flag != "" {
flags = append(flags, flag)
}
}

if f.st.NumUntracked != 0 && f.Symbols.Untracked != "" {
flags = append(flags, f.formatFlag(f.Styles.Untracked, f.Symbols.Untracked, f.st.NumUntracked))
if f.st.NumUntracked != 0 {
flag := f.formatFlag(f.Styles.Untracked, f.Symbols.Untracked, f.st.NumUntracked)
if flag != "" {
flags = append(flags, flag)
}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code would be much simpler if formatFlag mehod was:

func (f *Formater) appendFlag(flags []string, style, symbol string, count int) []string

It would be called like that for each flag kind:

flags = f.appendFlag(flags, f.Styles.Stashed, f.Symbols.Stashed, f.st.NumStashed)

and appendFlag method would take care of handling all cases with both flag-related options

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored the code to use the suggested appendFlag method approach in commit 883c536. The method signature is func (f *Formater) appendFlag(flags []string, style, symbol string, count int) []string as suggested, and it handles both flag-related options.

}

if len(flags) > 0 {
Expand Down
142 changes: 141 additions & 1 deletion tmux/formater_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,7 @@ func TestFlagsWithEmptySymbols(t *testing.T) {
name string
styles styles
symbols symbols
options options
st *gitstatus.Status
want string
}{
Expand All @@ -998,6 +999,9 @@ func TestFlagsWithEmptySymbols(t *testing.T) {
Modified: "SymbolMod",
Stashed: "", // empty symbol should hide this flag
},
options: options{
HideFlagCountIfEmptySymbol: true, // Use old behavior for this test
},
st: &gitstatus.Status{
NumStashed: 5,
Porcelain: gitstatus.Porcelain{
Expand All @@ -1017,6 +1021,9 @@ func TestFlagsWithEmptySymbols(t *testing.T) {
Modified: "", // empty symbol should hide this flag
Stashed: "SymbolStash",
},
options: options{
HideFlagCountIfEmptySymbol: true, // Use old behavior for this test
},
st: &gitstatus.Status{
NumStashed: 1,
Porcelain: gitstatus.Porcelain{
Expand All @@ -1036,6 +1043,9 @@ func TestFlagsWithEmptySymbols(t *testing.T) {
Staged: "", // empty symbol should hide this flag
Stashed: "SymbolStash",
},
options: options{
HideFlagCountIfEmptySymbol: true, // Use old behavior for this test
},
st: &gitstatus.Status{
NumStashed: 1,
Porcelain: gitstatus.Porcelain{
Expand All @@ -1055,6 +1065,9 @@ func TestFlagsWithEmptySymbols(t *testing.T) {
Untracked: "", // empty symbol should hide this flag
Stashed: "SymbolStash",
},
options: options{
HideFlagCountIfEmptySymbol: true, // Use old behavior for this test
},
st: &gitstatus.Status{
NumStashed: 1,
Porcelain: gitstatus.Porcelain{
Expand All @@ -1074,6 +1087,9 @@ func TestFlagsWithEmptySymbols(t *testing.T) {
Conflict: "", // empty symbol should hide this flag
Stashed: "SymbolStash",
},
options: options{
HideFlagCountIfEmptySymbol: true, // Use old behavior for this test
},
st: &gitstatus.Status{
NumStashed: 1,
Porcelain: gitstatus.Porcelain{
Expand All @@ -1093,6 +1109,9 @@ func TestFlagsWithEmptySymbols(t *testing.T) {
Clean: "", // empty symbol should hide this flag
Stashed: "SymbolStash",
},
options: options{
HideFlagCountIfEmptySymbol: true, // Use old behavior for this test
},
st: &gitstatus.Status{
IsClean: true,
NumStashed: 1,
Expand All @@ -1109,6 +1128,9 @@ func TestFlagsWithEmptySymbols(t *testing.T) {
Clean: "SymbolClean",
Stashed: "", // empty symbol should hide this flag
},
options: options{
HideFlagCountIfEmptySymbol: true, // Use old behavior for this test
},
st: &gitstatus.Status{
IsClean: true,
NumStashed: 1,
Expand All @@ -1134,6 +1156,9 @@ func TestFlagsWithEmptySymbols(t *testing.T) {
Untracked: "",
Stashed: "",
},
options: options{
HideFlagCountIfEmptySymbol: true, // Use old behavior for this test
},
st: &gitstatus.Status{
IsClean: false,
NumStashed: 1,
Expand All @@ -1150,7 +1175,122 @@ func TestFlagsWithEmptySymbols(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f := &Formater{
Config: Config{Styles: tt.styles, Symbols: tt.symbols},
Config: Config{Styles: tt.styles, Symbols: tt.symbols, Options: tt.options},
st: tt.st,
}

compareStrings(t, tt.want, f.flags())
})
}
}
func TestFlagsWithEmptySymbolsNewBehavior(t *testing.T) {
tests := []struct {
name string
styles styles
symbols symbols
options options
st *gitstatus.Status
want string
}{
{
name: "empty stashed symbol shows count only (new behavior)",
styles: styles{
Clear: "StyleClear",
Modified: "StyleMod",
Stashed: "StyleStash",
},
symbols: symbols{
Modified: "SymbolMod",
Stashed: "", // empty symbol should show count only
},
options: options{
HideFlagCountIfEmptySymbol: false, // Use new behavior
},
st: &gitstatus.Status{
NumStashed: 5,
Porcelain: gitstatus.Porcelain{
NumModified: 2,
},
},
want: "StyleClear" + "StyleModSymbolMod2 StyleStash5",
},
{
name: "empty modified symbol shows count only (new behavior)",
styles: styles{
Clear: "StyleClear",
Modified: "StyleMod",
Stashed: "StyleStash",
},
symbols: symbols{
Modified: "", // empty symbol should show count only
Stashed: "SymbolStash",
},
options: options{
HideFlagCountIfEmptySymbol: false, // Use new behavior
},
st: &gitstatus.Status{
NumStashed: 1,
Porcelain: gitstatus.Porcelain{
NumModified: 2,
},
},
want: "StyleClear" + "StyleMod2 StyleStashSymbolStash1",
},
{
name: "multiple empty symbols show counts only (new behavior)",
styles: styles{
Clear: "StyleClear",
Staged: "StyleStaged",
Modified: "StyleMod",
Untracked: "StyleUntracked",
},
symbols: symbols{
Staged: "", // empty symbols should show counts only
Modified: "",
Untracked: "",
},
options: options{
HideFlagCountIfEmptySymbol: false, // Use new behavior
},
st: &gitstatus.Status{
Porcelain: gitstatus.Porcelain{
NumStaged: 3,
NumModified: 2,
NumUntracked: 4,
},
},
want: "StyleClear" + "StyleStaged3 StyleMod2 StyleUntracked4",
},
{
name: "mixed symbols and empty symbols (new behavior)",
styles: styles{
Clear: "StyleClear",
Staged: "StyleStaged",
Modified: "StyleMod",
Stashed: "StyleStash",
},
symbols: symbols{
Staged: "SymbolStaged", // normal symbol
Modified: "", // empty symbol should show count only
Stashed: "SymbolStash", // normal symbol
},
options: options{
HideFlagCountIfEmptySymbol: false, // Use new behavior
},
st: &gitstatus.Status{
NumStashed: 1,
Porcelain: gitstatus.Porcelain{
NumStaged: 3,
NumModified: 2,
},
},
want: "StyleClear" + "StyleStagedSymbolStaged3 StyleMod2 StyleStashSymbolStash1",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f := &Formater{
Config: Config{Styles: tt.styles, Symbols: tt.symbols, Options: tt.options},
st: tt.st,
}

Expand Down