mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-06-02 23:27: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:
commit
fcf30caf40
@ -2,6 +2,7 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
@ -753,6 +754,7 @@ func (self *FilesController) isResolvingConflicts() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *FilesController) handleStatusFilterPressed() error {
|
func (self *FilesController) handleStatusFilterPressed() error {
|
||||||
|
currentFilter := self.context().GetFilter()
|
||||||
return self.c.Menu(types.CreateMenuOptions{
|
return self.c.Menu(types.CreateMenuOptions{
|
||||||
Title: self.c.Tr.FilteringMenuTitle,
|
Title: self.c.Tr.FilteringMenuTitle,
|
||||||
Items: []*types.MenuItem{
|
Items: []*types.MenuItem{
|
||||||
@ -761,44 +763,69 @@ func (self *FilesController) handleStatusFilterPressed() error {
|
|||||||
OnPress: func() error {
|
OnPress: func() error {
|
||||||
return self.setStatusFiltering(filetree.DisplayStaged)
|
return self.setStatusFiltering(filetree.DisplayStaged)
|
||||||
},
|
},
|
||||||
Key: 's',
|
Key: 's',
|
||||||
|
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayStaged),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Label: self.c.Tr.FilterUnstagedFiles,
|
Label: self.c.Tr.FilterUnstagedFiles,
|
||||||
OnPress: func() error {
|
OnPress: func() error {
|
||||||
return self.setStatusFiltering(filetree.DisplayUnstaged)
|
return self.setStatusFiltering(filetree.DisplayUnstaged)
|
||||||
},
|
},
|
||||||
Key: 'u',
|
Key: 'u',
|
||||||
|
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayUnstaged),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Label: self.c.Tr.FilterTrackedFiles,
|
Label: self.c.Tr.FilterTrackedFiles,
|
||||||
OnPress: func() error {
|
OnPress: func() error {
|
||||||
return self.setStatusFiltering(filetree.DisplayTracked)
|
return self.setStatusFiltering(filetree.DisplayTracked)
|
||||||
},
|
},
|
||||||
Key: 't',
|
Key: 't',
|
||||||
|
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayTracked),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Label: self.c.Tr.FilterUntrackedFiles,
|
Label: self.c.Tr.FilterUntrackedFiles,
|
||||||
OnPress: func() error {
|
OnPress: func() error {
|
||||||
return self.setStatusFiltering(filetree.DisplayUntracked)
|
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 {
|
OnPress: func() error {
|
||||||
return self.setStatusFiltering(filetree.DisplayAll)
|
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 {
|
func (self *FilesController) setStatusFiltering(filter filetree.FileTreeDisplayFilter) error {
|
||||||
previousFilter := self.context().GetFilter()
|
previousFilter := self.context().GetFilter()
|
||||||
|
|
||||||
self.context().FileTreeViewModel.SetStatusFilter(filter)
|
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
|
// 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`.
|
// because the untracked files filter applies when running `git status`.
|
||||||
|
@ -588,16 +588,14 @@ func (self *RefreshHelper) refreshStateFiles() error {
|
|||||||
fileTreeViewModel.RWMutex.Lock()
|
fileTreeViewModel.RWMutex.Lock()
|
||||||
|
|
||||||
// only taking over the filter if it hasn't already been set by the user.
|
// 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
|
if conflictFileCount > 0 && prevConflictFileCount == 0 {
|
||||||
// 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 fileTreeViewModel.GetFilter() == filetree.DisplayAll {
|
if fileTreeViewModel.GetFilter() == filetree.DisplayAll {
|
||||||
fileTreeViewModel.SetStatusFilter(filetree.DisplayConflicted)
|
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)
|
fileTreeViewModel.SetStatusFilter(filetree.DisplayAll)
|
||||||
|
self.c.Contexts().Files.GetView().Subtitle = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
self.c.Model().Files = files
|
self.c.Model().Files = files
|
||||||
|
@ -89,7 +89,12 @@ type TranslationSet struct {
|
|||||||
FilterUnstagedFiles string
|
FilterUnstagedFiles string
|
||||||
FilterTrackedFiles string
|
FilterTrackedFiles string
|
||||||
FilterUntrackedFiles string
|
FilterUntrackedFiles string
|
||||||
ResetFilter string
|
NoFilter string
|
||||||
|
FilterLabelStagedFiles string
|
||||||
|
FilterLabelUnstagedFiles string
|
||||||
|
FilterLabelTrackedFiles string
|
||||||
|
FilterLabelUntrackedFiles string
|
||||||
|
FilterLabelConflictingFiles string
|
||||||
MergeConflictsTitle string
|
MergeConflictsTitle string
|
||||||
Checkout string
|
Checkout string
|
||||||
CheckoutTooltip string
|
CheckoutTooltip string
|
||||||
@ -1115,7 +1120,12 @@ func EnglishTranslationSet() *TranslationSet {
|
|||||||
FilterUnstagedFiles: "Show only unstaged files",
|
FilterUnstagedFiles: "Show only unstaged files",
|
||||||
FilterTrackedFiles: "Show only tracked files",
|
FilterTrackedFiles: "Show only tracked files",
|
||||||
FilterUntrackedFiles: "Show only untracked 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",
|
NoChangedFiles: "No changed files",
|
||||||
SoftReset: "Soft reset",
|
SoftReset: "Soft reset",
|
||||||
AlreadyCheckedOutBranch: "You have already checked out this branch",
|
AlreadyCheckedOutBranch: "You have already checked out this branch",
|
||||||
|
@ -25,7 +25,7 @@ var Filter = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Tap(func() {
|
Tap(func() {
|
||||||
t.ExpectPopup().Menu().
|
t.ExpectPopup().Menu().
|
||||||
Title(Equals("Filtering")).
|
Title(Equals("Filtering")).
|
||||||
Select(Contains("Reset filter")).
|
Select(Contains("No filter")).
|
||||||
Confirm()
|
Confirm()
|
||||||
}).
|
}).
|
||||||
Lines(
|
Lines(
|
||||||
|
@ -52,7 +52,7 @@ var FilterByFileStatus = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Tap(func() {
|
Tap(func() {
|
||||||
t.ExpectPopup().Menu().
|
t.ExpectPopup().Menu().
|
||||||
Title(Equals("Filtering")).
|
Title(Equals("Filtering")).
|
||||||
Select(Contains("Reset filter")).
|
Select(Contains("No filter")).
|
||||||
Confirm()
|
Confirm()
|
||||||
}).
|
}).
|
||||||
Lines(
|
Lines(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user