mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-05-12 04:45:47 +02:00
Add author filtering to commit view
This commit introduces a new feature to the commit view, allowing users to filter commits based on the author's name or email address. Similar to the existing path filtering functionality, accessible through <c-s>, this feature allows users to filter the commit history by the currently selected commit's author if the commit view is focused, or by typing in the author's name or email address. This feature adds an entry to the filtering menu, to provide users with a familiar and intuitive experience
This commit is contained in:
parent
329b434915
commit
503422a72e
22 changed files with 292 additions and 27 deletions
|
@ -23,7 +23,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
||||||
| `` + `` | Next screen mode (normal/half/fullscreen) | |
|
| `` + `` | Next screen mode (normal/half/fullscreen) | |
|
||||||
| `` _ `` | Prev screen mode | |
|
| `` _ `` | Prev screen mode | |
|
||||||
| `` ? `` | Open keybindings menu | |
|
| `` ? `` | Open keybindings menu | |
|
||||||
| `` <c-s> `` | View filter-by-path options | View options for filtering the commit log by a file path, so that only commits relating to that path are shown. |
|
| `` <c-s> `` | View filter options | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
| `` W `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` W `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` <c-e> `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` <c-e> `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` q `` | Quit | |
|
| `` q `` | Quit | |
|
||||||
|
|
|
@ -23,7 +23,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
||||||
| `` + `` | 次のスクリーンモード (normal/half/fullscreen) | |
|
| `` + `` | 次のスクリーンモード (normal/half/fullscreen) | |
|
||||||
| `` _ `` | 前のスクリーンモード | |
|
| `` _ `` | 前のスクリーンモード | |
|
||||||
| `` ? `` | メニューを開く | |
|
| `` ? `` | メニューを開く | |
|
||||||
| `` <c-s> `` | View filter-by-path options | View options for filtering the commit log by a file path, so that only commits relating to that path are shown. |
|
| `` <c-s> `` | View filter options | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
| `` W `` | 差分メニューを開く | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` W `` | 差分メニューを開く | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` <c-e> `` | 差分メニューを開く | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` <c-e> `` | 差分メニューを開く | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` q `` | 終了 | |
|
| `` q `` | 終了 | |
|
||||||
|
|
|
@ -23,7 +23,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
||||||
| `` + `` | 다음 스크린 모드 (normal/half/fullscreen) | |
|
| `` + `` | 다음 스크린 모드 (normal/half/fullscreen) | |
|
||||||
| `` _ `` | 이전 스크린 모드 | |
|
| `` _ `` | 이전 스크린 모드 | |
|
||||||
| `` ? `` | 매뉴 열기 | |
|
| `` ? `` | 매뉴 열기 | |
|
||||||
| `` <c-s> `` | View filter-by-path options | View options for filtering the commit log by a file path, so that only commits relating to that path are shown. |
|
| `` <c-s> `` | View filter-by-path options | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
| `` W `` | Diff 메뉴 열기 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` W `` | Diff 메뉴 열기 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` <c-e> `` | Diff 메뉴 열기 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` <c-e> `` | Diff 메뉴 열기 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` q `` | 종료 | |
|
| `` q `` | 종료 | |
|
||||||
|
|
|
@ -23,7 +23,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
||||||
| `` + `` | Volgende scherm modus (normaal/half/groot) | |
|
| `` + `` | Volgende scherm modus (normaal/half/groot) | |
|
||||||
| `` _ `` | Vorige scherm modus | |
|
| `` _ `` | Vorige scherm modus | |
|
||||||
| `` ? `` | Open menu | |
|
| `` ? `` | Open menu | |
|
||||||
| `` <c-s> `` | Bekijk scoping opties | View options for filtering the commit log by a file path, so that only commits relating to that path are shown. |
|
| `` <c-s> `` | Bekijk scoping opties | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
| `` W `` | Open diff menu | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` W `` | Open diff menu | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` <c-e> `` | Open diff menu | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` <c-e> `` | Open diff menu | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` q `` | Quit | |
|
| `` q `` | Quit | |
|
||||||
|
|
|
@ -23,7 +23,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
||||||
| `` + `` | Next screen mode (normal/half/fullscreen) | |
|
| `` + `` | Next screen mode (normal/half/fullscreen) | |
|
||||||
| `` _ `` | Prev screen mode | |
|
| `` _ `` | Prev screen mode | |
|
||||||
| `` ? `` | Open keybindings menu | |
|
| `` ? `` | Open keybindings menu | |
|
||||||
| `` <c-s> `` | View filter-by-path options | View options for filtering the commit log by a file path, so that only commits relating to that path are shown. |
|
| `` <c-s> `` | View filter options | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
| `` W `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` W `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` <c-e> `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` <c-e> `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` q `` | Quit | |
|
| `` q `` | Quit | |
|
||||||
|
|
|
@ -23,7 +23,7 @@ _Связки клавиш_
|
||||||
| `` + `` | Следующий режим экрана (нормальный/полуэкранный/полноэкранный) | |
|
| `` + `` | Следующий режим экрана (нормальный/полуэкранный/полноэкранный) | |
|
||||||
| `` _ `` | Предыдущий режим экрана | |
|
| `` _ `` | Предыдущий режим экрана | |
|
||||||
| `` ? `` | Открыть меню | |
|
| `` ? `` | Открыть меню | |
|
||||||
| `` <c-s> `` | Просмотреть параметры фильтрации по пути | View options for filtering the commit log by a file path, so that only commits relating to that path are shown. |
|
| `` <c-s> `` | Просмотреть параметры фильтрации по пути | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
| `` W `` | Открыть меню сравнении | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` W `` | Открыть меню сравнении | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` <c-e> `` | Открыть меню сравнении | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` <c-e> `` | Открыть меню сравнении | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` q `` | Выйти | |
|
| `` q `` | Выйти | |
|
||||||
|
|
|
@ -23,7 +23,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
||||||
| `` + `` | 下一屏模式(正常/半屏/全屏) | |
|
| `` + `` | 下一屏模式(正常/半屏/全屏) | |
|
||||||
| `` _ `` | 上一屏模式 | |
|
| `` _ `` | 上一屏模式 | |
|
||||||
| `` ? `` | 打开菜单 | |
|
| `` ? `` | 打开菜单 | |
|
||||||
| `` <c-s> `` | 查看按路径过滤选项 | View options for filtering the commit log by a file path, so that only commits relating to that path are shown. |
|
| `` <c-s> `` | 查看按路径过滤选项 | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
| `` W `` | 打开 diff 菜单 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` W `` | 打开 diff 菜单 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` <c-e> `` | 打开 diff 菜单 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` <c-e> `` | 打开 diff 菜单 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` q `` | 退出 | |
|
| `` q `` | 退出 | |
|
||||||
|
|
|
@ -23,7 +23,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
||||||
| `` + `` | 下一個螢幕模式(常規/半螢幕/全螢幕) | |
|
| `` + `` | 下一個螢幕模式(常規/半螢幕/全螢幕) | |
|
||||||
| `` _ `` | 上一個螢幕模式 | |
|
| `` _ `` | 上一個螢幕模式 | |
|
||||||
| `` ? `` | 開啟選單 | |
|
| `` ? `` | 開啟選單 | |
|
||||||
| `` <c-s> `` | 檢視篩選路徑選項 | View options for filtering the commit log by a file path, so that only commits relating to that path are shown. |
|
| `` <c-s> `` | 檢視篩選路徑選項 | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
| `` W `` | 開啟差異比較選單 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` W `` | 開啟差異比較選單 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` <c-e> `` | 開啟差異比較選單 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` <c-e> `` | 開啟差異比較選單 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` q `` | 結束 | |
|
| `` q `` | 結束 | |
|
||||||
|
|
|
@ -64,6 +64,7 @@ func NewCommitLoader(
|
||||||
type GetCommitsOptions struct {
|
type GetCommitsOptions struct {
|
||||||
Limit bool
|
Limit bool
|
||||||
FilterPath string
|
FilterPath string
|
||||||
|
FilterAuthor string
|
||||||
IncludeRebaseCommits bool
|
IncludeRebaseCommits bool
|
||||||
RefName string // e.g. "HEAD" or "my_branch"
|
RefName string // e.g. "HEAD" or "my_branch"
|
||||||
RefForPushedStatus string // the ref to use for determining pushed/unpushed status
|
RefForPushedStatus string // the ref to use for determining pushed/unpushed status
|
||||||
|
@ -664,6 +665,7 @@ func (self *CommitLoader) getLogCmd(opts GetCommitsOptions) oscommands.ICmdObj {
|
||||||
Arg("--oneline").
|
Arg("--oneline").
|
||||||
Arg(prettyFormat).
|
Arg(prettyFormat).
|
||||||
Arg("--abbrev=40").
|
Arg("--abbrev=40").
|
||||||
|
ArgIf(opts.FilterAuthor != "", "--author="+opts.FilterAuthor).
|
||||||
ArgIf(opts.Limit, "-300").
|
ArgIf(opts.Limit, "-300").
|
||||||
ArgIf(opts.FilterPath != "", "--follow").
|
ArgIf(opts.FilterPath != "", "--follow").
|
||||||
Arg("--no-show-signature").
|
Arg("--no-show-signature").
|
||||||
|
|
|
@ -23,7 +23,7 @@ func NewReflogCommitLoader(common *common.Common, cmd oscommands.ICmdObjBuilder)
|
||||||
|
|
||||||
// GetReflogCommits only returns the new reflog commits since the given lastReflogCommit
|
// GetReflogCommits only returns the new reflog commits since the given lastReflogCommit
|
||||||
// if none is passed (i.e. it's value is nil) then we get all the reflog commits
|
// if none is passed (i.e. it's value is nil) then we get all the reflog commits
|
||||||
func (self *ReflogCommitLoader) GetReflogCommits(lastReflogCommit *models.Commit, filterPath string) ([]*models.Commit, bool, error) {
|
func (self *ReflogCommitLoader) GetReflogCommits(lastReflogCommit *models.Commit, filterPath string, filterAuthor string) ([]*models.Commit, bool, error) {
|
||||||
commits := make([]*models.Commit, 0)
|
commits := make([]*models.Commit, 0)
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("log").
|
cmdArgs := NewGitCmd("log").
|
||||||
|
@ -31,6 +31,7 @@ func (self *ReflogCommitLoader) GetReflogCommits(lastReflogCommit *models.Commit
|
||||||
Arg("-g").
|
Arg("-g").
|
||||||
Arg("--abbrev=40").
|
Arg("--abbrev=40").
|
||||||
Arg("--format=%h%x00%ct%x00%gs%x00%p").
|
Arg("--format=%h%x00%ct%x00%gs%x00%p").
|
||||||
|
ArgIf(filterAuthor != "", "--author="+filterAuthor).
|
||||||
ArgIf(filterPath != "", "--follow", "--", filterPath).
|
ArgIf(filterPath != "", "--follow", "--", filterPath).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ func TestGetReflogCommits(t *testing.T) {
|
||||||
runner *oscommands.FakeCmdObjRunner
|
runner *oscommands.FakeCmdObjRunner
|
||||||
lastReflogCommit *models.Commit
|
lastReflogCommit *models.Commit
|
||||||
filterPath string
|
filterPath string
|
||||||
|
filterAuthor string
|
||||||
expectedCommits []*models.Commit
|
expectedCommits []*models.Commit
|
||||||
expectedOnlyObtainedNew bool
|
expectedOnlyObtainedNew bool
|
||||||
expectedError error
|
expectedError error
|
||||||
|
@ -136,6 +137,31 @@ func TestGetReflogCommits(t *testing.T) {
|
||||||
expectedOnlyObtainedNew: true,
|
expectedOnlyObtainedNew: true,
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
testName: "when passing filterAuthor",
|
||||||
|
runner: oscommands.NewFakeRunner(t).
|
||||||
|
ExpectGitArgs([]string{"-c", "log.showSignature=false", "log", "-g", "--abbrev=40", "--format=%h%x00%ct%x00%gs%x00%p", "--author=John Doe <john@doe.com>"}, reflogOutput, nil),
|
||||||
|
|
||||||
|
lastReflogCommit: &models.Commit{
|
||||||
|
Sha: "c3c4b66b64c97ffeecde",
|
||||||
|
Name: "checkout: moving from B to A",
|
||||||
|
Status: models.StatusReflog,
|
||||||
|
UnixTimestamp: 1643150483,
|
||||||
|
Parents: []string{"51baa8c1"},
|
||||||
|
},
|
||||||
|
filterAuthor: "John Doe <john@doe.com>",
|
||||||
|
expectedCommits: []*models.Commit{
|
||||||
|
{
|
||||||
|
Sha: "c3c4b66b64c97ffeecde",
|
||||||
|
Name: "checkout: moving from A to B",
|
||||||
|
Status: models.StatusReflog,
|
||||||
|
UnixTimestamp: 1643150483,
|
||||||
|
Parents: []string{"51baa8c1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedOnlyObtainedNew: true,
|
||||||
|
expectedError: nil,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
testName: "when command returns error",
|
testName: "when command returns error",
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
|
@ -157,7 +183,7 @@ func TestGetReflogCommits(t *testing.T) {
|
||||||
cmd: oscommands.NewDummyCmdObjBuilder(scenario.runner),
|
cmd: oscommands.NewDummyCmdObjBuilder(scenario.runner),
|
||||||
}
|
}
|
||||||
|
|
||||||
commits, onlyObtainednew, err := builder.GetReflogCommits(scenario.lastReflogCommit, scenario.filterPath)
|
commits, onlyObtainednew, err := builder.GetReflogCommits(scenario.lastReflogCommit, scenario.filterPath, scenario.filterAuthor)
|
||||||
assert.Equal(t, scenario.expectedOnlyObtainedNew, onlyObtainednew)
|
assert.Equal(t, scenario.expectedOnlyObtainedNew, onlyObtainednew)
|
||||||
assert.Equal(t, scenario.expectedError, err)
|
assert.Equal(t, scenario.expectedError, err)
|
||||||
t.Logf("actual commits: \n%s", litter.Sdump(commits))
|
t.Logf("actual commits: \n%s", litter.Sdump(commits))
|
||||||
|
|
|
@ -13,6 +13,7 @@ type FilteringMenuAction struct {
|
||||||
|
|
||||||
func (self *FilteringMenuAction) Call() error {
|
func (self *FilteringMenuAction) Call() error {
|
||||||
fileName := ""
|
fileName := ""
|
||||||
|
author := ""
|
||||||
switch self.c.CurrentSideContext() {
|
switch self.c.CurrentSideContext() {
|
||||||
case self.c.Contexts().Files:
|
case self.c.Contexts().Files:
|
||||||
node := self.c.Contexts().Files.GetSelected()
|
node := self.c.Contexts().Files.GetSelected()
|
||||||
|
@ -24,16 +25,36 @@ func (self *FilteringMenuAction) Call() error {
|
||||||
if node != nil {
|
if node != nil {
|
||||||
fileName = node.GetPath()
|
fileName = node.GetPath()
|
||||||
}
|
}
|
||||||
|
case self.c.Contexts().LocalCommits:
|
||||||
|
commit := self.c.Contexts().LocalCommits.GetSelected()
|
||||||
|
if commit != nil {
|
||||||
|
author = fmt.Sprintf("%s <%s>", commit.AuthorName, commit.AuthorEmail)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
menuItems := []*types.MenuItem{}
|
menuItems := []*types.MenuItem{}
|
||||||
|
tooltip := ""
|
||||||
|
if self.c.Modes().Filtering.Active() {
|
||||||
|
tooltip = self.c.Tr.WillCancelExistingFilterTooltip
|
||||||
|
}
|
||||||
|
|
||||||
if fileName != "" {
|
if fileName != "" {
|
||||||
menuItems = append(menuItems, &types.MenuItem{
|
menuItems = append(menuItems, &types.MenuItem{
|
||||||
Label: fmt.Sprintf("%s '%s'", self.c.Tr.FilterBy, fileName),
|
Label: fmt.Sprintf("%s '%s'", self.c.Tr.FilterBy, fileName),
|
||||||
OnPress: func() error {
|
OnPress: func() error {
|
||||||
return self.setFiltering(fileName)
|
return self.setFilteringPath(fileName)
|
||||||
},
|
},
|
||||||
|
Tooltip: tooltip,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if author != "" {
|
||||||
|
menuItems = append(menuItems, &types.MenuItem{
|
||||||
|
Label: fmt.Sprintf("%s '%s'", self.c.Tr.FilterBy, author),
|
||||||
|
OnPress: func() error {
|
||||||
|
return self.setFilteringAuthor(author)
|
||||||
|
},
|
||||||
|
Tooltip: tooltip,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,10 +65,25 @@ func (self *FilteringMenuAction) Call() error {
|
||||||
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetFilePathSuggestionsFunc(),
|
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetFilePathSuggestionsFunc(),
|
||||||
Title: self.c.Tr.EnterFileName,
|
Title: self.c.Tr.EnterFileName,
|
||||||
HandleConfirm: func(response string) error {
|
HandleConfirm: func(response string) error {
|
||||||
return self.setFiltering(strings.TrimSpace(response))
|
return self.setFilteringPath(strings.TrimSpace(response))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
Tooltip: tooltip,
|
||||||
|
})
|
||||||
|
|
||||||
|
menuItems = append(menuItems, &types.MenuItem{
|
||||||
|
Label: self.c.Tr.FilterAuthorOption,
|
||||||
|
OnPress: func() error {
|
||||||
|
return self.c.Prompt(types.PromptOpts{
|
||||||
|
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetAuthorsSuggestionsFunc(),
|
||||||
|
Title: self.c.Tr.EnterAuthor,
|
||||||
|
HandleConfirm: func(response string) error {
|
||||||
|
return self.setFilteringAuthor(strings.TrimSpace(response))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
Tooltip: tooltip,
|
||||||
})
|
})
|
||||||
|
|
||||||
if self.c.Modes().Filtering.Active() {
|
if self.c.Modes().Filtering.Active() {
|
||||||
|
@ -60,9 +96,19 @@ func (self *FilteringMenuAction) Call() error {
|
||||||
return self.c.Menu(types.CreateMenuOptions{Title: self.c.Tr.FilteringMenuTitle, Items: menuItems})
|
return self.c.Menu(types.CreateMenuOptions{Title: self.c.Tr.FilteringMenuTitle, Items: menuItems})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FilteringMenuAction) setFiltering(path string) error {
|
func (self *FilteringMenuAction) setFilteringPath(path string) error {
|
||||||
|
self.c.Modes().Filtering.Reset()
|
||||||
self.c.Modes().Filtering.SetPath(path)
|
self.c.Modes().Filtering.SetPath(path)
|
||||||
|
return self.setFiltering()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FilteringMenuAction) setFilteringAuthor(author string) error {
|
||||||
|
self.c.Modes().Filtering.Reset()
|
||||||
|
self.c.Modes().Filtering.SetAuthor(author)
|
||||||
|
return self.setFiltering()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FilteringMenuAction) setFiltering() error {
|
||||||
repoState := self.c.State().GetRepoState()
|
repoState := self.c.State().GetRepoState()
|
||||||
if repoState.GetScreenMode() == types.SCREEN_NORMAL {
|
if repoState.GetScreenMode() == types.SCREEN_NORMAL {
|
||||||
repoState.SetScreenMode(types.SCREEN_HALF)
|
repoState.SetScreenMode(types.SCREEN_HALF)
|
||||||
|
|
|
@ -72,11 +72,12 @@ func (self *ModeHelper) Statuses() []ModeStatus {
|
||||||
{
|
{
|
||||||
IsActive: self.c.Modes().Filtering.Active,
|
IsActive: self.c.Modes().Filtering.Active,
|
||||||
Description: func() string {
|
Description: func() string {
|
||||||
|
filterContent := lo.Ternary(self.c.Modes().Filtering.GetPath() != "", self.c.Modes().Filtering.GetPath(), self.c.Modes().Filtering.GetAuthor())
|
||||||
return self.withResetButton(
|
return self.withResetButton(
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"%s '%s'",
|
"%s '%s'",
|
||||||
self.c.Tr.FilteringBy,
|
self.c.Tr.FilteringBy,
|
||||||
self.c.Modes().Filtering.GetPath(),
|
filterContent,
|
||||||
),
|
),
|
||||||
style.FgRed,
|
style.FgRed,
|
||||||
)
|
)
|
||||||
|
|
|
@ -317,6 +317,7 @@ func (self *RefreshHelper) refreshCommitsWithLimit() error {
|
||||||
git_commands.GetCommitsOptions{
|
git_commands.GetCommitsOptions{
|
||||||
Limit: self.c.Contexts().LocalCommits.GetLimitCommits(),
|
Limit: self.c.Contexts().LocalCommits.GetLimitCommits(),
|
||||||
FilterPath: self.c.Modes().Filtering.GetPath(),
|
FilterPath: self.c.Modes().Filtering.GetPath(),
|
||||||
|
FilterAuthor: self.c.Modes().Filtering.GetAuthor(),
|
||||||
IncludeRebaseCommits: true,
|
IncludeRebaseCommits: true,
|
||||||
RefName: self.refForLog(),
|
RefName: self.refForLog(),
|
||||||
RefForPushedStatus: checkedOutBranchName,
|
RefForPushedStatus: checkedOutBranchName,
|
||||||
|
@ -342,6 +343,7 @@ func (self *RefreshHelper) refreshSubCommitsWithLimit() error {
|
||||||
git_commands.GetCommitsOptions{
|
git_commands.GetCommitsOptions{
|
||||||
Limit: self.c.Contexts().SubCommits.GetLimitCommits(),
|
Limit: self.c.Contexts().SubCommits.GetLimitCommits(),
|
||||||
FilterPath: self.c.Modes().Filtering.GetPath(),
|
FilterPath: self.c.Modes().Filtering.GetPath(),
|
||||||
|
FilterAuthor: self.c.Modes().Filtering.GetAuthor(),
|
||||||
IncludeRebaseCommits: false,
|
IncludeRebaseCommits: false,
|
||||||
RefName: self.c.Contexts().SubCommits.GetRef().FullRefName(),
|
RefName: self.c.Contexts().SubCommits.GetRef().FullRefName(),
|
||||||
RefToShowDivergenceFrom: self.c.Contexts().SubCommits.GetRefToShowDivergenceFrom(),
|
RefToShowDivergenceFrom: self.c.Contexts().SubCommits.GetRefToShowDivergenceFrom(),
|
||||||
|
@ -438,7 +440,7 @@ func (self *RefreshHelper) refreshBranches(refreshWorktrees bool, keepBranchSele
|
||||||
// which allows us to order them correctly. So if we're filtering we'll just
|
// which allows us to order them correctly. So if we're filtering we'll just
|
||||||
// manually load all the reflog commits here
|
// manually load all the reflog commits here
|
||||||
var err error
|
var err error
|
||||||
reflogCommits, _, err = self.c.Git().Loaders.ReflogCommitLoader.GetReflogCommits(nil, "")
|
reflogCommits, _, err = self.c.Git().Loaders.ReflogCommitLoader.GetReflogCommits(nil, "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.c.Log.Error(err)
|
self.c.Log.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -597,9 +599,9 @@ func (self *RefreshHelper) refreshReflogCommits() error {
|
||||||
lastReflogCommit = model.ReflogCommits[0]
|
lastReflogCommit = model.ReflogCommits[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh := func(stateCommits *[]*models.Commit, filterPath string) error {
|
refresh := func(stateCommits *[]*models.Commit, filterPath string, filterAuthor string) error {
|
||||||
commits, onlyObtainedNewReflogCommits, err := self.c.Git().Loaders.ReflogCommitLoader.
|
commits, onlyObtainedNewReflogCommits, err := self.c.Git().Loaders.ReflogCommitLoader.
|
||||||
GetReflogCommits(lastReflogCommit, filterPath)
|
GetReflogCommits(lastReflogCommit, filterPath, filterAuthor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return self.c.Error(err)
|
return self.c.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -612,12 +614,12 @@ func (self *RefreshHelper) refreshReflogCommits() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := refresh(&model.ReflogCommits, ""); err != nil {
|
if err := refresh(&model.ReflogCommits, "", ""); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.c.Modes().Filtering.Active() {
|
if self.c.Modes().Filtering.Active() {
|
||||||
if err := refresh(&model.FilteredReflogCommits, self.c.Modes().Filtering.GetPath()); err != nil {
|
if err := refresh(&model.FilteredReflogCommits, self.c.Modes().Filtering.GetPath(), self.c.Modes().Filtering.GetAuthor()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -39,6 +39,7 @@ func (self *SubCommitsHelper) ViewSubCommits(opts ViewSubCommitsOpts) error {
|
||||||
git_commands.GetCommitsOptions{
|
git_commands.GetCommitsOptions{
|
||||||
Limit: true,
|
Limit: true,
|
||||||
FilterPath: self.c.Modes().Filtering.GetPath(),
|
FilterPath: self.c.Modes().Filtering.GetPath(),
|
||||||
|
FilterAuthor: self.c.Modes().Filtering.GetAuthor(),
|
||||||
IncludeRebaseCommits: false,
|
IncludeRebaseCommits: false,
|
||||||
RefName: opts.Ref.FullRefName(),
|
RefName: opts.Ref.FullRefName(),
|
||||||
RefForPushedStatus: opts.Ref.FullRefName(),
|
RefForPushedStatus: opts.Ref.FullRefName(),
|
||||||
|
|
|
@ -386,7 +386,7 @@ func (gui *Gui) resetState(startArgs appTypes.StartArgs) types.Context {
|
||||||
Authors: map[string]*models.Author{},
|
Authors: map[string]*models.Author{},
|
||||||
},
|
},
|
||||||
Modes: &types.Modes{
|
Modes: &types.Modes{
|
||||||
Filtering: filtering.New(startArgs.FilterPath),
|
Filtering: filtering.New(startArgs.FilterPath, ""),
|
||||||
CherryPicking: cherrypicking.New(),
|
CherryPicking: cherrypicking.New(),
|
||||||
Diffing: diffing.New(),
|
Diffing: diffing.New(),
|
||||||
MarkedBaseCommit: marked_base_commit.New(),
|
MarkedBaseCommit: marked_base_commit.New(),
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
package filtering
|
package filtering
|
||||||
|
|
||||||
type Filtering struct {
|
type Filtering struct {
|
||||||
path string // the filename that gets passed to git log
|
path string // the filename that gets passed to git log
|
||||||
|
author string // the author that gets passed to git log
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(path string) Filtering {
|
func New(path string, author string) Filtering {
|
||||||
return Filtering{path: path}
|
return Filtering{path: path, author: author}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Filtering) Active() bool {
|
func (m *Filtering) Active() bool {
|
||||||
return m.path != ""
|
return m.path != "" || m.author != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Filtering) Reset() {
|
func (m *Filtering) Reset() {
|
||||||
m.path = ""
|
m.path = ""
|
||||||
|
m.author = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Filtering) SetPath(path string) {
|
func (m *Filtering) SetPath(path string) {
|
||||||
|
@ -23,3 +25,11 @@ func (m *Filtering) SetPath(path string) {
|
||||||
func (m *Filtering) GetPath() string {
|
func (m *Filtering) GetPath() string {
|
||||||
return m.path
|
return m.path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Filtering) SetAuthor(author string) {
|
||||||
|
m.author = author
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Filtering) GetAuthor() string {
|
||||||
|
return m.author
|
||||||
|
}
|
||||||
|
|
|
@ -536,9 +536,13 @@ type TranslationSet struct {
|
||||||
OpenFilteringMenuTooltip string
|
OpenFilteringMenuTooltip string
|
||||||
FilterBy string
|
FilterBy string
|
||||||
ExitFilterMode string
|
ExitFilterMode string
|
||||||
|
ExitFilterModeAuthor string
|
||||||
FilterPathOption string
|
FilterPathOption string
|
||||||
|
FilterAuthorOption string
|
||||||
EnterFileName string
|
EnterFileName string
|
||||||
|
EnterAuthor string
|
||||||
FilteringMenuTitle string
|
FilteringMenuTitle string
|
||||||
|
WillCancelExistingFilterTooltip string
|
||||||
MustExitFilterModeTitle string
|
MustExitFilterModeTitle string
|
||||||
MustExitFilterModePrompt string
|
MustExitFilterModePrompt string
|
||||||
Diff string
|
Diff string
|
||||||
|
@ -1475,13 +1479,16 @@ func EnglishTranslationSet() TranslationSet {
|
||||||
GotoBottom: "Scroll to bottom",
|
GotoBottom: "Scroll to bottom",
|
||||||
FilteringBy: "Filtering by",
|
FilteringBy: "Filtering by",
|
||||||
ResetInParentheses: "(Reset)",
|
ResetInParentheses: "(Reset)",
|
||||||
OpenFilteringMenu: "View filter-by-path options",
|
OpenFilteringMenu: "View filter options",
|
||||||
OpenFilteringMenuTooltip: "View options for filtering the commit log by a file path, so that only commits relating to that path are shown.",
|
OpenFilteringMenuTooltip: "View options for filtering the commit log, so that only commits matching the filter are shown.",
|
||||||
FilterBy: "Filter by",
|
FilterBy: "Filter by",
|
||||||
ExitFilterMode: "Stop filtering by path",
|
ExitFilterMode: "Stop filtering",
|
||||||
FilterPathOption: "Enter path to filter by",
|
FilterPathOption: "Enter path to filter by",
|
||||||
|
FilterAuthorOption: "Enter author to filter by",
|
||||||
EnterFileName: "Enter path:",
|
EnterFileName: "Enter path:",
|
||||||
|
EnterAuthor: "Enter author:",
|
||||||
FilteringMenuTitle: "Filtering",
|
FilteringMenuTitle: "Filtering",
|
||||||
|
WillCancelExistingFilterTooltip: "Note: this will cancel the existing filter",
|
||||||
MustExitFilterModeTitle: "Command not available",
|
MustExitFilterModeTitle: "Command not available",
|
||||||
MustExitFilterModePrompt: "Command not available in filter-by-path mode. Exit filter-by-path mode?",
|
MustExitFilterModePrompt: "Command not available in filter-by-path mode. Exit filter-by-path mode?",
|
||||||
Diff: "Diff",
|
Diff: "Diff",
|
||||||
|
|
70
pkg/integration/tests/filter_by_author/select_author.go
Normal file
70
pkg/integration/tests/filter_by_author/select_author.go
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
package filter_by_author
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var SelectAuthor = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Filter commits using the currently highlighted commit's author when the commit view is active",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {
|
||||||
|
config.AppState.GitLogShowGraph = "never"
|
||||||
|
},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
commonSetup(shell)
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Commits().
|
||||||
|
Focus().
|
||||||
|
SelectedLineIdx(0).
|
||||||
|
Press(keys.Universal.FilteringMenu)
|
||||||
|
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("Filtering")).
|
||||||
|
Select(Contains("Filter by 'Paul Oberstein <paul.oberstein@email.com>'")).
|
||||||
|
Confirm()
|
||||||
|
|
||||||
|
t.Views().Commits().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains("commit 7"),
|
||||||
|
Contains("commit 6"),
|
||||||
|
Contains("commit 5"),
|
||||||
|
Contains("commit 4"),
|
||||||
|
Contains("commit 3"),
|
||||||
|
Contains("commit 2"),
|
||||||
|
Contains("commit 1"),
|
||||||
|
Contains("commit 0"),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().Information().Content(Contains("Filtering by 'Paul Oberstein <paul.oberstein@email.com>'"))
|
||||||
|
|
||||||
|
t.Views().Commits().
|
||||||
|
Press(keys.Universal.FilteringMenu)
|
||||||
|
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("Filtering")).
|
||||||
|
Select(Contains("Stop filtering")).
|
||||||
|
Confirm()
|
||||||
|
|
||||||
|
t.Views().Commits().
|
||||||
|
IsFocused().
|
||||||
|
NavigateToLine(Contains("SK commit 0")).
|
||||||
|
Press(keys.Universal.FilteringMenu)
|
||||||
|
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("Filtering")).
|
||||||
|
Select(Contains("Filter by 'Siegfried Kircheis <siegfried.kircheis@email.com>'")).
|
||||||
|
Confirm()
|
||||||
|
|
||||||
|
t.Views().Commits().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains("commit 0"),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().Information().Content(Contains("Filtering by 'Siegfried Kircheis <siegfried.kircheis@email.com>'"))
|
||||||
|
},
|
||||||
|
})
|
30
pkg/integration/tests/filter_by_author/shared.go
Normal file
30
pkg/integration/tests/filter_by_author/shared.go
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package filter_by_author
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AuthorInfo struct {
|
||||||
|
name string
|
||||||
|
numberOfCommits int
|
||||||
|
}
|
||||||
|
|
||||||
|
func commonSetup(shell *Shell) {
|
||||||
|
authors := []AuthorInfo{{"Yang Wen-li", 3}, {"Siegfried Kircheis", 1}, {"Paul Oberstein", 8}}
|
||||||
|
totalCommits := 0
|
||||||
|
repoStartDaysAgo := 100
|
||||||
|
|
||||||
|
for _, authorInfo := range authors {
|
||||||
|
for i := 0; i < authorInfo.numberOfCommits; i++ {
|
||||||
|
authorEmail := strings.ToLower(strings.ReplaceAll(authorInfo.name, " ", ".")) + "@email.com"
|
||||||
|
commitMessage := fmt.Sprintf("commit %d", i)
|
||||||
|
|
||||||
|
shell.SetAuthor(authorInfo.name, authorEmail)
|
||||||
|
shell.EmptyCommitDaysAgo(commitMessage, repoStartDaysAgo-totalCommits)
|
||||||
|
totalCommits++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
66
pkg/integration/tests/filter_by_author/type_author.go
Normal file
66
pkg/integration/tests/filter_by_author/type_author.go
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
package filter_by_author
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var TypeAuthor = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Filter commits by author using the typed in author",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {
|
||||||
|
},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
commonSetup(shell)
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Status().
|
||||||
|
Focus().
|
||||||
|
Press(keys.Universal.FilteringMenu)
|
||||||
|
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("Filtering")).
|
||||||
|
Select(Contains("Enter author to filter by")).
|
||||||
|
Confirm()
|
||||||
|
|
||||||
|
t.ExpectPopup().Prompt().
|
||||||
|
Title(Equals("Enter author:")).
|
||||||
|
Type("Yang").
|
||||||
|
SuggestionLines(Equals("Yang Wen-li <yang.wen-li@email.com>")).
|
||||||
|
ConfirmFirstSuggestion()
|
||||||
|
|
||||||
|
t.Views().Commits().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains("commit 2"),
|
||||||
|
Contains("commit 1"),
|
||||||
|
Contains("commit 0"),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().Information().Content(Contains("Filtering by 'Yang Wen-li <yang.wen-li@email.com>'"))
|
||||||
|
|
||||||
|
t.Views().Status().
|
||||||
|
Focus().
|
||||||
|
Press(keys.Universal.FilteringMenu)
|
||||||
|
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("Filtering")).
|
||||||
|
Select(Contains("Enter author to filter by")).
|
||||||
|
Confirm()
|
||||||
|
|
||||||
|
t.ExpectPopup().Prompt().
|
||||||
|
Title(Equals("Enter author:")).
|
||||||
|
Type("Siegfried").
|
||||||
|
SuggestionLines(Equals("Siegfried Kircheis <siegfried.kircheis@email.com>")).
|
||||||
|
ConfirmFirstSuggestion()
|
||||||
|
|
||||||
|
t.Views().Commits().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains("commit 0"),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().Information().Content(Contains("Filtering by 'Siegfried Kircheis <siegfried.kircheis@email.com>'"))
|
||||||
|
},
|
||||||
|
})
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/diff"
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/diff"
|
||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/file"
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/file"
|
||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/filter_and_search"
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/filter_and_search"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/filter_by_author"
|
||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/filter_by_path"
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/filter_by_path"
|
||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/interactive_rebase"
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/interactive_rebase"
|
||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/misc"
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/misc"
|
||||||
|
@ -149,6 +150,8 @@ var tests = []*components.IntegrationTest{
|
||||||
filter_and_search.NestedFilter,
|
filter_and_search.NestedFilter,
|
||||||
filter_and_search.NestedFilterTransient,
|
filter_and_search.NestedFilterTransient,
|
||||||
filter_and_search.NewSearch,
|
filter_and_search.NewSearch,
|
||||||
|
filter_by_author.SelectAuthor,
|
||||||
|
filter_by_author.TypeAuthor,
|
||||||
filter_by_path.CliArg,
|
filter_by_path.CliArg,
|
||||||
filter_by_path.SelectFile,
|
filter_by_path.SelectFile,
|
||||||
filter_by_path.TypeFile,
|
filter_by_path.TypeFile,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue