From 40fbce91ce636eb037c2221946261ce4f4bf4317 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 29 Mar 2020 14:34:17 +1100 Subject: [PATCH] add new diff mode WIP WIP WIP WIP WIP WIP WIP --- docs/Config.md | 1 + pkg/commands/git.go | 5 - pkg/commands/remote_branch.go | 4 + pkg/commands/stash_entry.go | 6 + pkg/config/app_config.go | 1 + pkg/gui/branches_panel.go | 6 +- pkg/gui/commit_files_panel.go | 16 +- pkg/gui/commits_panel.go | 21 ++- pkg/gui/diffing.go | 189 ++++++++++++++++++++++++ pkg/gui/discard_changes_menu_panel.go | 2 +- pkg/gui/files_panel.go | 42 +++--- pkg/gui/filtering_menu_panel.go | 10 +- pkg/gui/global_handlers.go | 8 + pkg/gui/gui.go | 14 +- pkg/gui/keybindings.go | 9 +- pkg/gui/layout.go | 4 +- pkg/gui/merge_panel.go | 6 +- pkg/gui/patch_building_panel.go | 4 +- pkg/gui/patch_options_panel.go | 2 +- pkg/gui/presentation/branches.go | 14 +- pkg/gui/presentation/commit_files.go | 15 +- pkg/gui/presentation/commits.go | 35 ++--- pkg/gui/presentation/files.go | 20 ++- pkg/gui/presentation/reflog_commits.go | 18 ++- pkg/gui/presentation/remote_branches.go | 15 +- pkg/gui/presentation/remotes.go | 15 +- pkg/gui/presentation/stash_entries.go | 15 +- pkg/gui/presentation/tags.go | 15 +- pkg/gui/quitting.go | 6 + pkg/gui/reflog_panel.go | 6 +- pkg/gui/remote_branches_panel.go | 13 +- pkg/gui/remotes_panel.go | 6 +- pkg/gui/staging_panel.go | 4 +- pkg/gui/stash_panel.go | 12 +- pkg/gui/status_panel.go | 4 + pkg/gui/tags_panel.go | 6 +- pkg/i18n/english.go | 30 ++++ pkg/theme/theme.go | 2 + 38 files changed, 465 insertions(+), 136 deletions(-) create mode 100644 pkg/gui/diffing.go diff --git a/docs/Config.md b/docs/Config.md index f57f761a7..e1d0cb689 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -90,6 +90,7 @@ Default path for the config file: undo: 'z' redo: '' filteringMenu: + diffingMenu: '\' status: checkForUpdate: 'u' recentRepos: '' diff --git a/pkg/commands/git.go b/pkg/commands/git.go index 6bf74b864..5958886c3 100644 --- a/pkg/commands/git.go +++ b/pkg/commands/git.go @@ -1021,11 +1021,6 @@ func (c *GitCommand) ResetSoft(ref string) error { return c.OSCommand.RunCommand("git reset --soft " + ref) } -// DiffCommits show diff between commits -func (c *GitCommand) DiffCommits(sha1, sha2 string) (string, error) { - return c.OSCommand.RunCommandWithOutput("git diff --color=%s --stat -p %s %s", c.colorArg(), sha1, sha2) -} - // CreateFixupCommit creates a commit that fixes up a previous commit func (c *GitCommand) CreateFixupCommit(sha string) error { return c.OSCommand.RunCommand("git commit --fixup=%s", sha) diff --git a/pkg/commands/remote_branch.go b/pkg/commands/remote_branch.go index 0435a050f..ca39ac4c1 100644 --- a/pkg/commands/remote_branch.go +++ b/pkg/commands/remote_branch.go @@ -5,3 +5,7 @@ type RemoteBranch struct { Name string RemoteName string } + +func (r *RemoteBranch) FullName() string { + return r.RemoteName + "/" + r.Name +} diff --git a/pkg/commands/stash_entry.go b/pkg/commands/stash_entry.go index 94e4417d4..eb70693ef 100644 --- a/pkg/commands/stash_entry.go +++ b/pkg/commands/stash_entry.go @@ -1,7 +1,13 @@ package commands +import "fmt" + // StashEntry : A git stash entry type StashEntry struct { Index int Name string } + +func (s *StashEntry) RefName() string { + return fmt.Sprintf("stash@{%d}", s.Index) +} diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index 360aee9e1..72e10b095 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -321,6 +321,7 @@ keybinding: undo: 'z' redo: '' filteringMenu: + diffingMenu: '\' status: checkForUpdate: 'u' recentRepos: '' diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go index e2c09a4d8..c3bbcb059 100644 --- a/pkg/gui/branches_panel.go +++ b/pkg/gui/branches_panel.go @@ -42,6 +42,10 @@ func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error { branch := gui.getSelectedBranch() v.FocusPoint(0, gui.State.Panels.Branches.SelectedLine) + if gui.inDiffMode() { + return gui.renderDiff() + } + cmd := gui.OSCommand.ExecutableFromString( gui.GitCommand.GetBranchGraphCmdStr(branch.Name), ) @@ -85,7 +89,7 @@ func (gui *Gui) renderLocalBranchesWithSelection() error { branchesView := gui.getBranchesView() gui.refreshSelectedLine(&gui.State.Panels.Branches.SelectedLine, len(gui.State.Branches)) - displayStrings := presentation.GetBranchListDisplayStrings(gui.State.Branches, gui.State.ScreenMode != SCREEN_NORMAL) + displayStrings := presentation.GetBranchListDisplayStrings(gui.State.Branches, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Diff.Ref) gui.renderDisplayStrings(branchesView, displayStrings) if gui.g.CurrentView() == branchesView { if err := gui.handleBranchSelect(gui.g, branchesView); err != nil { diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index 810a732ec..4870876c0 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -7,7 +7,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/presentation" ) -func (gui *Gui) getSelectedCommitFile(g *gocui.Gui) *commands.CommitFile { +func (gui *Gui) getSelectedCommitFile() *commands.CommitFile { selectedLine := gui.State.Panels.CommitFiles.SelectedLine if selectedLine == -1 { return nil @@ -34,7 +34,7 @@ func (gui *Gui) handleCommitFileSelect(g *gocui.Gui, v *gocui.View) error { gui.handleEscapeLineByLinePanel() } - commitFile := gui.getSelectedCommitFile(g) + commitFile := gui.getSelectedCommitFile() if commitFile == nil { gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) return nil @@ -99,7 +99,7 @@ func (gui *Gui) refreshCommitFilesView() error { return err } - commit := gui.getSelectedCommit(gui.g) + commit := gui.getSelectedCommit() if commit == nil { return nil } @@ -113,14 +113,14 @@ func (gui *Gui) refreshCommitFilesView() error { gui.refreshSelectedLine(&gui.State.Panels.CommitFiles.SelectedLine, len(gui.State.CommitFiles)) commitsFileView := gui.getCommitFilesView() - displayStrings := presentation.GetCommitFileListDisplayStrings(gui.State.CommitFiles) + displayStrings := presentation.GetCommitFileListDisplayStrings(gui.State.CommitFiles, gui.State.Diff.Ref) gui.renderDisplayStrings(commitsFileView, displayStrings) return gui.handleCommitFileSelect(gui.g, commitsFileView) } func (gui *Gui) handleOpenOldCommitFile(g *gocui.Gui, v *gocui.View) error { - file := gui.getSelectedCommitFile(g) + file := gui.getSelectedCommitFile() return gui.openFile(file.Name) } @@ -129,7 +129,7 @@ func (gui *Gui) handleToggleFileForPatch(g *gocui.Gui, v *gocui.View) error { return err } - commitFile := gui.getSelectedCommitFile(g) + commitFile := gui.getSelectedCommitFile() if commitFile == nil { gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) return nil @@ -167,7 +167,7 @@ func (gui *Gui) startPatchManager() error { diffMap[commitFile.Name] = commitText } - commit := gui.getSelectedCommit(gui.g) + commit := gui.getSelectedCommit() if commit == nil { return errors.New("No commit selected") } @@ -185,7 +185,7 @@ func (gui *Gui) enterCommitFile(selectedLineIdx int) error { return err } - commitFile := gui.getSelectedCommitFile(gui.g) + commitFile := gui.getSelectedCommitFile() if commitFile == nil { gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) return nil diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go index d2bfd4b63..cda71eb42 100644 --- a/pkg/gui/commits_panel.go +++ b/pkg/gui/commits_panel.go @@ -12,7 +12,7 @@ import ( // list panel functions -func (gui *Gui) getSelectedCommit(g *gocui.Gui) *commands.Commit { +func (gui *Gui) getSelectedCommit() *commands.Commit { selectedLine := gui.State.Panels.Commits.SelectedLine if selectedLine == -1 { return nil @@ -49,16 +49,15 @@ func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error { gui.getSecondaryView().Title = "Custom Patch" gui.handleEscapeLineByLinePanel() - commit := gui.getSelectedCommit(g) + commit := gui.getSelectedCommit() if commit == nil { return gui.newStringTask("main", gui.Tr.SLocalize("NoCommitsThisBranch")) } v.FocusPoint(0, gui.State.Panels.Commits.SelectedLine) - // if specific diff mode is on, don't show diff - if gui.State.Panels.Commits.SpecificDiffMode { - return nil + if gui.inDiffMode() { + return gui.renderDiff() } cmd := gui.OSCommand.ExecutableFromString( @@ -509,7 +508,7 @@ func (gui *Gui) handleCreateFixupCommit(g *gocui.Gui, v *gocui.View) error { return err } - commit := gui.getSelectedCommit(g) + commit := gui.getSelectedCommit() if commit == nil { return nil } @@ -533,7 +532,7 @@ func (gui *Gui) handleSquashAllAboveFixupCommits(g *gocui.Gui, v *gocui.View) er return err } - commit := gui.getSelectedCommit(g) + commit := gui.getSelectedCommit() if commit == nil { return nil } @@ -555,7 +554,7 @@ func (gui *Gui) handleTagCommit(g *gocui.Gui, v *gocui.View) error { // TODO: bring up menu asking if you want to make a lightweight or annotated tag // if annotated, switch to a subprocess to create the message - commit := gui.getSelectedCommit(g) + commit := gui.getSelectedCommit() if commit == nil { return nil } @@ -573,7 +572,7 @@ func (gui *Gui) handleCreateLightweightTag(commitSha string) error { } func (gui *Gui) handleCheckoutCommit(g *gocui.Gui, v *gocui.View) error { - commit := gui.getSelectedCommit(g) + commit := gui.getSelectedCommit() if commit == nil { return nil } @@ -587,7 +586,7 @@ func (gui *Gui) renderBranchCommitsWithSelection() error { commitsView := gui.getCommitsView() gui.refreshSelectedLine(&gui.State.Panels.Commits.SelectedLine, len(gui.State.Commits)) - displayStrings := presentation.GetCommitListDisplayStrings(gui.State.Commits, gui.State.ScreenMode != SCREEN_NORMAL, gui.cherryPickedCommitShaMap()) + displayStrings := presentation.GetCommitListDisplayStrings(gui.State.Commits, gui.State.ScreenMode != SCREEN_NORMAL, gui.cherryPickedCommitShaMap(), gui.State.Diff.Ref) gui.renderDisplayStrings(commitsView, displayStrings) if gui.g.CurrentView() == commitsView && commitsView.Context == "branch-commits" { if err := gui.handleCommitSelect(gui.g, commitsView); err != nil { @@ -649,7 +648,7 @@ func (gui *Gui) handlePrevCommitsTab(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleCreateCommitResetMenu(g *gocui.Gui, v *gocui.View) error { - commit := gui.getSelectedCommit(g) + commit := gui.getSelectedCommit() if commit == nil { return gui.createErrorPanel(gui.Tr.SLocalize("NoCommitsThisBranch")) } diff --git a/pkg/gui/diffing.go b/pkg/gui/diffing.go new file mode 100644 index 000000000..a42b6b335 --- /dev/null +++ b/pkg/gui/diffing.go @@ -0,0 +1,189 @@ +package gui + +import ( + "fmt" + "strings" + + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands" +) + +func (gui *Gui) inDiffMode() bool { + return gui.State.Diff.Ref != "" +} + +func (gui *Gui) exitDiffMode() error { + gui.State.Diff = DiffState{} + return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) +} + +func (gui *Gui) renderDiff() error { + filterArg := "" + if gui.inFilterMode() { + filterArg = fmt.Sprintf(" -- %s", gui.State.FilterPath) + } + + cmd := gui.OSCommand.ExecutableFromString( + fmt.Sprintf("git diff --color %s %s", gui.diffStr(), filterArg), + ) + if err := gui.newPtyTask("main", cmd); err != nil { + gui.Log.Error(err) + } + return nil +} + +// currentDiffTerminals returns the current diff terminals of the currently selected item. +// in the case of a branch it returns both the branch and it's upstream name, +// which becomes an option when you bring up the diff menu, but when you're just +// flicking through branches it will be using the local branch name. +func (gui *Gui) currentDiffTerminals() []string { + names := []string{} + switch gui.g.CurrentView().Name() { + case "files": + file, err := gui.getSelectedFile() + if err == nil { + names = append(names, file.Name) + } + case "commitFiles": + file := gui.getSelectedCommitFile() + if file != nil { + names = append(names, file.Name) + } + case "commits": + var commit *commands.Commit + switch gui.getCommitsView().Context { + case "reflog-commits": + commit = gui.getSelectedReflogCommit() + case "branch-commits": + commit = gui.getSelectedCommit() + } + if commit != nil { + names = append(names, commit.Sha) + } + case "stash": + entry := gui.getSelectedStashEntry() + if entry != nil { + names = append(names, entry.RefName()) + } + case "branches": + switch gui.getBranchesView().Context { + case "local-branches": + branch := gui.getSelectedBranch() + if branch != nil { + names = append(names, branch.Name) + if branch.UpstreamName != "" { + names = append(names, branch.UpstreamName) + } + } + case "remotes": + remote := gui.getSelectedRemote() + if remote != nil { + names = append(names, remote.Name) + } + case "remote-branches": + remoteBranch := gui.getSelectedRemoteBranch() + if remoteBranch != nil { + names = append(names, remoteBranch.FullName()) + } + case "tags": + tag := gui.getSelectedTag() + if tag != nil { + names = append(names, tag.Name) + } + } + } + return names +} + +func (gui *Gui) currentDiffTerminal() string { + names := gui.currentDiffTerminals() + if len(names) == 0 { + return "HEAD" + } + return names[0] +} + +func (gui *Gui) diffStr() string { + left := gui.State.Diff.Ref + right := gui.currentDiffTerminal() + if gui.State.Diff.Reverse { + left, right = right, left + } + return fmt.Sprintf("%s %s", left, right) +} + +func (gui *Gui) handleCreateDiffingMenuPanel(g *gocui.Gui, v *gocui.View) error { + if gui.popupPanelFocused() { + return nil + } + + names := gui.currentDiffTerminals() + + menuItems := []*menuItem{} + for _, name := range names { + name := name + menuItems = append(menuItems, []*menuItem{ + { + displayString: fmt.Sprintf("%s %s", gui.Tr.SLocalize("diffFrom"), name), + onPress: func() error { + gui.State.Diff.Ref = name + gui.State.Diff.Reverse = false + // can scope this down based on current view but too lazy right now + return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + }, + }, + { + displayString: fmt.Sprintf("%s %s", gui.Tr.SLocalize("diffTo"), name), + onPress: func() error { + gui.State.Diff.Ref = name + gui.State.Diff.Reverse = true + // can scope this down based on current view but too lazy right now + return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + }, + }, + }...) + } + + menuItems = append(menuItems, []*menuItem{ + { + displayString: gui.Tr.SLocalize("enterRefToDiffFrom"), + onPress: func() error { + return gui.createPromptPanel(gui.g, v, gui.Tr.SLocalize("enteRefName"), "", func(g *gocui.Gui, promptView *gocui.View) error { + gui.State.Diff.Ref = strings.TrimSpace(promptView.Buffer()) + gui.State.Diff.Reverse = false + return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + }) + }, + }, + { + displayString: gui.Tr.SLocalize("enterRefToDiffTo"), + onPress: func() error { + return gui.createPromptPanel(gui.g, v, gui.Tr.SLocalize("enteRefName"), "", func(g *gocui.Gui, promptView *gocui.View) error { + gui.State.Diff.Ref = strings.TrimSpace(promptView.Buffer()) + gui.State.Diff.Reverse = true + return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + }) + }, + }, + }...) + + menuItems = append(menuItems, &menuItem{ + displayString: gui.Tr.SLocalize("swapDiff"), + onPress: func() error { + gui.State.Diff.Reverse = !gui.State.Diff.Reverse + return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + }, + }) + + if gui.inDiffMode() { + menuItems = append(menuItems, &menuItem{ + displayString: gui.Tr.SLocalize("exitDiffMode"), + onPress: func() error { + gui.State.Diff = DiffState{} + return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + }, + }) + } + + return gui.createMenu(gui.Tr.SLocalize("DiffingMenuTitle"), menuItems, createMenuOptions{showCancel: true}) +} diff --git a/pkg/gui/discard_changes_menu_panel.go b/pkg/gui/discard_changes_menu_panel.go index 0f01ad964..0d3b6989b 100644 --- a/pkg/gui/discard_changes_menu_panel.go +++ b/pkg/gui/discard_changes_menu_panel.go @@ -5,7 +5,7 @@ import ( ) func (gui *Gui) handleCreateDiscardMenu(g *gocui.Gui, v *gocui.View) error { - file, err := gui.getSelectedFile(g) + file, err := gui.getSelectedFile() if err != nil { if err != gui.Errors.ErrNoFiles { return err diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go index 7cb094837..620453d5a 100644 --- a/pkg/gui/files_panel.go +++ b/pkg/gui/files_panel.go @@ -17,7 +17,7 @@ import ( // list panel functions -func (gui *Gui) getSelectedFile(g *gocui.Gui) (*commands.File, error) { +func (gui *Gui) getSelectedFile() (*commands.File, error) { selectedLine := gui.State.Panels.Files.SelectedLine if selectedLine == -1 { return &commands.File{}, gui.Errors.ErrNoFiles @@ -27,7 +27,7 @@ func (gui *Gui) getSelectedFile(g *gocui.Gui) (*commands.File, error) { } func (gui *Gui) selectFile(alreadySelected bool) error { - file, err := gui.getSelectedFile(gui.g) + file, err := gui.getSelectedFile() if err != nil { if err != gui.Errors.ErrNoFiles { return err @@ -39,12 +39,6 @@ func (gui *Gui) selectFile(alreadySelected bool) error { gui.getFilesView().FocusPoint(0, gui.State.Panels.Files.SelectedLine) - if file.HasInlineMergeConflicts { - gui.getMainView().Title = gui.Tr.SLocalize("MergeConflictsTitle") - gui.State.SplitMainPanel = false - return gui.refreshMergePanel() - } - if !alreadySelected { if err := gui.resetOrigin(gui.getMainView()); err != nil { return err @@ -54,6 +48,16 @@ func (gui *Gui) selectFile(alreadySelected bool) error { } } + if gui.inDiffMode() { + return gui.renderDiff() + } + + if file.HasInlineMergeConflicts { + gui.getMainView().Title = gui.Tr.SLocalize("MergeConflictsTitle") + gui.State.SplitMainPanel = false + return gui.refreshMergePanel() + } + if file.HasStagedChanges && file.HasUnstagedChanges { gui.State.SplitMainPanel = true gui.getMainView().Title = gui.Tr.SLocalize("UnstagedChanges") @@ -89,7 +93,7 @@ func (gui *Gui) refreshFiles() error { gui.State.RefreshingFilesMutex.Unlock() }() - selectedFile, _ := gui.getSelectedFile(gui.g) + selectedFile, _ := gui.getSelectedFile() filesView := gui.getFilesView() if filesView == nil { @@ -101,11 +105,11 @@ func (gui *Gui) refreshFiles() error { } gui.g.Update(func(g *gocui.Gui) error { - displayStrings := presentation.GetFileListDisplayStrings(gui.State.Files) + displayStrings := presentation.GetFileListDisplayStrings(gui.State.Files, gui.State.Diff.Ref) gui.renderDisplayStrings(filesView, displayStrings) if g.CurrentView() == filesView || (g.CurrentView() == gui.getMainView() && g.CurrentView().Context == "merging") { - newSelectedFile, _ := gui.getSelectedFile(gui.g) + newSelectedFile, _ := gui.getSelectedFile() alreadySelected := newSelectedFile.Name == selectedFile.Name return gui.selectFile(alreadySelected) } @@ -140,7 +144,7 @@ func (gui *Gui) trackedFiles() []*commands.File { } func (gui *Gui) stageSelectedFile(g *gocui.Gui) error { - file, err := gui.getSelectedFile(g) + file, err := gui.getSelectedFile() if err != nil { return err } @@ -152,7 +156,7 @@ func (gui *Gui) handleEnterFile(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) enterFile(forceSecondaryFocused bool, selectedLineIdx int) error { - file, err := gui.getSelectedFile(gui.g) + file, err := gui.getSelectedFile() if err != nil { if err != gui.Errors.ErrNoFiles { return err @@ -173,7 +177,7 @@ func (gui *Gui) enterFile(forceSecondaryFocused bool, selectedLineIdx int) error } func (gui *Gui) handleFilePress(g *gocui.Gui, v *gocui.View) error { - file, err := gui.getSelectedFile(g) + file, err := gui.getSelectedFile() if err != nil { if err == gui.Errors.ErrNoFiles { return nil @@ -237,7 +241,7 @@ func (gui *Gui) handleStageAll(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleIgnoreFile(g *gocui.Gui, v *gocui.View) error { - file, err := gui.getSelectedFile(gui.g) + file, err := gui.getSelectedFile() if err != nil { return gui.surfaceError(err) } @@ -345,7 +349,7 @@ func (gui *Gui) editFile(filename string) error { } func (gui *Gui) handleFileEdit(g *gocui.Gui, v *gocui.View) error { - file, err := gui.getSelectedFile(g) + file, err := gui.getSelectedFile() if err != nil { return gui.surfaceError(err) } @@ -354,7 +358,7 @@ func (gui *Gui) handleFileEdit(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleFileOpen(g *gocui.Gui, v *gocui.View) error { - file, err := gui.getSelectedFile(g) + file, err := gui.getSelectedFile() if err != nil { return gui.surfaceError(err) } @@ -379,7 +383,7 @@ func (gui *Gui) refreshStateFiles() error { } func (gui *Gui) catSelectedFile(g *gocui.Gui) (string, error) { - item, err := gui.getSelectedFile(g) + item, err := gui.getSelectedFile() if err != nil { if err != gui.Errors.ErrNoFiles { return "", err @@ -489,7 +493,7 @@ func (gui *Gui) pushFiles(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleSwitchToMerge(g *gocui.Gui, v *gocui.View) error { - file, err := gui.getSelectedFile(g) + file, err := gui.getSelectedFile() if err != nil { if err != gui.Errors.ErrNoFiles { return gui.surfaceError(err) diff --git a/pkg/gui/filtering_menu_panel.go b/pkg/gui/filtering_menu_panel.go index 316ea95d0..856b71572 100644 --- a/pkg/gui/filtering_menu_panel.go +++ b/pkg/gui/filtering_menu_panel.go @@ -7,16 +7,20 @@ import ( "github.com/jesseduffield/gocui" ) -func (gui *Gui) handleCreateScopingMenuPanel(g *gocui.Gui, v *gocui.View) error { +func (gui *Gui) handleCreateFilteringMenuPanel(g *gocui.Gui, v *gocui.View) error { + if gui.popupPanelFocused() { + return nil + } + fileName := "" switch v.Name() { case "files": - file, err := gui.getSelectedFile(gui.g) + file, err := gui.getSelectedFile() if err == nil { fileName = file.Name } case "commitFiles": - file := gui.getSelectedCommitFile(gui.g) + file := gui.getSelectedCommitFile() if file != nil { fileName = file.Name } diff --git a/pkg/gui/global_handlers.go b/pkg/gui/global_handlers.go index 5f0752a6c..5df00d56f 100644 --- a/pkg/gui/global_handlers.go +++ b/pkg/gui/global_handlers.go @@ -144,6 +144,14 @@ func (gui *Gui) handleInfoClick(g *gocui.Gui, v *gocui.View) error { } } + if gui.inDiffMode() { + if width-cx <= len(gui.Tr.SLocalize("(reset)")) { + return gui.exitDiffMode() + } else { + return nil + } + } + if cx <= len(gui.Tr.SLocalize("Donate")) { return gui.OSCommand.OpenLink("https://github.com/sponsors/jesseduffield") } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 62e18f8fd..2fc029b64 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -136,9 +136,8 @@ type tagsPanelState struct { } type commitPanelState struct { - SelectedLine int - SpecificDiffMode bool - LimitCommits bool + SelectedLine int + LimitCommits bool } type reflogCommitPanelState struct { @@ -187,8 +186,8 @@ const ( // if ref is blank we're not diffing anything type DiffState struct { - Ref string - Left bool + Ref string + Reverse bool } type guiState struct { @@ -231,10 +230,12 @@ type guiState struct { } func (gui *Gui) resetState() { - // we carry over the filter path + // we carry over the filter path and diff state prevFilterPath := "" + prevDiff := DiffState{} if gui.State != nil { prevFilterPath = gui.State.FilterPath + prevDiff = gui.State.Diff } gui.State = &guiState{ @@ -266,6 +267,7 @@ func (gui *Gui) resetState() { SideView: nil, Ptmx: nil, FilterPath: prevFilterPath, + Diff: prevDiff, } } diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 486ea9a31..5ee8466d3 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -978,9 +978,16 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { ViewName: "", Key: gui.getKey("universal.filteringMenu"), Modifier: gocui.ModNone, - Handler: gui.handleCreateScopingMenuPanel, + Handler: gui.handleCreateFilteringMenuPanel, Description: gui.Tr.SLocalize("openScopingMenu"), }, + { + ViewName: "", + Key: gui.getKey("universal.diffingMenu"), + Modifier: gocui.ModNone, + Handler: gui.handleCreateDiffingMenuPanel, + Description: gui.Tr.SLocalize("openDiffingMenu"), + }, { ViewName: "secondary", Key: gocui.MouseWheelUp, diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index 1e9046441..62b1555c2 100644 --- a/pkg/gui/layout.go +++ b/pkg/gui/layout.go @@ -150,7 +150,9 @@ func (gui *Gui) layout(g *gocui.Gui) error { donate := color.New(color.FgMagenta, color.Underline).Sprint(gui.Tr.SLocalize("Donate")) information = donate + " " + information } - if gui.inFilterMode() { + if gui.inDiffMode() { + information = utils.ColoredString(fmt.Sprintf("%s %s %s", gui.Tr.SLocalize("showingGitDiff"), gui.diffStr(), utils.ColoredString(gui.Tr.SLocalize("(reset)"), color.Underline)), color.FgMagenta, color.Bold) + } else if gui.inFilterMode() { information = utils.ColoredString(fmt.Sprintf("%s '%s' %s", gui.Tr.SLocalize("filteringBy"), gui.State.FilterPath, utils.ColoredString(gui.Tr.SLocalize("(reset)"), color.Underline)), color.FgRed, color.Bold) } else if len(gui.State.CherryPickedCommits) > 0 { information = utils.ColoredString(fmt.Sprintf("%d commits copied", len(gui.State.CherryPickedCommits)), color.FgCyan) diff --git a/pkg/gui/merge_panel.go b/pkg/gui/merge_panel.go index 877d4fa9d..4d9a258fc 100644 --- a/pkg/gui/merge_panel.go +++ b/pkg/gui/merge_panel.go @@ -104,7 +104,7 @@ func (gui *Gui) isIndexToDelete(i int, conflict commands.Conflict, pick string) } func (gui *Gui) resolveConflict(g *gocui.Gui, conflict commands.Conflict, pick string) error { - gitFile, err := gui.getSelectedFile(g) + gitFile, err := gui.getSelectedFile() if err != nil { return err } @@ -130,7 +130,7 @@ func (gui *Gui) resolveConflict(g *gocui.Gui, conflict commands.Conflict, pick s } func (gui *Gui) pushFileSnapshot(g *gocui.Gui) error { - gitFile, err := gui.getSelectedFile(g) + gitFile, err := gui.getSelectedFile() if err != nil { return err } @@ -147,7 +147,7 @@ func (gui *Gui) handlePopFileSnapshot(g *gocui.Gui, v *gocui.View) error { return nil } prevContent := gui.State.Panels.Merging.EditHistory.Pop().(string) - gitFile, err := gui.getSelectedFile(g) + gitFile, err := gui.getSelectedFile() if err != nil { return err } diff --git a/pkg/gui/patch_building_panel.go b/pkg/gui/patch_building_panel.go index 17f7ad2cb..3e32386ec 100644 --- a/pkg/gui/patch_building_panel.go +++ b/pkg/gui/patch_building_panel.go @@ -16,7 +16,7 @@ func (gui *Gui) refreshPatchBuildingPanel(selectedLineIdx int) error { gui.getSecondaryView().Title = "Custom Patch" // get diff from commit file that's currently selected - commitFile := gui.getSelectedCommitFile(gui.g) + commitFile := gui.getSelectedCommitFile() if commitFile == nil { gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) return nil @@ -56,7 +56,7 @@ func (gui *Gui) handleToggleSelectionForPatch(g *gocui.Gui, v *gocui.View) error } // add range of lines to those set for the file - commitFile := gui.getSelectedCommitFile(gui.g) + commitFile := gui.getSelectedCommitFile() if commitFile == nil { gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) return nil diff --git a/pkg/gui/patch_options_panel.go b/pkg/gui/patch_options_panel.go index 074b4f38e..046f89b68 100644 --- a/pkg/gui/patch_options_panel.go +++ b/pkg/gui/patch_options_panel.go @@ -30,7 +30,7 @@ func (gui *Gui) handleCreatePatchOptionsMenu(g *gocui.Gui, v *gocui.View) error }, } - selectedCommit := gui.getSelectedCommit(gui.g) + selectedCommit := gui.getSelectedCommit() if selectedCommit != nil && gui.GitCommand.PatchManager.CommitSha != selectedCommit.Sha { // adding this option to index 1 menuItems = append( diff --git a/pkg/gui/presentation/branches.go b/pkg/gui/presentation/branches.go index b12ed8ca2..3e5c2d625 100644 --- a/pkg/gui/presentation/branches.go +++ b/pkg/gui/presentation/branches.go @@ -10,23 +10,29 @@ import ( "github.com/jesseduffield/lazygit/pkg/utils" ) -func GetBranchListDisplayStrings(branches []*commands.Branch, fullDescription bool) [][]string { +func GetBranchListDisplayStrings(branches []*commands.Branch, fullDescription bool, diffName string) [][]string { lines := make([][]string, len(branches)) for i := range branches { - lines[i] = getBranchDisplayStrings(branches[i], fullDescription) + diffed := branches[i].Name == diffName + lines[i] = getBranchDisplayStrings(branches[i], fullDescription, diffed) } return lines } // getBranchDisplayStrings returns the display string of branch -func getBranchDisplayStrings(b *commands.Branch, fullDescription bool) []string { +func getBranchDisplayStrings(b *commands.Branch, fullDescription bool, diffed bool) []string { displayName := b.Name if b.DisplayName != "" { displayName = b.DisplayName } - coloredName := utils.ColoredString(displayName, GetBranchColor(b.Name)) + + nameColorAttr := GetBranchColor(b.Name) + if diffed { + nameColorAttr = theme.DiffTerminalColor + } + coloredName := utils.ColoredString(displayName, nameColorAttr) if b.Pushables != "" && b.Pullables != "" && b.Pushables != "?" && b.Pullables != "?" { trackColor := color.FgYellow if b.Pushables == "0" && b.Pullables == "0" { diff --git a/pkg/gui/presentation/commit_files.go b/pkg/gui/presentation/commit_files.go index 4ea0f85db..3f16da965 100644 --- a/pkg/gui/presentation/commit_files.go +++ b/pkg/gui/presentation/commit_files.go @@ -6,21 +6,23 @@ import ( "github.com/jesseduffield/lazygit/pkg/theme" ) -func GetCommitFileListDisplayStrings(branches []*commands.CommitFile) [][]string { - lines := make([][]string, len(branches)) +func GetCommitFileListDisplayStrings(commitFiles []*commands.CommitFile, diffName string) [][]string { + lines := make([][]string, len(commitFiles)) - for i := range branches { - lines[i] = getCommitFileDisplayStrings(branches[i]) + for i := range commitFiles { + diffed := commitFiles[i].Name == diffName + lines[i] = getCommitFileDisplayStrings(commitFiles[i], diffed) } return lines } // getCommitFileDisplayStrings returns the display string of branch -func getCommitFileDisplayStrings(f *commands.CommitFile) []string { +func getCommitFileDisplayStrings(f *commands.CommitFile, diffed bool) []string { yellow := color.New(color.FgYellow) green := color.New(color.FgGreen) defaultColor := color.New(theme.DefaultTextColor) + diffTerminalColor := color.New(theme.DiffTerminalColor) var colour *color.Color switch f.Status { @@ -31,5 +33,8 @@ func getCommitFileDisplayStrings(f *commands.CommitFile) []string { case commands.PART: colour = yellow } + if diffed { + colour = diffTerminalColor + } return []string{colour.Sprint(f.DisplayString)} } diff --git a/pkg/gui/presentation/commits.go b/pkg/gui/presentation/commits.go index 5463cd531..6e54e9b3a 100644 --- a/pkg/gui/presentation/commits.go +++ b/pkg/gui/presentation/commits.go @@ -9,10 +9,10 @@ import ( "github.com/jesseduffield/lazygit/pkg/utils" ) -func GetCommitListDisplayStrings(commits []*commands.Commit, fullDescription bool, cherryPickedCommitShaMap map[string]bool) [][]string { +func GetCommitListDisplayStrings(commits []*commands.Commit, fullDescription bool, cherryPickedCommitShaMap map[string]bool, diffName string) [][]string { lines := make([][]string, len(commits)) - var displayFunc func(*commands.Commit, map[string]bool) []string + var displayFunc func(*commands.Commit, map[string]bool, bool) []string if fullDescription { displayFunc = getFullDescriptionDisplayStringsForCommit } else { @@ -20,20 +20,21 @@ func GetCommitListDisplayStrings(commits []*commands.Commit, fullDescription boo } for i := range commits { - lines[i] = displayFunc(commits[i], cherryPickedCommitShaMap) + diffed := commits[i].Sha == diffName + lines[i] = displayFunc(commits[i], cherryPickedCommitShaMap, diffed) } return lines } -func getFullDescriptionDisplayStringsForCommit(c *commands.Commit, cherryPickedCommitShaMap map[string]bool) []string { +func getFullDescriptionDisplayStringsForCommit(c *commands.Commit, cherryPickedCommitShaMap map[string]bool, diffed bool) []string { red := color.New(color.FgRed) yellow := color.New(color.FgYellow) green := color.New(color.FgGreen) blue := color.New(color.FgBlue) cyan := color.New(color.FgCyan) defaultColor := color.New(theme.DefaultTextColor) - // magenta := color.New(color.FgMagenta) + diffedColor := color.New(theme.DiffTerminalColor) // for some reason, setting the background to blue pads out the other commits // horizontally. For the sake of accessibility I'm considering this a feature, @@ -56,16 +57,12 @@ func getFullDescriptionDisplayStringsForCommit(c *commands.Commit, cherryPickedC shaColor = defaultColor } - if cherryPickedCommitShaMap[c.Sha] { + if diffed { + shaColor = diffedColor + } else if cherryPickedCommitShaMap[c.Sha] { shaColor = copied } - // for _, entry := range diffEntries { - // if c.Sha == entry.Sha { - // shaColor = magenta - // } - // } - tagString := "" secondColumnString := blue.Sprint(utils.UnixToDate(c.UnixTimestamp)) if c.Action != "" { @@ -80,14 +77,14 @@ func getFullDescriptionDisplayStringsForCommit(c *commands.Commit, cherryPickedC return []string{shaColor.Sprint(c.ShortSha()), secondColumnString, yellow.Sprint(truncatedAuthor), tagString + defaultColor.Sprint(c.Name)} } -func getDisplayStringsForCommit(c *commands.Commit, cherryPickedCommitShaMap map[string]bool) []string { +func getDisplayStringsForCommit(c *commands.Commit, cherryPickedCommitShaMap map[string]bool, diffed bool) []string { red := color.New(color.FgRed) yellow := color.New(color.FgYellow) green := color.New(color.FgGreen) blue := color.New(color.FgBlue) cyan := color.New(color.FgCyan) defaultColor := color.New(theme.DefaultTextColor) - // magenta := color.New(color.FgMagenta) + diffedColor := color.New(theme.DiffTerminalColor) // for some reason, setting the background to blue pads out the other commits // horizontally. For the sake of accessibility I'm considering this a feature, @@ -110,16 +107,12 @@ func getDisplayStringsForCommit(c *commands.Commit, cherryPickedCommitShaMap map shaColor = defaultColor } - if cherryPickedCommitShaMap[c.Sha] { + if diffed { + shaColor = diffedColor + } else if cherryPickedCommitShaMap[c.Sha] { shaColor = copied } - // for _, entry := range diffEntries { - // if c.Sha == entry.Sha { - // shaColor = magenta - // } - // } - actionString := "" tagString := "" if c.Action != "" { diff --git a/pkg/gui/presentation/files.go b/pkg/gui/presentation/files.go index 589e8aecc..3e70617fa 100644 --- a/pkg/gui/presentation/files.go +++ b/pkg/gui/presentation/files.go @@ -3,34 +3,42 @@ package presentation import ( "github.com/fatih/color" "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/theme" ) -func GetFileListDisplayStrings(files []*commands.File) [][]string { +func GetFileListDisplayStrings(files []*commands.File, diffName string) [][]string { lines := make([][]string, len(files)) for i := range files { - lines[i] = getFileDisplayStrings(files[i]) + diffed := files[i].Name == diffName + lines[i] = getFileDisplayStrings(files[i], diffed) } return lines } // getFileDisplayStrings returns the display string of branch -func getFileDisplayStrings(f *commands.File) []string { +func getFileDisplayStrings(f *commands.File, diffed bool) []string { // potentially inefficient to be instantiating these color // objects with each render red := color.New(color.FgRed) green := color.New(color.FgGreen) + diffColor := color.New(theme.DiffTerminalColor) if !f.Tracked && !f.HasStagedChanges { return []string{red.Sprint(f.DisplayString)} } output := green.Sprint(f.DisplayString[0:1]) output += red.Sprint(f.DisplayString[1:3]) - if f.HasUnstagedChanges { - output += red.Sprint(f.Name) + + var restColor *color.Color + if diffed { + restColor = diffColor + } else if f.HasUnstagedChanges { + restColor = red } else { - output += green.Sprint(f.Name) + restColor = green } + output += restColor.Sprint(f.Name) return []string{output} } diff --git a/pkg/gui/presentation/reflog_commits.go b/pkg/gui/presentation/reflog_commits.go index e57560b76..cf3765b1c 100644 --- a/pkg/gui/presentation/reflog_commits.go +++ b/pkg/gui/presentation/reflog_commits.go @@ -7,10 +7,10 @@ import ( "github.com/jesseduffield/lazygit/pkg/utils" ) -func GetReflogCommitListDisplayStrings(commits []*commands.Commit, fullDescription bool) [][]string { +func GetReflogCommitListDisplayStrings(commits []*commands.Commit, fullDescription bool, diffName string) [][]string { lines := make([][]string, len(commits)) - var displayFunc func(*commands.Commit) []string + var displayFunc func(*commands.Commit, bool) []string if fullDescription { displayFunc = getFullDescriptionDisplayStringsForReflogCommit } else { @@ -18,23 +18,27 @@ func GetReflogCommitListDisplayStrings(commits []*commands.Commit, fullDescripti } for i := range commits { - lines[i] = displayFunc(commits[i]) + diffed := commits[i].Sha == diffName + lines[i] = displayFunc(commits[i], diffed) } return lines } -func getFullDescriptionDisplayStringsForReflogCommit(c *commands.Commit) []string { - defaultColor := color.New(theme.DefaultTextColor) +func getFullDescriptionDisplayStringsForReflogCommit(c *commands.Commit, diffed bool) []string { + colorAttr := theme.DefaultTextColor + if diffed { + colorAttr = theme.DiffTerminalColor + } return []string{ utils.ColoredString(c.ShortSha(), color.FgBlue), utils.ColoredString(utils.UnixToDate(c.UnixTimestamp), color.FgMagenta), - defaultColor.Sprint(c.Name), + utils.ColoredString(c.Name, colorAttr), } } -func getDisplayStringsForReflogCommit(c *commands.Commit) []string { +func getDisplayStringsForReflogCommit(c *commands.Commit, diffed bool) []string { defaultColor := color.New(theme.DefaultTextColor) return []string{utils.ColoredString(c.ShortSha(), color.FgBlue), defaultColor.Sprint(c.Name)} diff --git a/pkg/gui/presentation/remote_branches.go b/pkg/gui/presentation/remote_branches.go index d3094c8cb..e52e6d7f3 100644 --- a/pkg/gui/presentation/remote_branches.go +++ b/pkg/gui/presentation/remote_branches.go @@ -2,22 +2,29 @@ package presentation import ( "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/theme" "github.com/jesseduffield/lazygit/pkg/utils" ) -func GetRemoteBranchListDisplayStrings(branches []*commands.RemoteBranch) [][]string { +func GetRemoteBranchListDisplayStrings(branches []*commands.RemoteBranch, diffName string) [][]string { lines := make([][]string, len(branches)) for i := range branches { - lines[i] = getRemoteBranchDisplayStrings(branches[i]) + diffed := branches[i].FullName() == diffName + lines[i] = getRemoteBranchDisplayStrings(branches[i], diffed) } return lines } // getRemoteBranchDisplayStrings returns the display string of branch -func getRemoteBranchDisplayStrings(b *commands.RemoteBranch) []string { - displayName := utils.ColoredString(b.Name, GetBranchColor(b.Name)) +func getRemoteBranchDisplayStrings(b *commands.RemoteBranch, diffed bool) []string { + nameColorAttr := GetBranchColor(b.Name) + if diffed { + nameColorAttr = theme.DiffTerminalColor + } + + displayName := utils.ColoredString(b.Name, nameColorAttr) return []string{displayName} } diff --git a/pkg/gui/presentation/remotes.go b/pkg/gui/presentation/remotes.go index 3adfad858..5ad5f77c8 100644 --- a/pkg/gui/presentation/remotes.go +++ b/pkg/gui/presentation/remotes.go @@ -5,22 +5,29 @@ import ( "github.com/fatih/color" "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/theme" "github.com/jesseduffield/lazygit/pkg/utils" ) -func GetRemoteListDisplayStrings(remotes []*commands.Remote) [][]string { +func GetRemoteListDisplayStrings(remotes []*commands.Remote, diffName string) [][]string { lines := make([][]string, len(remotes)) for i := range remotes { - lines[i] = getRemoteDisplayStrings(remotes[i]) + diffed := remotes[i].Name == diffName + lines[i] = getRemoteDisplayStrings(remotes[i], diffed) } return lines } // getRemoteDisplayStrings returns the display string of branch -func getRemoteDisplayStrings(r *commands.Remote) []string { +func getRemoteDisplayStrings(r *commands.Remote, diffed bool) []string { branchCount := len(r.Branches) - return []string{r.Name, utils.ColoredString(fmt.Sprintf("%d branches", branchCount), color.FgBlue)} + nameColorAttr := theme.DefaultTextColor + if diffed { + nameColorAttr = theme.DiffTerminalColor + } + + return []string{utils.ColoredString(r.Name, nameColorAttr), utils.ColoredString(fmt.Sprintf("%d branches", branchCount), color.FgBlue)} } diff --git a/pkg/gui/presentation/stash_entries.go b/pkg/gui/presentation/stash_entries.go index a5557a433..d1f54cc8a 100644 --- a/pkg/gui/presentation/stash_entries.go +++ b/pkg/gui/presentation/stash_entries.go @@ -2,19 +2,26 @@ package presentation import ( "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/theme" + "github.com/jesseduffield/lazygit/pkg/utils" ) -func GetStashEntryListDisplayStrings(stashEntries []*commands.StashEntry) [][]string { +func GetStashEntryListDisplayStrings(stashEntries []*commands.StashEntry, diffName string) [][]string { lines := make([][]string, len(stashEntries)) for i := range stashEntries { - lines[i] = getStashEntryDisplayStrings(stashEntries[i]) + diffed := stashEntries[i].RefName() == diffName + lines[i] = getStashEntryDisplayStrings(stashEntries[i], diffed) } return lines } // getStashEntryDisplayStrings returns the display string of branch -func getStashEntryDisplayStrings(s *commands.StashEntry) []string { - return []string{s.Name} +func getStashEntryDisplayStrings(s *commands.StashEntry, diffed bool) []string { + attr := theme.DefaultTextColor + if diffed { + attr = theme.DiffTerminalColor + } + return []string{utils.ColoredString(s.Name, attr)} } diff --git a/pkg/gui/presentation/tags.go b/pkg/gui/presentation/tags.go index 13f2b8b59..475c717cc 100644 --- a/pkg/gui/presentation/tags.go +++ b/pkg/gui/presentation/tags.go @@ -2,19 +2,26 @@ package presentation import ( "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/theme" + "github.com/jesseduffield/lazygit/pkg/utils" ) -func GetTagListDisplayStrings(tags []*commands.Tag) [][]string { +func GetTagListDisplayStrings(tags []*commands.Tag, diffName string) [][]string { lines := make([][]string, len(tags)) for i := range tags { - lines[i] = getTagDisplayStrings(tags[i]) + diffed := tags[i].Name == diffName + lines[i] = getTagDisplayStrings(tags[i], diffed) } return lines } // getTagDisplayStrings returns the display string of branch -func getTagDisplayStrings(t *commands.Tag) []string { - return []string{t.Name} +func getTagDisplayStrings(t *commands.Tag, diffed bool) []string { + attr := theme.DefaultTextColor + if diffed { + attr = theme.DiffTerminalColor + } + return []string{utils.ColoredString(t.Name, attr)} } diff --git a/pkg/gui/quitting.go b/pkg/gui/quitting.go index fca71d221..f9ad00177 100644 --- a/pkg/gui/quitting.go +++ b/pkg/gui/quitting.go @@ -38,6 +38,12 @@ func (gui *Gui) quit(v *gocui.View) error { if gui.State.Updating { return gui.createUpdateQuitConfirmation(gui.g, v) } + if gui.inDiffMode() { + return gui.exitDiffMode() + } + if gui.inFilterMode() { + return gui.exitFilterMode() + } if gui.Config.GetUserConfig().GetBool("confirmOnQuit") { return gui.createConfirmationPanel(gui.g, v, true, "", gui.Tr.SLocalize("ConfirmQuit"), func(g *gocui.Gui, v *gocui.View) error { return gocui.ErrQuit diff --git a/pkg/gui/reflog_panel.go b/pkg/gui/reflog_panel.go index 503ffde66..0e69cbbd8 100644 --- a/pkg/gui/reflog_panel.go +++ b/pkg/gui/reflog_panel.go @@ -37,6 +37,10 @@ func (gui *Gui) handleReflogCommitSelect(g *gocui.Gui, v *gocui.View) error { } v.FocusPoint(0, gui.State.Panels.ReflogCommits.SelectedLine) + if gui.inDiffMode() { + return gui.renderDiff() + } + cmd := gui.OSCommand.ExecutableFromString( gui.GitCommand.ShowCmdStr(commit.Sha, gui.State.FilterPath), ) @@ -100,7 +104,7 @@ func (gui *Gui) renderReflogCommitsWithSelection() error { commitsView := gui.getCommitsView() gui.refreshSelectedLine(&gui.State.Panels.ReflogCommits.SelectedLine, len(gui.State.FilteredReflogCommits)) - displayStrings := presentation.GetReflogCommitListDisplayStrings(gui.State.FilteredReflogCommits, gui.State.ScreenMode != SCREEN_NORMAL) + displayStrings := presentation.GetReflogCommitListDisplayStrings(gui.State.FilteredReflogCommits, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Diff.Ref) gui.renderDisplayStrings(commitsView, displayStrings) if gui.g.CurrentView() == commitsView && commitsView.Context == "reflog-commits" { if err := gui.handleReflogCommitSelect(gui.g, commitsView); err != nil { diff --git a/pkg/gui/remote_branches_panel.go b/pkg/gui/remote_branches_panel.go index e5c91b810..0b0349da0 100644 --- a/pkg/gui/remote_branches_panel.go +++ b/pkg/gui/remote_branches_panel.go @@ -32,7 +32,6 @@ func (gui *Gui) handleRemoteBranchSelect(g *gocui.Gui, v *gocui.View) error { gui.getMainView().Title = "Remote Branch" - remote := gui.getSelectedRemote() remoteBranch := gui.getSelectedRemoteBranch() if remoteBranch == nil { return gui.newStringTask("main", "No branches for this remote") @@ -40,10 +39,12 @@ func (gui *Gui) handleRemoteBranchSelect(g *gocui.Gui, v *gocui.View) error { v.FocusPoint(0, gui.State.Panels.RemoteBranches.SelectedLine) - branchName := fmt.Sprintf("%s/%s", remote.Name, remoteBranch.Name) + if gui.inDiffMode() { + return gui.renderDiff() + } cmd := gui.OSCommand.ExecutableFromString( - gui.GitCommand.GetBranchGraphCmdStr(branchName), + gui.GitCommand.GetBranchGraphCmdStr(remoteBranch.FullName()), ) if err := gui.newCmdTask("main", cmd); err != nil { gui.Log.Error(err) @@ -60,7 +61,7 @@ func (gui *Gui) renderRemoteBranchesWithSelection() error { branchesView := gui.getBranchesView() gui.refreshSelectedLine(&gui.State.Panels.RemoteBranches.SelectedLine, len(gui.State.RemoteBranches)) - displayStrings := presentation.GetRemoteBranchListDisplayStrings(gui.State.RemoteBranches) + displayStrings := presentation.GetRemoteBranchListDisplayStrings(gui.State.RemoteBranches, gui.State.Diff.Ref) gui.renderDisplayStrings(branchesView, displayStrings) if gui.g.CurrentView() == branchesView && branchesView.Context == "remote-branches" { if err := gui.handleRemoteBranchSelect(gui.g, branchesView); err != nil { @@ -76,7 +77,7 @@ func (gui *Gui) handleCheckoutRemoteBranch(g *gocui.Gui, v *gocui.View) error { if remoteBranch == nil { return nil } - if err := gui.handleCheckoutRef(remoteBranch.RemoteName+"/"+remoteBranch.Name, handleCheckoutRefOptions{}); err != nil { + if err := gui.handleCheckoutRef(remoteBranch.FullName(), handleCheckoutRefOptions{}); err != nil { return err } return gui.switchBranchesPanelContext("local-branches") @@ -117,7 +118,7 @@ func (gui *Gui) handleSetBranchUpstream(g *gocui.Gui, v *gocui.View) error { "SetUpstreamMessage", Teml{ "checkedOut": checkedOutBranch.Name, - "selected": selectedBranch.RemoteName + "/" + selectedBranch.Name, + "selected": selectedBranch.FullName(), }, ) diff --git a/pkg/gui/remotes_panel.go b/pkg/gui/remotes_panel.go index c8bb9c6fb..58479b93b 100644 --- a/pkg/gui/remotes_panel.go +++ b/pkg/gui/remotes_panel.go @@ -41,6 +41,10 @@ func (gui *Gui) handleRemoteSelect(g *gocui.Gui, v *gocui.View) error { } v.FocusPoint(0, gui.State.Panels.Remotes.SelectedLine) + if gui.inDiffMode() { + return gui.renderDiff() + } + return gui.newStringTask("main", fmt.Sprintf("%s\nUrls:\n%s", utils.ColoredString(remote.Name, color.FgGreen), strings.Join(remote.Urls, "\n"))) } @@ -80,7 +84,7 @@ func (gui *Gui) renderRemotesWithSelection() error { gui.refreshSelectedLine(&gui.State.Panels.Remotes.SelectedLine, len(gui.State.Remotes)) - displayStrings := presentation.GetRemoteListDisplayStrings(gui.State.Remotes) + displayStrings := presentation.GetRemoteListDisplayStrings(gui.State.Remotes, gui.State.Diff.Ref) gui.renderDisplayStrings(branchesView, displayStrings) if gui.g.CurrentView() == branchesView && branchesView.Context == "remotes" { diff --git a/pkg/gui/staging_panel.go b/pkg/gui/staging_panel.go index 1074dfbc1..9db981599 100644 --- a/pkg/gui/staging_panel.go +++ b/pkg/gui/staging_panel.go @@ -19,7 +19,7 @@ func (gui *Gui) refreshStagingPanel(forceSecondaryFocused bool, selectedLineIdx return err } - file, err := gui.getSelectedFile(gui.g) + file, err := gui.getSelectedFile() if err != nil { if err != gui.Errors.ErrNoFiles { return err @@ -125,7 +125,7 @@ func (gui *Gui) handleResetSelection(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) applySelection(reverse bool) error { state := gui.State.Panels.LineByLine - file, err := gui.getSelectedFile(gui.g) + file, err := gui.getSelectedFile() if err != nil { return err } diff --git a/pkg/gui/stash_panel.go b/pkg/gui/stash_panel.go index 67747b80f..cc368be66 100644 --- a/pkg/gui/stash_panel.go +++ b/pkg/gui/stash_panel.go @@ -8,7 +8,7 @@ import ( // list panel functions -func (gui *Gui) getSelectedStashEntry(v *gocui.View) *commands.StashEntry { +func (gui *Gui) getSelectedStashEntry() *commands.StashEntry { selectedLine := gui.State.Panels.Stash.SelectedLine if selectedLine == -1 { return nil @@ -30,12 +30,16 @@ func (gui *Gui) handleStashEntrySelect(g *gocui.Gui, v *gocui.View) error { gui.getMainView().Title = "Stash" - stashEntry := gui.getSelectedStashEntry(v) + stashEntry := gui.getSelectedStashEntry() if stashEntry == nil { return gui.newStringTask("main", gui.Tr.SLocalize("NoStashEntries")) } v.FocusPoint(0, gui.State.Panels.Stash.SelectedLine) + if gui.inDiffMode() { + return gui.renderDiff() + } + cmd := gui.OSCommand.ExecutableFromString( gui.GitCommand.ShowStashEntryCmdStr(stashEntry.Index), ) @@ -53,7 +57,7 @@ func (gui *Gui) refreshStashEntries(g *gocui.Gui) error { stashView := gui.getStashView() - displayStrings := presentation.GetStashEntryListDisplayStrings(gui.State.StashEntries) + displayStrings := presentation.GetStashEntryListDisplayStrings(gui.State.StashEntries, gui.State.Diff.Ref) gui.renderDisplayStrings(stashView, displayStrings) return gui.resetOrigin(stashView) @@ -78,7 +82,7 @@ func (gui *Gui) handleStashDrop(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) stashDo(g *gocui.Gui, v *gocui.View, method string) error { - stashEntry := gui.getSelectedStashEntry(v) + stashEntry := gui.getSelectedStashEntry() if stashEntry == nil { errorMessage := gui.Tr.TemplateLocalize( "NoStashTo", diff --git a/pkg/gui/status_panel.go b/pkg/gui/status_panel.go index 6a21f2926..3b5c6dd05 100644 --- a/pkg/gui/status_panel.go +++ b/pkg/gui/status_panel.go @@ -97,6 +97,10 @@ func (gui *Gui) handleStatusSelect(g *gocui.Gui, v *gocui.View) error { gui.getMainView().Title = "" + if gui.inDiffMode() { + return gui.renderDiff() + } + magenta := color.New(color.FgMagenta) dashboardString := strings.Join( diff --git a/pkg/gui/tags_panel.go b/pkg/gui/tags_panel.go index acda2103f..8de632a8a 100644 --- a/pkg/gui/tags_panel.go +++ b/pkg/gui/tags_panel.go @@ -36,6 +36,10 @@ func (gui *Gui) handleTagSelect(g *gocui.Gui, v *gocui.View) error { } v.FocusPoint(0, gui.State.Panels.Tags.SelectedLine) + if gui.inDiffMode() { + return gui.renderDiff() + } + cmd := gui.OSCommand.ExecutableFromString( gui.GitCommand.GetBranchGraphCmdStr(tag.Name), ) @@ -65,7 +69,7 @@ func (gui *Gui) renderTagsWithSelection() error { branchesView := gui.getBranchesView() gui.refreshSelectedLine(&gui.State.Panels.Tags.SelectedLine, len(gui.State.Tags)) - displayStrings := presentation.GetTagListDisplayStrings(gui.State.Tags) + displayStrings := presentation.GetTagListDisplayStrings(gui.State.Tags, gui.State.Diff.Ref) gui.renderDisplayStrings(branchesView, displayStrings) if gui.g.CurrentView() == branchesView && branchesView.Context == "tags" { if err := gui.handleTagSelect(gui.g, branchesView); err != nil { diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 392813d0b..f01542118 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -1107,6 +1107,36 @@ func addEnglish(i18nObject *i18n.Bundle) error { }, &i18n.Message{ ID: "MustExitFilterModePrompt", Other: "Command not available in filtered mode. Exit filtered mode?", + }, &i18n.Message{ + ID: "diffFrom", + Other: "diff from", + }, &i18n.Message{ + ID: "diffTo", + Other: "diff to", + }, &i18n.Message{ + ID: "enterRefToDiffFrom", + Other: "enter ref to diff from", + }, &i18n.Message{ + ID: "enterRefToDiffTo", + Other: "enter ref to diff to", + }, &i18n.Message{ + ID: "enteRefName", + Other: "enter ref:", + }, &i18n.Message{ + ID: "exitDiffMode", + Other: "exit diff mode", + }, &i18n.Message{ + ID: "DiffingMenuTitle", + Other: "Diffing", + }, &i18n.Message{ + ID: "swapDiff", + Other: "reverse diff direction", + }, &i18n.Message{ + ID: "openDiffingMenu", + Other: "open diff menu", + }, &i18n.Message{ + ID: "showingGitDiff", + Other: "showing git diff:", }, ) } diff --git a/pkg/theme/theme.go b/pkg/theme/theme.go index 04b49a555..ccb6bef08 100644 --- a/pkg/theme/theme.go +++ b/pkg/theme/theme.go @@ -27,6 +27,8 @@ var ( OptionsFgColor color.Attribute OptionsColor gocui.Attribute + + DiffTerminalColor = color.FgMagenta ) // UpdateTheme updates all theme variables