1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-05-31 23:19:40 +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"
)
func (gui *Gui) handleBranchPress(g *gocui.Gui, v *gocui.View) error {
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)
}
// list panel functions
func (gui *Gui) handleCreatePullRequestPress(g *gocui.Gui, v *gocui.View) error {
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 {
func (gui *Gui) getSelectedBranch() *commands.Branch {
selectedLine := gui.State.Panels.Branches.SelectedLine
if selectedLine == -1 {
return nil
@ -145,7 +27,7 @@ func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
if len(gui.State.Branches) == 0 {
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 {
return err
}
@ -202,3 +84,132 @@ func (gui *Gui) handleBranchesPrevLine(g *gocui.Gui, v *gocui.View) error {
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
return gui.Errors.ErrSubProcess
}
gui.refreshFiles(g)
v.Clear()
v.SetCursor(0, 0)
v.SetOrigin(0, 0)
g.SetViewOnBottom("commitMessage")
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 {

View File

@ -9,31 +9,54 @@ import (
"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 {
g.Update(func(*gocui.Gui) error {
commits, err := gui.GitCommand.GetCommits()
if err != nil {
return err
}
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))
v.Clear()
list, err := utils.RenderList(gui.State.Commits)
if err != nil {
return err
}
v := gui.getCommitsView(gui.g)
v.Clear()
fmt.Fprint(v, list)
gui.refreshStatus(g)
if g.CurrentView().Name() == "commits" {
if v == g.CurrentView() {
gui.handleCommitSelect(g, v)
}
return nil
@ -41,6 +64,22 @@ func (gui *Gui) refreshCommits(g *gocui.Gui) error {
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 {
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)
@ -61,24 +100,8 @@ func (gui *Gui) handleResetToCommit(g *gocui.Gui, commitView *gocui.View) error
}, 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 {
if gui.getItemPosition(v) != 0 {
if gui.State.Panels.Commits.SelectedLine != 0 {
return gui.createErrorPanel(g, gui.Tr.SLocalize("OnlySquashTopmostCommit"))
}
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 {
if gui.getItemPosition(gui.getCommitsView(g)) != 0 {
if gui.State.Panels.Commits.SelectedLine != 0 {
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 {
@ -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 {
if gui.getItemPosition(gui.getCommitsView(g)) != 0 {
if gui.State.Panels.Commits.SelectedLine != 0 {
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
}
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"
)
// 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 {
files := gui.State.Files
result := make([]*commands.File, 0)
@ -139,15 +212,6 @@ func (gui *Gui) handleAddPatch(g *gocui.Gui, v *gocui.View) error {
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 {
file, err := gui.getSelectedFile(g)
if err != nil {
@ -191,27 +255,6 @@ func (gui *Gui) handleIgnoreFile(g *gocui.Gui, v *gocui.View) error {
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 {
if len(gui.stagedFiles()) == 0 && !gui.State.HasMergeConflicts {
return gui.createErrorPanel(g, gui.Tr.SLocalize("NoStagedFilesToCommit"))
@ -335,45 +378,6 @@ func (gui *Gui) catSelectedFile(g *gocui.Gui) (string, error) {
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 {
gui.createMessagePanel(g, v, "", gui.Tr.SLocalize("PullWait"))
go func() {
@ -399,8 +403,7 @@ func (gui *Gui) pushWithForceFlag(currentView *gocui.View, force bool) error {
_ = gui.createErrorPanel(gui.g, err.Error())
} else {
_ = gui.closeConfirmationPrompt(gui.g)
_ = gui.refreshCommits(gui.g)
_ = gui.refreshStatus(gui.g)
_ = gui.refreshSidePanels(gui.g)
}
}()
return nil

View File

@ -95,12 +95,17 @@ type stashPanelState struct {
SelectedLine int
}
type menuPanelState struct {
SelectedLine int
}
type panelStates struct {
Files *filePanelState
Staging *stagingPanelState
Branches *branchPanelState
Commits *commitPanelState
Stash *stashPanelState
Menu *menuPanelState
}
type guiState struct {
@ -137,6 +142,7 @@ func NewGui(log *logrus.Entry, gitCommand *commands.GitCommand, oSCommand *comma
Branches: &branchPanelState{SelectedLine: 0},
Commits: &commitPanelState{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.refreshFiles(g)
gui.refreshBranches(g)
gui.refreshCommits(g)
gui.refreshStashEntries(g)
if err := gui.renderGlobalOptions(g); err != nil {
return err
gui.refreshSidePanels(gui.g)
if gui.g.CurrentView().Name() != "menu" {
if err := gui.renderGlobalOptions(g); err != nil {
return err
}
}
if err := gui.switchFocus(g, nil, filesView); err != nil {
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)
}

View File

@ -386,7 +386,12 @@ func (gui *Gui) GetKeybindings() []*Binding {
Modifier: gocui.ModNone,
Handler: gui.handleStashDrop,
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",
Key: gocui.KeyEnter,
Modifier: gocui.ModNone,
@ -406,7 +411,11 @@ func (gui *Gui) GetKeybindings() []*Binding {
Key: 'q',
Modifier: gocui.ModNone,
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",
Key: gocui.KeyEsc,
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"} {
bindings = append(bindings, []*Binding{
{ViewName: viewName, Key: gocui.KeyTab, Modifier: gocui.ModNone, Handler: gui.nextView},

View File

@ -8,12 +8,32 @@ import (
"github.com/jesseduffield/lazygit/pkg/utils"
)
// list panel functions
func (gui *Gui) handleMenuSelect(g *gocui.Gui, v *gocui.View) error {
// doing nothing for now
// but it is needed for switch in newLineFocused
return nil
return gui.focusPoint(0, gui.State.Panels.Menu.SelectedLine, v)
}
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 {
optionsMap := map[string]string{
"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.Clear()
fmt.Fprint(menuView, list)
gui.State.Panels.Menu.SelectedLine = 0
if err := gui.renderMenuOptions(gui.g); err != nil {
return err
}
wrappedHandlePress := func(g *gocui.Gui, v *gocui.View) error {
lineNumber := gui.getItemPosition(v)
return handlePress(lineNumber)
selectedLine := gui.State.Panels.Menu.SelectedLine
return handlePress(selectedLine)
}
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"
)
// 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 {
g.Update(func(g *gocui.Gui) error {
v, err := g.View("stash")
if err != nil {
panic(err)
}
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)
if err != nil {
return err
}
v := gui.getStashView(gui.g)
v.Clear()
fmt.Fprint(v, list)
return gui.resetOrigin(v)
@ -28,28 +55,22 @@ func (gui *Gui) refreshStashEntries(g *gocui.Gui) error {
return nil
}
func (gui *Gui) getSelectedStashEntry(v *gocui.View) *commands.StashEntry {
if len(gui.State.StashEntries) == 0 {
return nil
}
stashView, _ := gui.g.View("stash")
lineNumber := gui.getItemPosition(stashView)
return gui.State.StashEntries[lineNumber]
func (gui *Gui) handleStashNextLine(g *gocui.Gui, v *gocui.View) error {
panelState := gui.State.Panels.Stash
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.StashEntries), false)
return gui.handleStashEntrySelect(gui.g, v)
}
func (gui *Gui) handleStashEntrySelect(g *gocui.Gui, v *gocui.View) error {
go func() {
stashEntry := gui.getSelectedStashEntry(v)
if stashEntry == nil {
gui.renderString(g, "main", gui.Tr.SLocalize("NoStashEntries"))
return
}
diff, _ := gui.GitCommand.GetStashEntryDiff(stashEntry.Index)
gui.renderString(g, "main", diff)
}()
return nil
func (gui *Gui) handleStashPrevLine(g *gocui.Gui, v *gocui.View) error {
panelState := gui.State.Panels.Stash
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.StashEntries), true)
return gui.handleStashEntrySelect(gui.g, v)
}
// specific functions
func (gui *Gui) handleStashApply(g *gocui.Gui, v *gocui.View) error {
return gui.stashDo(g, v, "apply")
}

View File

@ -16,6 +16,7 @@ func (gui *Gui) refreshSidePanels(g *gocui.Gui) error {
gui.refreshBranches(g)
gui.refreshFiles(g)
gui.refreshCommits(g)
gui.refreshStashEntries(g)
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 {
mainView, _ := g.View("main")
mainView.SetOrigin(0, 0)
switch v.Name() {
case "menu":
return gui.handleMenuSelect(g, v)
return nil
case "status":
return gui.handleStatusSelect(g, v)
case "files":
return gui.handleFileSelect(g, v)
case "branches":
return gui.handleBranchSelect(g, v)
case "commits":
return gui.handleCommitSelect(g, v)
case "stash":
return gui.handleStashEntrySelect(g, v)
case "confirmation":
return nil
case "commitMessage":
@ -99,10 +101,6 @@ func (gui *Gui) newLineFocused(g *gocui.Gui, v *gocui.View) error {
gui.refreshMergePanel(g)
v.Highlight = false
return nil
case "commits":
return gui.handleCommitSelect(g, v)
case "stash":
return gui.handleStashEntrySelect(g, v)
case "staging":
return nil
// 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)
}
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 {
if err := v.SetCursor(0, 0); err != nil {
return err
@ -227,12 +170,6 @@ func (gui *Gui) resetOrigin(v *gocui.View) error {
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
func (gui *Gui) focusPoint(cx int, cy int, v *gocui.View) error {
if cy < 0 {
@ -283,6 +220,9 @@ func (gui *Gui) renderString(g *gocui.Gui, viewName, s string) error {
return nil
}
v.Clear()
if err := v.SetOrigin(0, 0); err != nil {
return err
}
output := string(bom.Clean([]byte(s)))
output = utils.NormalizeLinefeeds(output)
fmt.Fprint(v, output)
@ -331,6 +271,16 @@ func (gui *Gui) getStagingView(g *gocui.Gui) *gocui.View {
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 {
return strings.TrimSpace(v.Buffer())
}