1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-05-29 23:17:32 +02:00

Show files filter status (#4230)

- **PR Description**

This PR contains three improvements to the Files panel filtering:
- it allows the user to switch to a different filter type (or reset the
filter) when we are auto-showing only conflicting files
- it shows the filter menu as radio buttons
- it displays the current filter in the top-right corner of the Files
panel's frame

See the individual commits for details.
This commit is contained in:
Stefan Haller 2025-02-07 09:27:23 +01:00 committed by GitHub
commit fcf30caf40
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 51 additions and 16 deletions

View File

@ -2,6 +2,7 @@ package controllers
import (
"errors"
"fmt"
"strings"
"github.com/jesseduffield/gocui"
@ -753,6 +754,7 @@ func (self *FilesController) isResolvingConflicts() bool {
}
func (self *FilesController) handleStatusFilterPressed() error {
currentFilter := self.context().GetFilter()
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.FilteringMenuTitle,
Items: []*types.MenuItem{
@ -761,44 +763,69 @@ func (self *FilesController) handleStatusFilterPressed() error {
OnPress: func() error {
return self.setStatusFiltering(filetree.DisplayStaged)
},
Key: 's',
Key: 's',
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayStaged),
},
{
Label: self.c.Tr.FilterUnstagedFiles,
OnPress: func() error {
return self.setStatusFiltering(filetree.DisplayUnstaged)
},
Key: 'u',
Key: 'u',
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayUnstaged),
},
{
Label: self.c.Tr.FilterTrackedFiles,
OnPress: func() error {
return self.setStatusFiltering(filetree.DisplayTracked)
},
Key: 't',
Key: 't',
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayTracked),
},
{
Label: self.c.Tr.FilterUntrackedFiles,
OnPress: func() error {
return self.setStatusFiltering(filetree.DisplayUntracked)
},
Key: 'T',
Key: 'T',
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayUntracked),
},
{
Label: self.c.Tr.ResetFilter,
Label: self.c.Tr.NoFilter,
OnPress: func() error {
return self.setStatusFiltering(filetree.DisplayAll)
},
Key: 'r',
Key: 'r',
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayAll),
},
},
})
}
func (self *FilesController) filteringLabel(filter filetree.FileTreeDisplayFilter) string {
switch filter {
case filetree.DisplayAll:
return ""
case filetree.DisplayStaged:
return self.c.Tr.FilterLabelStagedFiles
case filetree.DisplayUnstaged:
return self.c.Tr.FilterLabelUnstagedFiles
case filetree.DisplayTracked:
return self.c.Tr.FilterLabelTrackedFiles
case filetree.DisplayUntracked:
return self.c.Tr.FilterLabelUntrackedFiles
case filetree.DisplayConflicted:
return self.c.Tr.FilterLabelConflictingFiles
}
panic(fmt.Sprintf("Unexpected files display filter: %d", filter))
}
func (self *FilesController) setStatusFiltering(filter filetree.FileTreeDisplayFilter) error {
previousFilter := self.context().GetFilter()
self.context().FileTreeViewModel.SetStatusFilter(filter)
self.c.Contexts().Files.GetView().Subtitle = self.filteringLabel(filter)
// Whenever we switch between untracked and other filters, we need to refresh the files view
// because the untracked files filter applies when running `git status`.

View File

@ -588,16 +588,14 @@ func (self *RefreshHelper) refreshStateFiles() error {
fileTreeViewModel.RWMutex.Lock()
// only taking over the filter if it hasn't already been set by the user.
// Though this does make it impossible for the user to actually say they want to display all if
// conflicts are currently being shown. Hmm. Worth it I reckon. If we need to add some
// extra state here to see if the user's set the filter themselves we can do that, but
// I'd prefer to maintain as little state as possible.
if conflictFileCount > 0 {
if conflictFileCount > 0 && prevConflictFileCount == 0 {
if fileTreeViewModel.GetFilter() == filetree.DisplayAll {
fileTreeViewModel.SetStatusFilter(filetree.DisplayConflicted)
self.c.Contexts().Files.GetView().Subtitle = self.c.Tr.FilterLabelConflictingFiles
}
} else if fileTreeViewModel.GetFilter() == filetree.DisplayConflicted {
} else if conflictFileCount == 0 && fileTreeViewModel.GetFilter() == filetree.DisplayConflicted {
fileTreeViewModel.SetStatusFilter(filetree.DisplayAll)
self.c.Contexts().Files.GetView().Subtitle = ""
}
self.c.Model().Files = files

View File

@ -89,7 +89,12 @@ type TranslationSet struct {
FilterUnstagedFiles string
FilterTrackedFiles string
FilterUntrackedFiles string
ResetFilter string
NoFilter string
FilterLabelStagedFiles string
FilterLabelUnstagedFiles string
FilterLabelTrackedFiles string
FilterLabelUntrackedFiles string
FilterLabelConflictingFiles string
MergeConflictsTitle string
Checkout string
CheckoutTooltip string
@ -1115,7 +1120,12 @@ func EnglishTranslationSet() *TranslationSet {
FilterUnstagedFiles: "Show only unstaged files",
FilterTrackedFiles: "Show only tracked files",
FilterUntrackedFiles: "Show only untracked files",
ResetFilter: "Reset filter",
NoFilter: "No filter",
FilterLabelStagedFiles: "(only staged)",
FilterLabelUnstagedFiles: "(only unstaged)",
FilterLabelTrackedFiles: "(only tracked)",
FilterLabelUntrackedFiles: "(only untracked)",
FilterLabelConflictingFiles: "(only conflicting)",
NoChangedFiles: "No changed files",
SoftReset: "Soft reset",
AlreadyCheckedOutBranch: "You have already checked out this branch",

View File

@ -25,7 +25,7 @@ var Filter = NewIntegrationTest(NewIntegrationTestArgs{
Tap(func() {
t.ExpectPopup().Menu().
Title(Equals("Filtering")).
Select(Contains("Reset filter")).
Select(Contains("No filter")).
Confirm()
}).
Lines(

View File

@ -52,7 +52,7 @@ var FilterByFileStatus = NewIntegrationTest(NewIntegrationTestArgs{
Tap(func() {
t.ExpectPopup().Menu().
Title(Equals("Filtering")).
Select(Contains("Reset filter")).
Select(Contains("No filter")).
Confirm()
}).
Lines(