1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-06-04 23:37:41 +02:00

standardising how list panels deal with cursor movement

This commit is contained in:
Jesse Duffield 2018-12-06 22:18:17 +11:00
parent 99a8b1ae8b
commit ca3afa2a39
9 changed files with 373 additions and 362 deletions

View File

@ -10,127 +10,9 @@ import (
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
func (gui *Gui) handleBranchPress(g *gocui.Gui, v *gocui.View) error { // list panel functions
index := gui.getItemPosition(gui.getBranchesView(g))
if index == 0 {
return gui.createErrorPanel(g, gui.Tr.SLocalize("AlreadyCheckedOutBranch"))
}
branch := gui.getSelectedBranch(gui.getBranchesView(g))
if err := gui.GitCommand.Checkout(branch.Name, false); err != nil {
gui.createErrorPanel(g, err.Error())
}
return gui.refreshSidePanels(g)
}
func (gui *Gui) handleCreatePullRequestPress(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) getSelectedBranch() *commands.Branch {
branch := gui.getSelectedBranch(gui.getBranchesView(g))
pullRequest := commands.NewPullRequest(gui.GitCommand)
if err := pullRequest.Create(branch); err != nil {
return gui.createErrorPanel(g, err.Error())
}
return nil
}
func (gui *Gui) handleForceCheckout(g *gocui.Gui, v *gocui.View) error {
branch := gui.getSelectedBranch(v)
message := gui.Tr.SLocalize("SureForceCheckout")
title := gui.Tr.SLocalize("ForceCheckoutBranch")
return gui.createConfirmationPanel(g, v, title, message, func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.Checkout(branch.Name, true); err != nil {
gui.createErrorPanel(g, err.Error())
}
return gui.refreshSidePanels(g)
}, nil)
}
func (gui *Gui) handleCheckoutByName(g *gocui.Gui, v *gocui.View) error {
gui.createPromptPanel(g, v, gui.Tr.SLocalize("BranchName")+":", func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.Checkout(gui.trimmedContent(v), false); err != nil {
return gui.createErrorPanel(g, err.Error())
}
return gui.refreshSidePanels(g)
})
return nil
}
func (gui *Gui) handleNewBranch(g *gocui.Gui, v *gocui.View) error {
branch := gui.State.Branches[0]
message := gui.Tr.TemplateLocalize(
"NewBranchNameBranchOff",
Teml{
"branchName": branch.Name,
},
)
gui.createPromptPanel(g, v, message, func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.NewBranch(gui.trimmedContent(v)); err != nil {
return gui.createErrorPanel(g, err.Error())
}
gui.refreshSidePanels(g)
return gui.handleBranchSelect(g, v)
})
return nil
}
func (gui *Gui) handleDeleteBranch(g *gocui.Gui, v *gocui.View) error {
return gui.deleteBranch(g, v, false)
}
func (gui *Gui) handleForceDeleteBranch(g *gocui.Gui, v *gocui.View) error {
return gui.deleteBranch(g, v, true)
}
func (gui *Gui) deleteBranch(g *gocui.Gui, v *gocui.View, force bool) error {
checkedOutBranch := gui.State.Branches[0]
selectedBranch := gui.getSelectedBranch(v)
if checkedOutBranch.Name == selectedBranch.Name {
return gui.createErrorPanel(g, gui.Tr.SLocalize("CantDeleteCheckOutBranch"))
}
return gui.deleteNamedBranch(g, v, selectedBranch, force)
}
func (gui *Gui) deleteNamedBranch(g *gocui.Gui, v *gocui.View, selectedBranch *commands.Branch, force bool) error {
title := gui.Tr.SLocalize("DeleteBranch")
var messageId string
if force {
messageId = "ForceDeleteBranchMessage"
} else {
messageId = "DeleteBranchMessage"
}
message := gui.Tr.TemplateLocalize(
messageId,
Teml{
"selectedBranchName": selectedBranch.Name,
},
)
return gui.createConfirmationPanel(g, v, title, message, func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.DeleteBranch(selectedBranch.Name, force); err != nil {
errMessage := err.Error()
if !force && strings.Contains(errMessage, "is not fully merged") {
return gui.deleteNamedBranch(g, v, selectedBranch, true)
} else {
return gui.createErrorPanel(g, errMessage)
}
}
return gui.refreshSidePanels(g)
}, nil)
}
func (gui *Gui) handleMerge(g *gocui.Gui, v *gocui.View) error {
checkedOutBranch := gui.State.Branches[0]
selectedBranch := gui.getSelectedBranch(v)
defer gui.refreshSidePanels(g)
if checkedOutBranch.Name == selectedBranch.Name {
return gui.createErrorPanel(g, gui.Tr.SLocalize("CantMergeBranchIntoItself"))
}
if err := gui.GitCommand.Merge(selectedBranch.Name); err != nil {
return gui.createErrorPanel(g, err.Error())
}
return nil
}
func (gui *Gui) getSelectedBranch(v *gocui.View) *commands.Branch {
selectedLine := gui.State.Panels.Branches.SelectedLine selectedLine := gui.State.Panels.Branches.SelectedLine
if selectedLine == -1 { if selectedLine == -1 {
return nil return nil
@ -145,7 +27,7 @@ func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
if len(gui.State.Branches) == 0 { if len(gui.State.Branches) == 0 {
return gui.renderString(g, "main", gui.Tr.SLocalize("NoBranchesThisRepo")) return gui.renderString(g, "main", gui.Tr.SLocalize("NoBranchesThisRepo"))
} }
branch := gui.getSelectedBranch(v) branch := gui.getSelectedBranch()
if err := gui.focusPoint(0, gui.State.Panels.Branches.SelectedLine, v); err != nil { if err := gui.focusPoint(0, gui.State.Panels.Branches.SelectedLine, v); err != nil {
return err return err
} }
@ -202,3 +84,132 @@ func (gui *Gui) handleBranchesPrevLine(g *gocui.Gui, v *gocui.View) error {
return gui.handleBranchSelect(gui.g, v) return gui.handleBranchSelect(gui.g, v)
} }
// specific functions
func (gui *Gui) handleBranchPress(g *gocui.Gui, v *gocui.View) error {
if gui.State.Panels.Branches.SelectedLine == -1 {
return nil
}
if gui.State.Panels.Branches.SelectedLine == 0 {
return gui.createErrorPanel(g, gui.Tr.SLocalize("AlreadyCheckedOutBranch"))
}
branch := gui.getSelectedBranch()
if err := gui.GitCommand.Checkout(branch.Name, false); err != nil {
if err := gui.createErrorPanel(g, err.Error()); err != nil {
return err
}
}
return gui.refreshSidePanels(g)
}
func (gui *Gui) handleCreatePullRequestPress(g *gocui.Gui, v *gocui.View) error {
pullRequest := commands.NewPullRequest(gui.GitCommand)
branch := gui.getSelectedBranch()
if err := pullRequest.Create(branch); err != nil {
return gui.createErrorPanel(g, err.Error())
}
return nil
}
func (gui *Gui) handleForceCheckout(g *gocui.Gui, v *gocui.View) error {
branch := gui.getSelectedBranch()
message := gui.Tr.SLocalize("SureForceCheckout")
title := gui.Tr.SLocalize("ForceCheckoutBranch")
return gui.createConfirmationPanel(g, v, title, message, func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.Checkout(branch.Name, true); err != nil {
gui.createErrorPanel(g, err.Error())
}
return gui.refreshSidePanels(g)
}, nil)
}
func (gui *Gui) handleCheckoutByName(g *gocui.Gui, v *gocui.View) error {
gui.createPromptPanel(g, v, gui.Tr.SLocalize("BranchName")+":", func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.Checkout(gui.trimmedContent(v), false); err != nil {
return gui.createErrorPanel(g, err.Error())
}
return gui.refreshSidePanels(g)
})
return nil
}
func (gui *Gui) handleNewBranch(g *gocui.Gui, v *gocui.View) error {
branch := gui.State.Branches[0]
message := gui.Tr.TemplateLocalize(
"NewBranchNameBranchOff",
Teml{
"branchName": branch.Name,
},
)
gui.createPromptPanel(g, v, message, func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.NewBranch(gui.trimmedContent(v)); err != nil {
return gui.createErrorPanel(g, err.Error())
}
gui.refreshSidePanels(g)
return gui.handleBranchSelect(g, v)
})
return nil
}
func (gui *Gui) handleDeleteBranch(g *gocui.Gui, v *gocui.View) error {
return gui.deleteBranch(g, v, false)
}
func (gui *Gui) handleForceDeleteBranch(g *gocui.Gui, v *gocui.View) error {
return gui.deleteBranch(g, v, true)
}
func (gui *Gui) deleteBranch(g *gocui.Gui, v *gocui.View, force bool) error {
selectedBranch := gui.getSelectedBranch()
if selectedBranch == nil {
return nil
}
checkedOutBranch := gui.State.Branches[0]
if checkedOutBranch.Name == selectedBranch.Name {
return gui.createErrorPanel(g, gui.Tr.SLocalize("CantDeleteCheckOutBranch"))
}
return gui.deleteNamedBranch(g, v, selectedBranch, force)
}
func (gui *Gui) deleteNamedBranch(g *gocui.Gui, v *gocui.View, selectedBranch *commands.Branch, force bool) error {
title := gui.Tr.SLocalize("DeleteBranch")
var messageId string
if force {
messageId = "ForceDeleteBranchMessage"
} else {
messageId = "DeleteBranchMessage"
}
message := gui.Tr.TemplateLocalize(
messageId,
Teml{
"selectedBranchName": selectedBranch.Name,
},
)
return gui.createConfirmationPanel(g, v, title, message, func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.DeleteBranch(selectedBranch.Name, force); err != nil {
errMessage := err.Error()
if !force && strings.Contains(errMessage, "is not fully merged") {
return gui.deleteNamedBranch(g, v, selectedBranch, true)
} else {
return gui.createErrorPanel(g, errMessage)
}
}
return gui.refreshSidePanels(g)
}, nil)
}
func (gui *Gui) handleMerge(g *gocui.Gui, v *gocui.View) error {
checkedOutBranch := gui.State.Branches[0]
selectedBranch := gui.getSelectedBranch()
defer gui.refreshSidePanels(g)
if checkedOutBranch.Name == selectedBranch.Name {
return gui.createErrorPanel(g, gui.Tr.SLocalize("CantMergeBranchIntoItself"))
}
if err := gui.GitCommand.Merge(selectedBranch.Name); err != nil {
return gui.createErrorPanel(g, err.Error())
}
return nil
}

View File

@ -23,12 +23,12 @@ func (gui *Gui) handleCommitConfirm(g *gocui.Gui, v *gocui.View) error {
gui.SubProcess = sub gui.SubProcess = sub
return gui.Errors.ErrSubProcess return gui.Errors.ErrSubProcess
} }
gui.refreshFiles(g)
v.Clear() v.Clear()
v.SetCursor(0, 0) v.SetCursor(0, 0)
v.SetOrigin(0, 0)
g.SetViewOnBottom("commitMessage") g.SetViewOnBottom("commitMessage")
gui.switchFocus(g, v, gui.getFilesView(g)) gui.switchFocus(g, v, gui.getFilesView(g))
return gui.refreshCommits(g) return gui.refreshSidePanels(g)
} }
func (gui *Gui) handleCommitClose(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleCommitClose(g *gocui.Gui, v *gocui.View) error {

View File

@ -9,31 +9,54 @@ import (
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
// list panel functions
func (gui *Gui) getSelectedCommit(g *gocui.Gui) *commands.Commit {
selectedLine := gui.State.Panels.Commits.SelectedLine
if selectedLine == -1 {
return nil
}
return gui.State.Commits[selectedLine]
}
func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error {
commit := gui.getSelectedCommit(g)
if commit == nil {
return gui.renderString(g, "main", gui.Tr.SLocalize("NoCommitsThisBranch"))
}
if err := gui.focusPoint(0, gui.State.Panels.Commits.SelectedLine, v); err != nil {
return err
}
commitText, err := gui.GitCommand.Show(commit.Sha)
if err != nil {
return err
}
return gui.renderString(g, "main", commitText)
}
func (gui *Gui) refreshCommits(g *gocui.Gui) error { func (gui *Gui) refreshCommits(g *gocui.Gui) error {
g.Update(func(*gocui.Gui) error { g.Update(func(*gocui.Gui) error {
commits, err := gui.GitCommand.GetCommits() commits, err := gui.GitCommand.GetCommits()
if err != nil { if err != nil {
return err return err
} }
gui.State.Commits = commits gui.State.Commits = commits
v, err := g.View("commits")
if err != nil {
return err
}
gui.refreshSelectedLine(&gui.State.Panels.Commits.SelectedLine, len(gui.State.Commits)) gui.refreshSelectedLine(&gui.State.Panels.Commits.SelectedLine, len(gui.State.Commits))
v.Clear()
list, err := utils.RenderList(gui.State.Commits) list, err := utils.RenderList(gui.State.Commits)
if err != nil { if err != nil {
return err return err
} }
v := gui.getCommitsView(gui.g)
v.Clear()
fmt.Fprint(v, list) fmt.Fprint(v, list)
gui.refreshStatus(g) gui.refreshStatus(g)
if g.CurrentView().Name() == "commits" { if v == g.CurrentView() {
gui.handleCommitSelect(g, v) gui.handleCommitSelect(g, v)
} }
return nil return nil
@ -41,6 +64,22 @@ func (gui *Gui) refreshCommits(g *gocui.Gui) error {
return nil return nil
} }
func (gui *Gui) handleCommitsNextLine(g *gocui.Gui, v *gocui.View) error {
panelState := gui.State.Panels.Commits
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Commits), false)
return gui.handleCommitSelect(gui.g, v)
}
func (gui *Gui) handleCommitsPrevLine(g *gocui.Gui, v *gocui.View) error {
panelState := gui.State.Panels.Commits
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Commits), true)
return gui.handleCommitSelect(gui.g, v)
}
// specific functions
func (gui *Gui) handleResetToCommit(g *gocui.Gui, commitView *gocui.View) error { func (gui *Gui) handleResetToCommit(g *gocui.Gui, commitView *gocui.View) error {
return gui.createConfirmationPanel(g, commitView, gui.Tr.SLocalize("ResetToCommit"), gui.Tr.SLocalize("SureResetThisCommit"), func(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(g, commitView, gui.Tr.SLocalize("ResetToCommit"), gui.Tr.SLocalize("SureResetThisCommit"), func(g *gocui.Gui, v *gocui.View) error {
commit := gui.getSelectedCommit(g) commit := gui.getSelectedCommit(g)
@ -61,24 +100,8 @@ func (gui *Gui) handleResetToCommit(g *gocui.Gui, commitView *gocui.View) error
}, nil) }, nil)
} }
func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error {
commit := gui.getSelectedCommit(g)
if commit == nil {
return gui.renderString(g, "main", gui.Tr.SLocalize("NoCommitsThisBranch"))
}
if err := gui.focusPoint(0, gui.State.Panels.Commits.SelectedLine, v); err != nil {
return err
}
commitText, err := gui.GitCommand.Show(commit.Sha)
if err != nil {
return err
}
return gui.renderString(g, "main", commitText)
}
func (gui *Gui) handleCommitSquashDown(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleCommitSquashDown(g *gocui.Gui, v *gocui.View) error {
if gui.getItemPosition(v) != 0 { if gui.State.Panels.Commits.SelectedLine != 0 {
return gui.createErrorPanel(g, gui.Tr.SLocalize("OnlySquashTopmostCommit")) return gui.createErrorPanel(g, gui.Tr.SLocalize("OnlySquashTopmostCommit"))
} }
if len(gui.State.Commits) <= 1 { if len(gui.State.Commits) <= 1 {
@ -134,7 +157,7 @@ func (gui *Gui) handleCommitFixup(g *gocui.Gui, v *gocui.View) error {
} }
func (gui *Gui) handleRenameCommit(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleRenameCommit(g *gocui.Gui, v *gocui.View) error {
if gui.getItemPosition(gui.getCommitsView(g)) != 0 { if gui.State.Panels.Commits.SelectedLine != 0 {
return gui.createErrorPanel(g, gui.Tr.SLocalize("OnlyRenameTopCommit")) return gui.createErrorPanel(g, gui.Tr.SLocalize("OnlyRenameTopCommit"))
} }
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("renameCommit"), func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(g, v, gui.Tr.SLocalize("renameCommit"), func(g *gocui.Gui, v *gocui.View) error {
@ -149,7 +172,7 @@ func (gui *Gui) handleRenameCommit(g *gocui.Gui, v *gocui.View) error {
} }
func (gui *Gui) handleRenameCommitEditor(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleRenameCommitEditor(g *gocui.Gui, v *gocui.View) error {
if gui.getItemPosition(gui.getCommitsView(g)) != 0 { if gui.State.Panels.Commits.SelectedLine != 0 {
return gui.createErrorPanel(g, gui.Tr.SLocalize("OnlyRenameTopCommit")) return gui.createErrorPanel(g, gui.Tr.SLocalize("OnlyRenameTopCommit"))
} }
@ -160,28 +183,3 @@ func (gui *Gui) handleRenameCommitEditor(g *gocui.Gui, v *gocui.View) error {
return nil return nil
} }
func (gui *Gui) getSelectedCommit(g *gocui.Gui) *commands.Commit {
selectedLine := gui.State.Panels.Commits.SelectedLine
if selectedLine == -1 {
return nil
}
return gui.State.Commits[selectedLine]
}
func (gui *Gui) handleCommitsNextLine(g *gocui.Gui, v *gocui.View) error {
gui.Log.Info(utils.AsJson(gui.State.Panels))
panelState := gui.State.Panels.Commits
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Commits), false)
return gui.handleCommitSelect(gui.g, v)
}
func (gui *Gui) handleCommitsPrevLine(g *gocui.Gui, v *gocui.View) error {
gui.Log.Info(utils.AsJson(gui.State.Panels))
panelState := gui.State.Panels.Commits
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Commits), true)
return gui.handleCommitSelect(gui.g, v)
}

View File

@ -15,6 +15,79 @@ import (
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
// list panel functions
func (gui *Gui) getSelectedFile(g *gocui.Gui) (*commands.File, error) {
selectedLine := gui.State.Panels.Files.SelectedLine
if selectedLine == -1 {
return &commands.File{}, gui.Errors.ErrNoFiles
}
return gui.State.Files[selectedLine], nil
}
func (gui *Gui) handleFileSelect(g *gocui.Gui, v *gocui.View) error {
file, err := gui.getSelectedFile(g)
if err != nil {
if err != gui.Errors.ErrNoFiles {
return err
}
return gui.renderString(g, "main", gui.Tr.SLocalize("NoChangedFiles"))
}
if file.HasMergeConflicts {
return gui.refreshMergePanel(g)
}
if err := gui.focusPoint(0, gui.State.Panels.Files.SelectedLine, v); err != nil {
return err
}
content := gui.GitCommand.Diff(file, false)
return gui.renderString(g, "main", content)
}
func (gui *Gui) refreshFiles(g *gocui.Gui) error {
filesView, err := g.View("files")
if err != nil {
return err
}
gui.refreshStateFiles()
gui.g.Update(func(g *gocui.Gui) error {
filesView.Clear()
list, err := utils.RenderList(gui.State.Files)
if err != nil {
return err
}
fmt.Fprint(filesView, list)
if filesView == g.CurrentView() {
gui.handleFileSelect(g, filesView)
}
return nil
})
return nil
}
func (gui *Gui) handleFilesNextLine(g *gocui.Gui, v *gocui.View) error {
panelState := gui.State.Panels.Files
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Files), false)
return gui.handleFileSelect(gui.g, v)
}
func (gui *Gui) handleFilesPrevLine(g *gocui.Gui, v *gocui.View) error {
panelState := gui.State.Panels.Files
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Files), true)
return gui.handleFileSelect(gui.g, v)
}
// specific functions
func (gui *Gui) stagedFiles() []*commands.File { func (gui *Gui) stagedFiles() []*commands.File {
files := gui.State.Files files := gui.State.Files
result := make([]*commands.File, 0) result := make([]*commands.File, 0)
@ -139,15 +212,6 @@ func (gui *Gui) handleAddPatch(g *gocui.Gui, v *gocui.View) error {
return gui.Errors.ErrSubProcess return gui.Errors.ErrSubProcess
} }
func (gui *Gui) getSelectedFile(g *gocui.Gui) (*commands.File, error) {
selectedLine := gui.State.Panels.Files.SelectedLine
if selectedLine == -1 {
return &commands.File{}, gui.Errors.ErrNoFiles
}
return gui.State.Files[selectedLine], nil
}
func (gui *Gui) handleFileRemove(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleFileRemove(g *gocui.Gui, v *gocui.View) error {
file, err := gui.getSelectedFile(g) file, err := gui.getSelectedFile(g)
if err != nil { if err != nil {
@ -191,27 +255,6 @@ func (gui *Gui) handleIgnoreFile(g *gocui.Gui, v *gocui.View) error {
return gui.refreshFiles(g) return gui.refreshFiles(g)
} }
func (gui *Gui) handleFileSelect(g *gocui.Gui, v *gocui.View) error {
file, err := gui.getSelectedFile(g)
if err != nil {
if err != gui.Errors.ErrNoFiles {
return err
}
return gui.renderString(g, "main", gui.Tr.SLocalize("NoChangedFiles"))
}
if file.HasMergeConflicts {
return gui.refreshMergePanel(g)
}
if err := gui.focusPoint(0, gui.State.Panels.Files.SelectedLine, v); err != nil {
return err
}
content := gui.GitCommand.Diff(file, false)
return gui.renderString(g, "main", content)
}
func (gui *Gui) handleCommitPress(g *gocui.Gui, filesView *gocui.View) error { func (gui *Gui) handleCommitPress(g *gocui.Gui, filesView *gocui.View) error {
if len(gui.stagedFiles()) == 0 && !gui.State.HasMergeConflicts { if len(gui.stagedFiles()) == 0 && !gui.State.HasMergeConflicts {
return gui.createErrorPanel(g, gui.Tr.SLocalize("NoStagedFilesToCommit")) return gui.createErrorPanel(g, gui.Tr.SLocalize("NoStagedFilesToCommit"))
@ -335,45 +378,6 @@ func (gui *Gui) catSelectedFile(g *gocui.Gui) (string, error) {
return cat, nil return cat, nil
} }
func (gui *Gui) handleFilesNextLine(g *gocui.Gui, v *gocui.View) error {
panelState := gui.State.Panels.Files
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Files), false)
return gui.handleFileSelect(gui.g, v)
}
func (gui *Gui) handleFilesPrevLine(g *gocui.Gui, v *gocui.View) error {
panelState := gui.State.Panels.Files
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Files), true)
return gui.handleFileSelect(gui.g, v)
}
func (gui *Gui) refreshFiles(g *gocui.Gui) error {
filesView, err := g.View("files")
if err != nil {
return err
}
gui.refreshStateFiles()
gui.g.Update(func(g *gocui.Gui) error {
filesView.Clear()
list, err := utils.RenderList(gui.State.Files)
if err != nil {
return err
}
fmt.Fprint(filesView, list)
if filesView == g.CurrentView() {
gui.handleFileSelect(g, filesView)
}
return nil
})
return nil
}
func (gui *Gui) pullFiles(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) pullFiles(g *gocui.Gui, v *gocui.View) error {
gui.createMessagePanel(g, v, "", gui.Tr.SLocalize("PullWait")) gui.createMessagePanel(g, v, "", gui.Tr.SLocalize("PullWait"))
go func() { go func() {
@ -399,8 +403,7 @@ func (gui *Gui) pushWithForceFlag(currentView *gocui.View, force bool) error {
_ = gui.createErrorPanel(gui.g, err.Error()) _ = gui.createErrorPanel(gui.g, err.Error())
} else { } else {
_ = gui.closeConfirmationPrompt(gui.g) _ = gui.closeConfirmationPrompt(gui.g)
_ = gui.refreshCommits(gui.g) _ = gui.refreshSidePanels(gui.g)
_ = gui.refreshStatus(gui.g)
} }
}() }()
return nil return nil

View File

@ -95,12 +95,17 @@ type stashPanelState struct {
SelectedLine int SelectedLine int
} }
type menuPanelState struct {
SelectedLine int
}
type panelStates struct { type panelStates struct {
Files *filePanelState Files *filePanelState
Staging *stagingPanelState Staging *stagingPanelState
Branches *branchPanelState Branches *branchPanelState
Commits *commitPanelState Commits *commitPanelState
Stash *stashPanelState Stash *stashPanelState
Menu *menuPanelState
} }
type guiState struct { type guiState struct {
@ -137,6 +142,7 @@ func NewGui(log *logrus.Entry, gitCommand *commands.GitCommand, oSCommand *comma
Branches: &branchPanelState{SelectedLine: 0}, Branches: &branchPanelState{SelectedLine: 0},
Commits: &commitPanelState{SelectedLine: -1}, Commits: &commitPanelState{SelectedLine: -1},
Stash: &stashPanelState{SelectedLine: -1}, Stash: &stashPanelState{SelectedLine: -1},
Menu: &menuPanelState{SelectedLine: 0},
}, },
} }
@ -359,12 +365,12 @@ func (gui *Gui) layout(g *gocui.Gui) error {
} }
gui.g.SetCurrentView(filesView.Name()) gui.g.SetCurrentView(filesView.Name())
gui.refreshFiles(g)
gui.refreshBranches(g) gui.refreshSidePanels(gui.g)
gui.refreshCommits(g) if gui.g.CurrentView().Name() != "menu" {
gui.refreshStashEntries(g) if err := gui.renderGlobalOptions(g); err != nil {
if err := gui.renderGlobalOptions(g); err != nil { return err
return err }
} }
if err := gui.switchFocus(g, nil, filesView); err != nil { if err := gui.switchFocus(g, nil, filesView); err != nil {
return err return err
@ -388,6 +394,9 @@ func (gui *Gui) layout(g *gocui.Gui) error {
} }
} }
// TODO: comment-out
gui.Log.Info(utils.AsJson(gui.State))
return gui.resizeCurrentPopupPanel(g) return gui.resizeCurrentPopupPanel(g)
} }

View File

@ -386,7 +386,12 @@ func (gui *Gui) GetKeybindings() []*Binding {
Modifier: gocui.ModNone, Modifier: gocui.ModNone,
Handler: gui.handleStashDrop, Handler: gui.handleStashDrop,
Description: gui.Tr.SLocalize("drop"), Description: gui.Tr.SLocalize("drop"),
}, { },
{ViewName: "stash", Key: 'k', Modifier: gocui.ModNone, Handler: gui.handleStashPrevLine},
{ViewName: "stash", Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: gui.handleStashPrevLine},
{ViewName: "stash", Key: 'j', Modifier: gocui.ModNone, Handler: gui.handleStashNextLine},
{ViewName: "stash", Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: gui.handleStashNextLine},
{
ViewName: "commitMessage", ViewName: "commitMessage",
Key: gocui.KeyEnter, Key: gocui.KeyEnter,
Modifier: gocui.ModNone, Modifier: gocui.ModNone,
@ -406,7 +411,11 @@ func (gui *Gui) GetKeybindings() []*Binding {
Key: 'q', Key: 'q',
Modifier: gocui.ModNone, Modifier: gocui.ModNone,
Handler: gui.handleMenuClose, Handler: gui.handleMenuClose,
}, { },
{ViewName: "menu", Key: 'k', Modifier: gocui.ModNone, Handler: gui.handleMenuPrevLine},
{ViewName: "menu", Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: gui.handleMenuPrevLine},
{ViewName: "menu", Key: 'j', Modifier: gocui.ModNone, Handler: gui.handleMenuNextLine},
{ViewName: "menu", Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: gui.handleMenuNextLine}, {
ViewName: "staging", ViewName: "staging",
Key: gocui.KeyEsc, Key: gocui.KeyEsc,
Modifier: gocui.ModNone, Modifier: gocui.ModNone,
@ -468,17 +477,6 @@ func (gui *Gui) GetKeybindings() []*Binding {
}, },
} }
// Would make these keybindings global but that interferes with editing
// input in the confirmation panel
for _, viewName := range []string{"status", "commits", "stash", "menu"} {
bindings = append(bindings, []*Binding{
{ViewName: viewName, Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: gui.cursorUp},
{ViewName: viewName, Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: gui.cursorDown},
{ViewName: viewName, Key: 'k', Modifier: gocui.ModNone, Handler: gui.cursorUp},
{ViewName: viewName, Key: 'j', Modifier: gocui.ModNone, Handler: gui.cursorDown},
}...)
}
for _, viewName := range []string{"status", "branches", "files", "commits", "stash", "menu"} { for _, viewName := range []string{"status", "branches", "files", "commits", "stash", "menu"} {
bindings = append(bindings, []*Binding{ bindings = append(bindings, []*Binding{
{ViewName: viewName, Key: gocui.KeyTab, Modifier: gocui.ModNone, Handler: gui.nextView}, {ViewName: viewName, Key: gocui.KeyTab, Modifier: gocui.ModNone, Handler: gui.nextView},

View File

@ -8,12 +8,32 @@ import (
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
// list panel functions
func (gui *Gui) handleMenuSelect(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleMenuSelect(g *gocui.Gui, v *gocui.View) error {
// doing nothing for now return gui.focusPoint(0, gui.State.Panels.Menu.SelectedLine, v)
// but it is needed for switch in newLineFocused
return nil
} }
func (gui *Gui) handleMenuNextLine(g *gocui.Gui, v *gocui.View) error {
panelState := gui.State.Panels.Menu
gui.changeSelectedLine(&panelState.SelectedLine, v.LinesHeight(), false)
return gui.handleMenuSelect(g, v)
}
func (gui *Gui) handleMenuPrevLine(g *gocui.Gui, v *gocui.View) error {
panelState := gui.State.Panels.Menu
gui.changeSelectedLine(&panelState.SelectedLine, v.LinesHeight(), true)
if err := gui.focusPoint(0, gui.State.Panels.Commits.SelectedLine, v); err != nil {
return err
}
return gui.handleMenuSelect(g, v)
}
// specific functions
func (gui *Gui) renderMenuOptions(g *gocui.Gui) error { func (gui *Gui) renderMenuOptions(g *gocui.Gui) error {
optionsMap := map[string]string{ optionsMap := map[string]string{
"esc/q": gui.Tr.SLocalize("close"), "esc/q": gui.Tr.SLocalize("close"),
@ -46,14 +66,15 @@ func (gui *Gui) createMenu(items interface{}, handlePress func(int) error) error
menuView.FgColor = gocui.ColorWhite menuView.FgColor = gocui.ColorWhite
menuView.Clear() menuView.Clear()
fmt.Fprint(menuView, list) fmt.Fprint(menuView, list)
gui.State.Panels.Menu.SelectedLine = 0
if err := gui.renderMenuOptions(gui.g); err != nil { if err := gui.renderMenuOptions(gui.g); err != nil {
return err return err
} }
wrappedHandlePress := func(g *gocui.Gui, v *gocui.View) error { wrappedHandlePress := func(g *gocui.Gui, v *gocui.View) error {
lineNumber := gui.getItemPosition(v) selectedLine := gui.State.Panels.Menu.SelectedLine
return handlePress(lineNumber) return handlePress(selectedLine)
} }
if err := gui.g.SetKeybinding("menu", gocui.KeySpace, gocui.ModNone, wrappedHandlePress); err != nil { if err := gui.g.SetKeybinding("menu", gocui.KeySpace, gocui.ModNone, wrappedHandlePress); err != nil {

View File

@ -8,19 +8,46 @@ import (
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
// list panel functions
func (gui *Gui) getSelectedStashEntry(v *gocui.View) *commands.StashEntry {
selectedLine := gui.State.Panels.Stash.SelectedLine
if selectedLine == -1 {
return nil
}
return gui.State.StashEntries[selectedLine]
}
func (gui *Gui) handleStashEntrySelect(g *gocui.Gui, v *gocui.View) error {
stashEntry := gui.getSelectedStashEntry(v)
if stashEntry == nil {
return gui.renderString(g, "main", gui.Tr.SLocalize("NoStashEntries"))
}
if err := gui.focusPoint(0, gui.State.Panels.Stash.SelectedLine, v); err != nil {
return err
}
go func() {
// doing this asynchronously cos it can take time
diff, _ := gui.GitCommand.GetStashEntryDiff(stashEntry.Index)
gui.renderString(g, "main", diff)
}()
return nil
}
func (gui *Gui) refreshStashEntries(g *gocui.Gui) error { func (gui *Gui) refreshStashEntries(g *gocui.Gui) error {
g.Update(func(g *gocui.Gui) error { g.Update(func(g *gocui.Gui) error {
v, err := g.View("stash")
if err != nil {
panic(err)
}
gui.State.StashEntries = gui.GitCommand.GetStashEntries() gui.State.StashEntries = gui.GitCommand.GetStashEntries()
v.Clear() gui.refreshSelectedLine(&gui.State.Panels.Stash.SelectedLine, len(gui.State.StashEntries))
list, err := utils.RenderList(gui.State.StashEntries) list, err := utils.RenderList(gui.State.StashEntries)
if err != nil { if err != nil {
return err return err
} }
v := gui.getStashView(gui.g)
v.Clear()
fmt.Fprint(v, list) fmt.Fprint(v, list)
return gui.resetOrigin(v) return gui.resetOrigin(v)
@ -28,28 +55,22 @@ func (gui *Gui) refreshStashEntries(g *gocui.Gui) error {
return nil return nil
} }
func (gui *Gui) getSelectedStashEntry(v *gocui.View) *commands.StashEntry { func (gui *Gui) handleStashNextLine(g *gocui.Gui, v *gocui.View) error {
if len(gui.State.StashEntries) == 0 { panelState := gui.State.Panels.Stash
return nil gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.StashEntries), false)
}
stashView, _ := gui.g.View("stash") return gui.handleStashEntrySelect(gui.g, v)
lineNumber := gui.getItemPosition(stashView)
return gui.State.StashEntries[lineNumber]
} }
func (gui *Gui) handleStashEntrySelect(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleStashPrevLine(g *gocui.Gui, v *gocui.View) error {
go func() { panelState := gui.State.Panels.Stash
stashEntry := gui.getSelectedStashEntry(v) gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.StashEntries), true)
if stashEntry == nil {
gui.renderString(g, "main", gui.Tr.SLocalize("NoStashEntries")) return gui.handleStashEntrySelect(gui.g, v)
return
}
diff, _ := gui.GitCommand.GetStashEntryDiff(stashEntry.Index)
gui.renderString(g, "main", diff)
}()
return nil
} }
// specific functions
func (gui *Gui) handleStashApply(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleStashApply(g *gocui.Gui, v *gocui.View) error {
return gui.stashDo(g, v, "apply") return gui.stashDo(g, v, "apply")
} }

View File

@ -16,6 +16,7 @@ func (gui *Gui) refreshSidePanels(g *gocui.Gui) error {
gui.refreshBranches(g) gui.refreshBranches(g)
gui.refreshFiles(g) gui.refreshFiles(g)
gui.refreshCommits(g) gui.refreshCommits(g)
gui.refreshStashEntries(g)
return nil return nil
} }
@ -78,18 +79,19 @@ func (gui *Gui) previousView(g *gocui.Gui, v *gocui.View) error {
} }
func (gui *Gui) newLineFocused(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) newLineFocused(g *gocui.Gui, v *gocui.View) error {
mainView, _ := g.View("main")
mainView.SetOrigin(0, 0)
switch v.Name() { switch v.Name() {
case "menu": case "menu":
return gui.handleMenuSelect(g, v) return nil
case "status": case "status":
return gui.handleStatusSelect(g, v) return gui.handleStatusSelect(g, v)
case "files": case "files":
return gui.handleFileSelect(g, v) return gui.handleFileSelect(g, v)
case "branches": case "branches":
return gui.handleBranchSelect(g, v) return gui.handleBranchSelect(g, v)
case "commits":
return gui.handleCommitSelect(g, v)
case "stash":
return gui.handleStashEntrySelect(g, v)
case "confirmation": case "confirmation":
return nil return nil
case "commitMessage": case "commitMessage":
@ -99,10 +101,6 @@ func (gui *Gui) newLineFocused(g *gocui.Gui, v *gocui.View) error {
gui.refreshMergePanel(g) gui.refreshMergePanel(g)
v.Highlight = false v.Highlight = false
return nil return nil
case "commits":
return gui.handleCommitSelect(g, v)
case "stash":
return gui.handleStashEntrySelect(g, v)
case "staging": case "staging":
return nil return nil
// return gui.handleStagingSelect(g, v) // return gui.handleStagingSelect(g, v)
@ -165,61 +163,6 @@ func (gui *Gui) switchFocus(g *gocui.Gui, oldView, newView *gocui.View) error {
return gui.newLineFocused(g, newView) return gui.newLineFocused(g, newView)
} }
func (gui *Gui) getItemPosition(v *gocui.View) int {
gui.correctCursor(v)
_, cy := v.Cursor()
_, oy := v.Origin()
return oy + cy
}
func (gui *Gui) cursorUp(g *gocui.Gui, v *gocui.View) error {
// swallowing cursor movements in main
if v == nil || v.Name() == "main" {
return nil
}
ox, oy := v.Origin()
cx, cy := v.Cursor()
if err := v.SetCursor(cx, cy-1); err != nil && oy > 0 {
if err := v.SetOrigin(ox, oy-1); err != nil {
return err
}
}
gui.newLineFocused(g, v)
return nil
}
func (gui *Gui) cursorDown(g *gocui.Gui, v *gocui.View) error {
// swallowing cursor movements in main
if v == nil || v.Name() == "main" {
return nil
}
cx, cy := v.Cursor()
ox, oy := v.Origin()
ly := v.LinesHeight() - 1
_, height := v.Size()
maxY := height - 1
// if we are at the end we just return
if cy+oy == ly {
return nil
}
var err error
if cy < maxY {
err = v.SetCursor(cx, cy+1)
} else {
err = v.SetOrigin(ox, oy+1)
}
if err != nil {
return err
}
gui.newLineFocused(g, v)
return nil
}
func (gui *Gui) resetOrigin(v *gocui.View) error { func (gui *Gui) resetOrigin(v *gocui.View) error {
if err := v.SetCursor(0, 0); err != nil { if err := v.SetCursor(0, 0); err != nil {
return err return err
@ -227,12 +170,6 @@ func (gui *Gui) resetOrigin(v *gocui.View) error {
return v.SetOrigin(0, 0) return v.SetOrigin(0, 0)
} }
// if the cursor down past the last item, move it to the last line
func (gui *Gui) correctCursor(v *gocui.View) error {
cx, cy := v.Cursor()
return gui.focusPoint(cx, cy, v)
}
// if the cursor down past the last item, move it to the last line // if the cursor down past the last item, move it to the last line
func (gui *Gui) focusPoint(cx int, cy int, v *gocui.View) error { func (gui *Gui) focusPoint(cx int, cy int, v *gocui.View) error {
if cy < 0 { if cy < 0 {
@ -283,6 +220,9 @@ func (gui *Gui) renderString(g *gocui.Gui, viewName, s string) error {
return nil return nil
} }
v.Clear() v.Clear()
if err := v.SetOrigin(0, 0); err != nil {
return err
}
output := string(bom.Clean([]byte(s))) output := string(bom.Clean([]byte(s)))
output = utils.NormalizeLinefeeds(output) output = utils.NormalizeLinefeeds(output)
fmt.Fprint(v, output) fmt.Fprint(v, output)
@ -331,6 +271,16 @@ func (gui *Gui) getStagingView(g *gocui.Gui) *gocui.View {
return v return v
} }
func (gui *Gui) getMainView(g *gocui.Gui) *gocui.View {
v, _ := g.View("main")
return v
}
func (gui *Gui) getStashView(g *gocui.Gui) *gocui.View {
v, _ := g.View("stash")
return v
}
func (gui *Gui) trimmedContent(v *gocui.View) string { func (gui *Gui) trimmedContent(v *gocui.View) string {
return strings.TrimSpace(v.Buffer()) return strings.TrimSpace(v.Buffer())
} }