Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow user to filter the files view to only show untracked files #4226

Merged
merged 1 commit into from
Feb 6, 2025
Merged
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
6 changes: 5 additions & 1 deletion pkg/commands/git_commands/file_loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,17 @@ func NewFileLoader(gitCommon *GitCommon, cmd oscommands.ICmdObjBuilder, config F

type GetStatusFileOptions struct {
NoRenames bool
// If true, we'll show untracked files even if the user has set the config to hide them.
// This is useful for users with bare repos for dotfiles who default to hiding untracked files,
// but want to occasionally see them to `git add` a new file.
ForceShowUntracked bool
}

func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*models.File {
// check if config wants us ignoring untracked files
untrackedFilesSetting := self.config.GetShowUntrackedFiles()

if untrackedFilesSetting == "" {
if opts.ForceShowUntracked || untrackedFilesSetting == "" {
untrackedFilesSetting = "all"
}
untrackedFilesArg := fmt.Sprintf("--untracked-files=%s", untrackedFilesSetting)
Expand Down
21 changes: 19 additions & 2 deletions pkg/gui/controllers/files_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,13 @@ func (self *FilesController) handleStatusFilterPressed() error {
},
Key: 't',
},
{
Label: self.c.Tr.FilterUntrackedFiles,
OnPress: func() error {
return self.setStatusFiltering(filetree.DisplayUntracked)
},
Key: 'T',
},
{
Label: self.c.Tr.ResetFilter,
OnPress: func() error {
Expand All @@ -789,9 +796,19 @@ func (self *FilesController) handleStatusFilterPressed() error {
}

func (self *FilesController) setStatusFiltering(filter filetree.FileTreeDisplayFilter) error {
previousFilter := self.context().GetFilter()

self.context().FileTreeViewModel.SetStatusFilter(filter)
self.c.PostRefreshUpdate(self.context())
return nil

// 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`.
if previousFilter != filter && (previousFilter == filetree.DisplayUntracked || filter == filetree.DisplayUntracked) {
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}, Mode: types.ASYNC})
} else {
self.c.PostRefreshUpdate(self.context())

return nil
}
}

func (self *FilesController) edit(nodes []*filetree.FileNode) error {
Expand Down
4 changes: 3 additions & 1 deletion pkg/gui/controllers/helpers/refresh_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,9 @@ func (self *RefreshHelper) refreshStateFiles() error {
}

files := self.c.Git().Loaders.FileLoader.
GetStatusFiles(git_commands.GetStatusFileOptions{})
GetStatusFiles(git_commands.GetStatusFileOptions{
ForceShowUntracked: self.c.Contexts().Files.ForceShowUntracked(),
})

conflictFileCount := 0
for _, file := range files {
Expand Down
8 changes: 8 additions & 0 deletions pkg/gui/filetree/file_tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const (
DisplayStaged
DisplayUnstaged
DisplayTracked
DisplayUntracked
// this shows files with merge conflicts
DisplayConflicted
)
Expand All @@ -40,6 +41,7 @@ type IFileTree interface {

FilterFiles(test func(*models.File) bool) []*models.File
SetStatusFilter(filter FileTreeDisplayFilter)
ForceShowUntracked() bool
Get(index int) *FileNode
GetFile(path string) *models.File
GetAllItems() []*FileNode
Expand Down Expand Up @@ -87,13 +89,19 @@ func (self *FileTree) getFilesForDisplay() []*models.File {
return self.FilterFiles(func(file *models.File) bool { return file.HasUnstagedChanges })
case DisplayTracked:
return self.FilterFiles(func(file *models.File) bool { return file.Tracked })
case DisplayUntracked:
return self.FilterFiles(func(file *models.File) bool { return !file.Tracked })
case DisplayConflicted:
return self.FilterFiles(func(file *models.File) bool { return file.HasMergeConflicts })
default:
panic(fmt.Sprintf("Unexpected files display filter: %d", self.filter))
}
}

func (self *FileTree) ForceShowUntracked() bool {
return self.filter == DisplayUntracked
}

func (self *FileTree) FilterFiles(test func(*models.File) bool) []*models.File {
return lo.Filter(self.getFiles(), func(file *models.File, _ int) bool { return test(file) })
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/i18n/english.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ type TranslationSet struct {
FilterStagedFiles string
FilterUnstagedFiles string
FilterTrackedFiles string
FilterUntrackedFiles string
ResetFilter string
MergeConflictsTitle string
Checkout string
Expand Down Expand Up @@ -1113,6 +1114,7 @@ func EnglishTranslationSet() *TranslationSet {
FilterStagedFiles: "Show only staged files",
FilterUnstagedFiles: "Show only unstaged files",
FilterTrackedFiles: "Show only tracked files",
FilterUntrackedFiles: "Show only untracked files",
ResetFilter: "Reset filter",
NoChangedFiles: "No changed files",
SoftReset: "Soft reset",
Expand Down
62 changes: 62 additions & 0 deletions pkg/integration/tests/filter_and_search/filter_by_file_status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package filter_and_search

import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)

var FilterByFileStatus = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Filtering to show untracked files in repo that hides them by default",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {
},
SetupRepo: func(shell *Shell) {
// need to set untracked files to not be displayed in git config
shell.SetConfig("status.showUntrackedFiles", "no")

shell.CreateFileAndAdd("file-tracked", "foo")

shell.Commit("first commit")

shell.CreateFile("file-untracked", "bar")
shell.UpdateFile("file-tracked", "baz")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
Focus().
Lines(
Contains(`file-tracked`).IsSelected(),
).
Press(keys.Files.OpenStatusFilter).
Tap(func() {
t.ExpectPopup().Menu().
Title(Equals("Filtering")).
Select(Contains("Show only untracked files")).
Confirm()
}).
Lines(
Contains(`file-untracked`).IsSelected(),
).
Press(keys.Files.OpenStatusFilter).
Tap(func() {
t.ExpectPopup().Menu().
Title(Equals("Filtering")).
Select(Contains("Show only tracked files")).
Confirm()
}).
Lines(
Contains(`file-tracked`).IsSelected(),
).
Press(keys.Files.OpenStatusFilter).
Tap(func() {
t.ExpectPopup().Menu().
Title(Equals("Filtering")).
Select(Contains("Reset filter")).
Confirm()
}).
Lines(
Contains(`file-tracked`).IsSelected(),
)
},
})
1 change: 1 addition & 0 deletions pkg/integration/tests/test_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ var tests = []*components.IntegrationTest{
file.StageChildrenRangeSelect,
file.StageDeletedRangeSelect,
file.StageRangeSelect,
filter_and_search.FilterByFileStatus,
filter_and_search.FilterCommitFiles,
filter_and_search.FilterFiles,
filter_and_search.FilterFuzzy,
Expand Down