diff --git a/pkg/commands/commit_file.go b/pkg/commands/commit_file.go new file mode 100644 index 000000000..5910ccfec --- /dev/null +++ b/pkg/commands/commit_file.go @@ -0,0 +1,13 @@ +package commands + +// CommitFile : A git commit file +type CommitFile struct { + Sha string + Name string + DisplayString string +} + +// GetDisplayStrings is a function. +func (f *CommitFile) GetDisplayStrings() []string { + return []string{f.DisplayString} +} diff --git a/pkg/commands/git.go b/pkg/commands/git.go index 43f78a28f..3e0bf2441 100644 --- a/pkg/commands/git.go +++ b/pkg/commands/git.go @@ -796,3 +796,15 @@ func (c *GitCommand) CherryPickCommits(commits []*Commit) error { return c.OSCommand.RunPreparedCommand(cmd) } + +// CommitFiles get the specified commit files +func (c *GitCommand) CommitFiles(commitID string) (string, error) { + cmd := fmt.Sprintf("git show --pretty= --name-only %s", commitID) + return c.OSCommand.RunCommandWithOutput(cmd) +} + +// ShowCommitFile get the diff of specified commit file +func (c *GitCommand) ShowCommitFile(commitID, file string) (string, error) { + cmd := fmt.Sprintf("git show --color %s -- %s", commitID, file) + return c.OSCommand.RunCommandWithOutput(cmd) +} diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go new file mode 100644 index 000000000..1f2b33d4b --- /dev/null +++ b/pkg/gui/commit_files_panel.go @@ -0,0 +1,53 @@ +package gui + +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands" +) + +func (gui *Gui) getSelectedCommitFile(g *gocui.Gui) *commands.CommitFile { + selectedLine := gui.State.Panels.CommitFiles.SelectedLine + if selectedLine == -1 { + return nil + } + + return gui.State.CommitFiles[selectedLine] +} + +func (gui *Gui) handleCommitFileSelect(g *gocui.Gui, v *gocui.View) error { + commitFile := gui.getSelectedCommitFile(g) + if commitFile == nil { + return gui.renderString(g, "commit files", gui.Tr.SLocalize("NoCommiteFiles")) + } + + if err := gui.focusPoint(0, gui.State.Panels.CommitFiles.SelectedLine, v); err != nil { + return err + } + commitText, err := gui.GitCommand.ShowCommitFile(commitFile.Sha, commitFile.Name) + if err != nil { + return err + } + return gui.renderString(g, "main", commitText) +} + +func (gui *Gui) handleCommitFilesNextLine(g *gocui.Gui, v *gocui.View) error { + panelState := gui.State.Panels.CommitFiles + gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.CommitFiles), false) + + return gui.handleCommitFileSelect(gui.g, v) +} + +func (gui *Gui) handleCommitFilesPrevLine(g *gocui.Gui, v *gocui.View) error { + panelState := gui.State.Panels.CommitFiles + gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.CommitFiles), true) + + return gui.handleCommitFileSelect(gui.g, v) +} + +func (gui *Gui) handleSwitchToCommitsPanel(g *gocui.Gui, v *gocui.View) error { + commitsView, err := g.View("commits") + if err != nil { + return err + } + return gui.switchFocus(g, v, commitsView) +} diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go index 2154ad5c9..e1d520be1 100644 --- a/pkg/gui/commits_panel.go +++ b/pkg/gui/commits_panel.go @@ -3,6 +3,7 @@ package gui import ( "fmt" "strconv" + "strings" "github.com/go-errors/errors" @@ -437,3 +438,38 @@ func (gui *Gui) HandlePasteCommits(g *gocui.Gui, v *gocui.View) error { }) }, nil) } + +func (gui *Gui) handleSwitchToCommitFilesPanel(g *gocui.Gui, v *gocui.View) error { + commit := gui.getSelectedCommit(g) + if commit == nil { + return nil + } + + commitfileView, err := g.View("commit files") + if err != nil { + return err + } + + files, err := gui.GitCommand.CommitFiles(commit.Sha) + if err != nil { + return gui.createErrorPanel(g, err.Error()) + } + + gui.State.Panels.CommitFiles = &commitFilesPanelState{SelectedLine: 0} + gui.State.CommitFiles = make([]*commands.CommitFile, 0) + + if files == "" { + gui.State.Panels.CommitFiles.SelectedLine = -1 + } + + for _, file := range strings.Split(strings.TrimRight(files, "\n"), "\n") { + gui.State.CommitFiles = append(gui.State.CommitFiles, &commands.CommitFile{ + Sha: commit.Sha, + Name: file, + DisplayString: file, + }) + } + + gui.renderString(g, "commit files", files) + return gui.switchFocus(g, v, commitfileView) +} diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 89b99a919..f156a6d60 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -114,14 +114,19 @@ type menuPanelState struct { SelectedLine int } +type commitFilesPanelState struct { + SelectedLine int +} + type panelStates struct { - Files *filePanelState - Branches *branchPanelState - Commits *commitPanelState - Stash *stashPanelState - Menu *menuPanelState - Staging *stagingPanelState - Merging *mergingPanelState + Files *filePanelState + Branches *branchPanelState + Commits *commitPanelState + Stash *stashPanelState + Menu *menuPanelState + Staging *stagingPanelState + Merging *mergingPanelState + CommitFiles *commitFilesPanelState } type guiState struct { @@ -129,6 +134,7 @@ type guiState struct { Branches []*commands.Branch Commits []*commands.Commit StashEntries []*commands.StashEntry + CommitFiles []*commands.CommitFile PreviousView string Platform commands.Platform Updating bool @@ -352,6 +358,14 @@ func (gui *Gui) layout(g *gocui.Gui) error { branchesView.FgColor = gocui.ColorWhite } + if v, err := g.SetView("commit files", 0, commitsBranchesBoundary+panelSpacing, leftSideWidth, commitsStashBoundary, gocui.TOP|gocui.BOTTOM); err != nil { + if err.Error() != "unknown view" { + return err + } + v.Title = gui.Tr.SLocalize("CommitFiles") + v.FgColor = gocui.ColorWhite + } + commitsView, err := g.SetView("commits", 0, commitsBranchesBoundary+panelSpacing, leftSideWidth, commitsStashBoundary, gocui.TOP|gocui.BOTTOM) if err != nil { if err.Error() != "unknown view" { diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index eb3e765c4..4fdc3d969 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -388,6 +388,12 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { Modifier: gocui.ModNone, Handler: gui.HandlePasteCommits, Description: gui.Tr.SLocalize("pasteCommits"), + }, { + ViewName: "commits", + Key: gocui.KeyEnter, + Modifier: gocui.ModNone, + Handler: gui.handleSwitchToCommitFilesPanel, + Description: gui.Tr.SLocalize("CommitFiles"), }, { ViewName: "stash", Key: gocui.KeySpace, @@ -441,6 +447,12 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { Key: gocui.MouseLeft, Modifier: gocui.ModNone, Handler: gui.handleDonate, + }, { + ViewName: "commit files", + Key: gocui.KeyEsc, + Modifier: gocui.ModNone, + Handler: gui.handleSwitchToCommitsPanel, + Description: gui.Tr.SLocalize("CommitsTitle"), }, } @@ -459,12 +471,13 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { nextLine func(*gocui.Gui, *gocui.View) error focus func(*gocui.Gui, *gocui.View) error }{ - "menu": {prevLine: gui.handleMenuPrevLine, nextLine: gui.handleMenuNextLine, focus: gui.handleMenuSelect}, - "files": {prevLine: gui.handleFilesPrevLine, nextLine: gui.handleFilesNextLine, focus: gui.handleFilesFocus}, - "branches": {prevLine: gui.handleBranchesPrevLine, nextLine: gui.handleBranchesNextLine, focus: gui.handleBranchSelect}, - "commits": {prevLine: gui.handleCommitsPrevLine, nextLine: gui.handleCommitsNextLine, focus: gui.handleCommitSelect}, - "stash": {prevLine: gui.handleStashPrevLine, nextLine: gui.handleStashNextLine, focus: gui.handleStashEntrySelect}, - "status": {focus: gui.handleStatusSelect}, + "menu": {prevLine: gui.handleMenuPrevLine, nextLine: gui.handleMenuNextLine, focus: gui.handleMenuSelect}, + "files": {prevLine: gui.handleFilesPrevLine, nextLine: gui.handleFilesNextLine, focus: gui.handleFilesFocus}, + "branches": {prevLine: gui.handleBranchesPrevLine, nextLine: gui.handleBranchesNextLine, focus: gui.handleBranchSelect}, + "commits": {prevLine: gui.handleCommitsPrevLine, nextLine: gui.handleCommitsNextLine, focus: gui.handleCommitSelect}, + "stash": {prevLine: gui.handleStashPrevLine, nextLine: gui.handleStashNextLine, focus: gui.handleStashEntrySelect}, + "status": {focus: gui.handleStatusSelect}, + "commit files": {prevLine: gui.handleCommitFilesPrevLine, nextLine: gui.handleCommitFilesNextLine}, } for viewName, functions := range listPanelMap { diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go index dcb58c7de..9cf58144a 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -95,6 +95,8 @@ func (gui *Gui) newLineFocused(g *gocui.Gui, v *gocui.View) error { return gui.handleBranchSelect(g, v) case "commits": return gui.handleCommitSelect(g, v) + case "commit files": + return gui.handleCommitFileSelect(g, v) case "stash": return gui.handleStashEntrySelect(g, v) case "confirmation": diff --git a/pkg/i18n/dutch.go b/pkg/i18n/dutch.go index 9c0b63b90..57afcc74b 100644 --- a/pkg/i18n/dutch.go +++ b/pkg/i18n/dutch.go @@ -643,6 +643,12 @@ func addDutch(i18nObject *i18n.Bundle) error { }, &i18n.Message{ ID: "CherryPickingStatus", Other: "cherry-picking", + }, &i18n.Message{ + ID: "CommitFiles", + Other: "Commit files", + }, &i18n.Message{ + ID: "NoCommiteFiles", + Other: "No files for this commit", }, ) } diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index d397398ae..6acb43f0f 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -666,6 +666,12 @@ func addEnglish(i18nObject *i18n.Bundle) error { }, &i18n.Message{ ID: "CherryPickingStatus", Other: "cherry-picking", + }, &i18n.Message{ + ID: "CommitFiles", + Other: "Commit files", + }, &i18n.Message{ + ID: "NoCommiteFiles", + Other: "No files for this commit", }, ) } diff --git a/pkg/i18n/polish.go b/pkg/i18n/polish.go index 8fb7c5e88..4ec11817a 100644 --- a/pkg/i18n/polish.go +++ b/pkg/i18n/polish.go @@ -626,6 +626,12 @@ func addPolish(i18nObject *i18n.Bundle) error { }, &i18n.Message{ ID: "CherryPickingStatus", Other: "cherry-picking", + }, &i18n.Message{ + ID: "CommitFiles", + Other: "Commit files", + }, &i18n.Message{ + ID: "NoCommiteFiles", + Other: "No files for this commit", }, ) }