summaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2018-12-04 19:50:11 +1100
committerJesse Duffield <jessedduffield@gmail.com>2018-12-08 11:51:47 +1100
commit99a8b1ae8bb93565df8acbe168749278dc768979 (patch)
tree06f3707ff08a879cf9fac550cf71f42bbe0215bf /pkg
parentccc771d8b13d5b0d4635db4463556366470fd4f6 (diff)
making a start on unidirectional data binding to fix these UI bugs
Diffstat (limited to 'pkg')
-rw-r--r--pkg/app/app.go2
-rw-r--r--pkg/commands/git.go11
-rw-r--r--pkg/gui/branches_panel.go42
-rw-r--r--pkg/gui/commits_panel.go77
-rw-r--r--pkg/gui/files_panel.go65
-rw-r--r--pkg/gui/gui.go71
-rw-r--r--pkg/gui/keybindings.go36
-rw-r--r--pkg/gui/staging_panel.go62
-rw-r--r--pkg/gui/stash_panel.go7
-rw-r--r--pkg/gui/status_panel.go9
-rw-r--r--pkg/gui/view_helpers.go105
-rw-r--r--pkg/utils/utils.go6
12 files changed, 333 insertions, 160 deletions
diff --git a/pkg/app/app.go b/pkg/app/app.go
index 65acd2e35..b43f9568c 100644
--- a/pkg/app/app.go
+++ b/pkg/app/app.go
@@ -52,6 +52,8 @@ func newLogger(config config.AppConfigurer) *logrus.Entry {
} else {
log = newProductionLogger(config)
}
+ log.Formatter = &logrus.JSONFormatter{}
+
if config.GetUserConfig().GetString("reporting") == "on" {
// this isn't really a secret token: it only has permission to push new rollbar items
hook := rollrus.NewHook("23432119147a4367abf7c0de2aa99a2d", environment)
diff --git a/pkg/commands/git.go b/pkg/commands/git.go
index 7d820c599..e185b0fbd 100644
--- a/pkg/commands/git.go
+++ b/pkg/commands/git.go
@@ -130,6 +130,17 @@ func (c *GitCommand) GetStashEntryDiff(index int) (string, error) {
// GetStatusFiles git status files
func (c *GitCommand) GetStatusFiles() []*File {
+
+ // files := []*File{}
+ // for i := 0; i < 100; i++ {
+ // files = append(files, &File{
+ // Name: strconv.Itoa(i),
+ // DisplayString: strconv.Itoa(i),
+ // Type: "file",
+ // })
+ // }
+ // return files
+
statusOutput, _ := c.GitStatus()
statusStrings := utils.SplitLines(statusOutput)
files := []*File{}
diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go
index dbf4b007a..e1504bd69 100644
--- a/pkg/gui/branches_panel.go
+++ b/pkg/gui/branches_panel.go
@@ -131,30 +131,30 @@ func (gui *Gui) handleMerge(g *gocui.Gui, v *gocui.View) error {
}
func (gui *Gui) getSelectedBranch(v *gocui.View) *commands.Branch {
- lineNumber := gui.getItemPosition(v)
- return gui.State.Branches[lineNumber]
-}
+ selectedLine := gui.State.Panels.Branches.SelectedLine
+ if selectedLine == -1 {
+ return nil
+ }
-func (gui *Gui) renderBranchesOptions(g *gocui.Gui) error {
- return gui.renderGlobalOptions(g)
+ return gui.State.Branches[selectedLine]
}
// may want to standardise how these select methods work
func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
- if err := gui.renderBranchesOptions(g); err != nil {
- return err
- }
// This really shouldn't happen: there should always be a master branch
if len(gui.State.Branches) == 0 {
return gui.renderString(g, "main", gui.Tr.SLocalize("NoBranchesThisRepo"))
}
+ branch := gui.getSelectedBranch(v)
+ if err := gui.focusPoint(0, gui.State.Panels.Branches.SelectedLine, v); err != nil {
+ return err
+ }
go func() {
- branch := gui.getSelectedBranch(v)
- diff, err := gui.GitCommand.GetBranchGraph(branch.Name)
- if err != nil && strings.HasPrefix(diff, "fatal: ambiguous argument") {
- diff = gui.Tr.SLocalize("NoTrackingThisBranch")
+ graph, err := gui.GitCommand.GetBranchGraph(branch.Name)
+ if err != nil && strings.HasPrefix(graph, "fatal: ambiguous argument") {
+ graph = gui.Tr.SLocalize("NoTrackingThisBranch")
}
- gui.renderString(g, "main", diff)
+ _ = gui.renderString(g, "main", graph)
}()
return nil
}
@@ -173,6 +173,8 @@ func (gui *Gui) refreshBranches(g *gocui.Gui) error {
}
gui.State.Branches = builder.Build()
+ gui.refreshSelectedLine(&gui.State.Panels.Branches.SelectedLine, len(gui.State.Branches))
+
v.Clear()
list, err := utils.RenderList(gui.State.Branches)
if err != nil {
@@ -186,3 +188,17 @@ func (gui *Gui) refreshBranches(g *gocui.Gui) error {
})
return nil
}
+
+func (gui *Gui) handleBranchesNextLine(g *gocui.Gui, v *gocui.View) error {
+ panelState := gui.State.Panels.Branches
+ gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Branches), false)
+
+ return gui.handleBranchSelect(gui.g, v)
+}
+
+func (gui *Gui) handleBranchesPrevLine(g *gocui.Gui, v *gocui.View) error {
+ panelState := gui.State.Panels.Branches
+ gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Branches), true)
+
+ return gui.handleBranchSelect(gui.g, v)
+}
diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go
index ee7f191a7..be291091c 100644
--- a/pkg/gui/commits_panel.go
+++ b/pkg/gui/commits_panel.go
@@ -22,6 +22,8 @@ func (gui *Gui) refreshCommits(g *gocui.Gui) error {
return err
}
+ gui.refreshSelectedLine(&gui.State.Panels.Commits.SelectedLine, len(gui.State.Commits))
+
v.Clear()
list, err := utils.RenderList(gui.State.Commits)
@@ -41,9 +43,9 @@ func (gui *Gui) refreshCommits(g *gocui.Gui) 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 {
- commit, err := gui.getSelectedCommit(g)
- if err != nil {
- panic(err)
+ commit := gui.getSelectedCommit(g)
+ if commit == nil {
+ panic(errors.New(gui.Tr.SLocalize("NoCommitsThisBranch")))
}
if err := gui.GitCommand.ResetToCommit(commit.Sha); err != nil {
return gui.createErrorPanel(g, err.Error())
@@ -59,21 +61,15 @@ func (gui *Gui) handleResetToCommit(g *gocui.Gui, commitView *gocui.View) error
}, nil)
}
-func (gui *Gui) renderCommitsOptions(g *gocui.Gui) error {
- return gui.renderGlobalOptions(g)
-}
-
func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error {
- if err := gui.renderCommitsOptions(g); err != nil {
- return err
- }
- commit, err := gui.getSelectedCommit(g)
- if err != nil {
- if err.Error() != gui.Tr.SLocalize("NoCommitsThisBranch") {
- return err
- }
+ 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
@@ -85,12 +81,12 @@ func (gui *Gui) handleCommitSquashDown(g *gocui.Gui, v *gocui.View) error {
if gui.getItemPosition(v) != 0 {
return gui.createErrorPanel(g, gui.Tr.SLocalize("OnlySquashTopmostCommit"))
}
- if len(gui.State.Commits) == 1 {
+ if len(gui.State.Commits) <= 1 {
return gui.createErrorPanel(g, gui.Tr.SLocalize("YouNoCommitsToSquash"))
}
- commit, err := gui.getSelectedCommit(g)
- if err != nil {
- return err
+ commit := gui.getSelectedCommit(g)
+ if commit == nil {
+ return errors.New(gui.Tr.SLocalize("NoCommitsThisBranch"))
}
if err := gui.GitCommand.SquashPreviousTwoCommits(commit.Name); err != nil {
return gui.createErrorPanel(g, err.Error())
@@ -113,16 +109,16 @@ func (gui *Gui) anyUnStagedChanges(files []*commands.File) bool {
}
func (gui *Gui) handleCommitFixup(g *gocui.Gui, v *gocui.View) error {
- if len(gui.State.Commits) == 1 {
+ if len(gui.State.Commits) <= 1 {
return gui.createErrorPanel(g, gui.Tr.SLocalize("YouNoCommitsToSquash"))
}
if gui.anyUnStagedChanges(gui.State.Files) {
return gui.createErrorPanel(g, gui.Tr.SLocalize("CantFixupWhileUnstagedChanges"))
}
branch := gui.State.Branches[0]
- commit, err := gui.getSelectedCommit(g)
- if err != nil {
- return err
+ commit := gui.getSelectedCommit(g)
+ if commit == nil {
+ return gui.createErrorPanel(g, gui.Tr.SLocalize("NoCommitsThisBranch"))
}
message := gui.Tr.SLocalize("SureFixupThisCommit")
gui.createConfirmationPanel(g, v, gui.Tr.SLocalize("Fixup"), message, func(g *gocui.Gui, v *gocui.View) error {
@@ -165,18 +161,27 @@ func (gui *Gui) handleRenameCommitEditor(g *gocui.Gui, v *gocui.View) error {
return nil
}
-func (gui *Gui) getSelectedCommit(g *gocui.Gui) (*commands.Commit, error) {
- v, err := g.View("commits")
- if err != nil {
- panic(err)
- }
- if len(gui.State.Commits) == 0 {
- return &commands.Commit{}, errors.New(gui.Tr.SLocalize("NoCommitsThisBranch"))
- }
- lineNumber := gui.getItemPosition(v)
- if lineNumber > len(gui.State.Commits)-1 {
- gui.Log.Info(gui.Tr.SLocalize("PotentialErrInGetselectedCommit"), gui.State.Commits, lineNumber)
- return gui.State.Commits[len(gui.State.Commits)-1], 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[lineNumber], 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)
}
diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go
index 5eb8f63f1..13ce48d10 100644
--- a/pkg/gui/files_panel.go
+++ b/pkg/gui/files_panel.go
@@ -140,15 +140,12 @@ func (gui *Gui) handleAddPatch(g *gocui.Gui, v *gocui.View) error {
}
func (gui *Gui) getSelectedFile(g *gocui.Gui) (*commands.File, error) {
- if len(gui.State.Files) == 0 {
+ selectedLine := gui.State.Panels.Files.SelectedLine
+ if selectedLine == -1 {
return &commands.File{}, gui.Errors.ErrNoFiles
}
- filesView, err := g.View("files")
- if err != nil {
- panic(err)
- }
- lineNumber := gui.getItemPosition(filesView)
- return gui.State.Files[lineNumber], nil
+
+ return gui.State.Files[selectedLine], nil
}
func (gui *Gui) handleFileRemove(g *gocui.Gui, v *gocui.View) error {
@@ -194,26 +191,23 @@ func (gui *Gui) handleIgnoreFile(g *gocui.Gui, v *gocui.View) error {
return gui.refreshFiles(g)
}
-func (gui *Gui) renderfilesOptions(g *gocui.Gui, file *commands.File) error {
- return gui.renderGlobalOptions(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
}
- gui.renderString(g, "main", gui.Tr.SLocalize("NoChangedFiles"))
- return gui.renderfilesOptions(g, nil)
- }
- if err := gui.renderfilesOptions(g, file); err != nil {
- 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)
}
@@ -309,6 +303,7 @@ func (gui *Gui) refreshStateFiles() {
// get files to stage
files := gui.GitCommand.GetStatusFiles()
gui.State.Files = gui.GitCommand.MergeStatusFiles(gui.State.Files, files)
+ gui.refreshSelectedLine(&gui.State.Panels.Files.SelectedLine, len(gui.State.Files))
gui.updateHasMergeConflictStatus()
}
@@ -340,6 +335,20 @@ 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 {
@@ -347,17 +356,21 @@ func (gui *Gui) refreshFiles(g *gocui.Gui) error {
}
gui.refreshStateFiles()
- filesView.Clear()
- list, err := utils.RenderList(gui.State.Files)
- if err != nil {
- return err
- }
- fmt.Fprint(filesView, list)
+ 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
+ })
- gui.correctCursor(filesView)
- if filesView == g.CurrentView() {
- gui.handleFileSelect(g, filesView)
- }
return nil
}
diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go
index 9f25121d5..1af3a5e1f 100644
--- a/pkg/gui/gui.go
+++ b/pkg/gui/gui.go
@@ -72,11 +72,35 @@ type Gui struct {
statusManager *statusManager
}
-type stagingState struct {
- StageableLines []int
- HunkStarts []int
- CurrentLineIndex int
- Diff string
+type stagingPanelState struct {
+ SelectedLine int
+ StageableLines []int
+ HunkStarts []int
+ Diff string
+}
+
+type filePanelState struct {
+ SelectedLine int
+}
+
+type branchPanelState struct {
+ SelectedLine int
+}
+
+type commitPanelState struct {
+ SelectedLine int
+}
+
+type stashPanelState struct {
+ SelectedLine int
+}
+
+type panelStates struct {
+ Files *filePanelState
+ Staging *stagingPanelState
+ Branches *branchPanelState
+ Commits *commitPanelState
+ Stash *stashPanelState
}
type guiState struct {
@@ -92,7 +116,7 @@ type guiState struct {
EditHistory *stack.Stack
Platform commands.Platform
Updating bool
- StagingState *stagingState
+ Panels *panelStates
}
// NewGui builds a new gui handler
@@ -108,6 +132,12 @@ func NewGui(log *logrus.Entry, gitCommand *commands.GitCommand, oSCommand *comma
Conflicts: make([]commands.Conflict, 0),
EditHistory: stack.New(),
Platform: *oSCommand.Platform,
+ Panels: &panelStates{
+ Files: &filePanelState{SelectedLine: -1},
+ Branches: &branchPanelState{SelectedLine: 0},
+ Commits: &commitPanelState{SelectedLine: -1},
+ Stash: &stashPanelState{SelectedLine: -1},
+ },
}
gui := &Gui{
@@ -193,9 +223,11 @@ func (gui *Gui) layout(g *gocui.Gui) error {
}
v.Title = gui.Tr.SLocalize("NotEnoughSpace")
v.Wrap = true
- g.SetCurrentView(v.Name())
+ g.SetViewOnTop("limit")
}
return nil
+ } else {
+ g.SetViewOnBottom("limit")
}
g.DeleteView("limit")
@@ -247,12 +279,13 @@ func (gui *Gui) layout(g *gocui.Gui) error {
v.FgColor = gocui.ColorWhite
}
- if v, err := g.SetView("branches", 0, filesBranchesBoundary+panelSpacing, leftSideWidth, commitsBranchesBoundary, gocui.TOP|gocui.BOTTOM); err != nil {
+ branchesView, err := g.SetView("branches", 0, filesBranchesBoundary+panelSpacing, leftSideWidth, commitsBranchesBoundary, gocui.TOP|gocui.BOTTOM)
+ if err != nil {
if err != gocui.ErrUnknownView {
return err
}
- v.Title = gui.Tr.SLocalize("BranchesTitle")
- v.FgColor = gocui.ColorWhite
+ branchesView.Title = gui.Tr.SLocalize("BranchesTitle")
+ branchesView.FgColor = gocui.ColorWhite
}
if v, err := g.SetView("commits", 0, commitsBranchesBoundary+panelSpacing, leftSideWidth, commitsStashBoundary, gocui.TOP|gocui.BOTTOM); err != nil {
@@ -325,11 +358,14 @@ func (gui *Gui) layout(g *gocui.Gui) error {
return err
}
- gui.handleFileSelect(g, filesView)
+ 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
+ }
if err := gui.switchFocus(g, nil, filesView); err != nil {
return err
}
@@ -341,6 +377,17 @@ func (gui *Gui) layout(g *gocui.Gui) error {
}
}
+ listViews := map[*gocui.View]int{
+ filesView: gui.State.Panels.Files.SelectedLine,
+ branchesView: gui.State.Panels.Branches.SelectedLine,
+ }
+ for view, selectedLine := range listViews {
+ // check if the selected line is now out of view and if so refocus it
+ if err := gui.focusPoint(0, selectedLine, view); err != nil {
+ return err
+ }
+ }
+
return gui.resizeCurrentPopupPanel(g)
}
@@ -411,7 +458,7 @@ func (gui *Gui) Run() error {
}
gui.goEvery(g, time.Second*60, gui.fetch)
- gui.goEvery(g, time.Second*10, gui.refreshFiles)
+ // gui.goEvery(g, time.Second*2, gui.refreshFiles) // TODO: comment back in
gui.goEvery(g, time.Millisecond*50, gui.updateLoader)
gui.goEvery(g, time.Millisecond*50, gui.renderAppStatus)
diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go
index 1a63d009c..c8c3d642f 100644
--- a/pkg/gui/keybindings.go
+++ b/pkg/gui/keybindings.go
@@ -219,7 +219,12 @@ func (gui *Gui) GetKeybindings() []*Binding {
Handler: gui.handleSwitchToStagingPanel,
Description: gui.Tr.SLocalize("StageLines"),
KeyReadable: "enter",
- }, {
+ },
+ {ViewName: "files", Key: 'k', Modifier: gocui.ModNone, Handler: gui.handleFilesPrevLine},
+ {ViewName: "files", Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: gui.handleFilesPrevLine},
+ {ViewName: "files", Key: 'j', Modifier: gocui.ModNone, Handler: gui.handleFilesNextLine},
+ {ViewName: "files", Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: gui.handleFilesNextLine},
+ {
ViewName: "main",
Key: gocui.KeyEsc,
Modifier: gocui.ModNone,
@@ -322,7 +327,12 @@ func (gui *Gui) GetKeybindings() []*Binding {
Modifier: gocui.ModNone,
Handler: gui.handleMerge,
Description: gui.Tr.SLocalize("mergeIntoCurrentBranch"),
- }, {
+ },
+ {ViewName: "branches", Key: 'k', Modifier: gocui.ModNone, Handler: gui.handleBranchesPrevLine},
+ {ViewName: "branches", Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: gui.handleBranchesPrevLine},
+ {ViewName: "branches", Key: 'j', Modifier: gocui.ModNone, Handler: gui.handleBranchesNextLine},
+ {ViewName: "branches", Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: gui.handleBranchesNextLine},
+ {
ViewName: "commits",
Key: 's',
Modifier: gocui.ModNone,
@@ -352,7 +362,12 @@ func (gui *Gui) GetKeybindings() []*Binding {
Modifier: gocui.ModNone,
Handler: gui.handleCommitFixup,
Description: gui.Tr.SLocalize("fixupCommit"),
- }, {
+ },
+ {ViewName: "commits", Key: 'k', Modifier: gocui.ModNone, Handler: gui.handleCommitsPrevLine},
+ {ViewName: "commits", Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: gui.handleCommitsPrevLine},
+ {ViewName: "commits", Key: 'j', Modifier: gocui.ModNone, Handler: gui.handleCommitsNextLine},
+ {ViewName: "commits", Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: gui.handleCommitsNextLine},
+ {
ViewName: "stash",
Key: gocui.KeySpace,
Modifier: gocui.ModNone,
@@ -455,17 +470,22 @@ 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", "files", "branches", "commits", "stash", "menu"} {
+ 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},
{ViewName: viewName, Key: gocui.KeyArrowLeft, Modifier: gocui.ModNone, Handler: gui.previousView},
{ViewName: viewName, Key: gocui.KeyArrowRight, Modifier: gocui.ModNone, Handler: gui.nextView},
- {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: 'h', Modifier: gocui.ModNone, Handler: gui.previousView},
{ViewName: viewName, Key: 'l', Modifier: gocui.ModNone, Handler: gui.nextView},
- {ViewName: viewName, Key: 'k', Modifier: gocui.ModNone, Handler: gui.cursorUp},
- {ViewName: viewName, Key: 'j', Modifier: gocui.ModNone, Handler: gui.cursorDown},
}...)
}
diff --git a/pkg/gui/staging_panel.go b/pkg/gui/staging_panel.go
index cba7d7638..1408cfb45 100644
--- a/pkg/gui/staging_panel.go
+++ b/pkg/gui/staging_panel.go
@@ -40,23 +40,23 @@ func (gui *Gui) refreshStagingPanel() error {
return nil
}
- var currentLineIndex int
- if gui.State.StagingState != nil {
+ var selectedLine int
+ if gui.State.Panels.Staging != nil {
end := len(stageableLines) - 1
- if end < gui.State.StagingState.CurrentLineIndex {
- currentLineIndex = end
+ if end < gui.State.Panels.Staging.SelectedLine {
+ selectedLine = end
} else {
- currentLineIndex = gui.State.StagingState.CurrentLineIndex
+ selectedLine = gui.State.Panels.Staging.SelectedLine
}
} else {
- currentLineIndex = 0
+ selectedLine = 0
}
- gui.State.StagingState = &stagingState{
- StageableLines: stageableLines,
- HunkStarts: hunkStarts,
- CurrentLineIndex: currentLineIndex,
- Diff: diff,
+ gui.State.Panels.Staging = &stagingPanelState{
+ StageableLines: stageableLines,
+ HunkStarts: hunkStarts,
+ SelectedLine: selectedLine,
+ Diff: diff,
}
if len(stageableLines) == 0 {
@@ -74,7 +74,7 @@ func (gui *Gui) handleStagingEscape(g *gocui.Gui, v *gocui.View) error {
return err
}
- gui.State.StagingState = nil
+ gui.State.Panels.Staging = nil
return gui.switchFocus(gui.g, nil, gui.getFilesView(gui.g))
}
@@ -96,9 +96,9 @@ func (gui *Gui) handleStagingNextHunk(g *gocui.Gui, v *gocui.View) error {
}
func (gui *Gui) handleCycleHunk(prev bool) error {
- state := gui.State.StagingState
+ state := gui.State.Panels.Staging
lineNumbers := state.StageableLines
- currentLine := lineNumbers[state.CurrentLineIndex]
+ currentLine := lineNumbers[state.SelectedLine]
currentHunkIndex := utils.PrevIndex(state.HunkStarts, currentLine)
var newHunkIndex int
if prev {
@@ -115,22 +115,22 @@ func (gui *Gui) handleCycleHunk(prev bool) error {
}
}
- state.CurrentLineIndex = utils.NextIndex(lineNumbers, state.HunkStarts[newHunkIndex])
+ state.SelectedLine = utils.NextIndex(lineNumbers, state.HunkStarts[newHunkIndex])
return gui.focusLineAndHunk()
}
func (gui *Gui) handleCycleLine(prev bool) error {
- state := gui.State.StagingState
+ state := gui.State.Panels.Staging
lineNumbers := state.StageableLines
- currentLine := lineNumbers[state.CurrentLineIndex]
+ currentLine := lineNumbers[state.SelectedLine]
var newIndex int
if prev {
newIndex = utils.PrevIndex(lineNumbers, currentLine)
} else {
newIndex = utils.NextIndex(lineNumbers, currentLine)
}
- state.CurrentLineIndex = newIndex
+ state.SelectedLine = newIndex
return gui.focusLineAndHunk()
}
@@ -139,9 +139,9 @@ func (gui *Gui) handleCycleLine(prev bool) error {
// selected line and size of the hunk
func (gui *Gui) focusLineAndHunk() error {
stagingView := gui.getStagingView(gui.g)
- state := gui.State.StagingState
+ state := gui.State.Panels.Staging
- lineNumber := state.StageableLines[state.CurrentLineIndex]
+ lineNumber := state.StageableLines[state.SelectedLine]
// we want the bottom line of the view buffer to ideally be the bottom line
// of the hunk, but if the hunk is too big we'll just go three lines beyond
@@ -170,23 +170,7 @@ func (gui *Gui) focusLineAndHunk() error {
bottomLine = lineNumber + 3
}
- return gui.focusLine(lineNumber, bottomLine, stagingView)
-}
-
-// focusLine takes a lineNumber to focus, and a bottomLine to ensure we can see
-func (gui *Gui) focusLine(lineNumber int, bottomLine int, v *gocui.View) error {
- _, height := v.Size()
- overScroll := bottomLine - height + 1
- if overScroll < 0 {
- overScroll = 0
- }
- if err := v.SetOrigin(0, overScroll); err != nil {
- return err
- }
- if err := v.SetCursor(0, lineNumber-overScroll); err != nil {
- return err
- }
- return nil
+ return gui.generalFocusLine(lineNumber, bottomLine, stagingView)
}
func (gui *Gui) handleStageHunk(g *gocui.Gui, v *gocui.View) error {
@@ -198,13 +182,13 @@ func (gui *Gui) handleStageLine(g *gocui.Gui, v *gocui.View) error {
}
func (gui *Gui) handleStageLineOrHunk(hunk bool) error {
- state := gui.State.StagingState
+ state := gui.State.Panels.Staging
p, err := git.NewPatchModifier(gui.Log)
if err != nil {
return err
}
- currentLine := state.StageableLines[state.CurrentLineIndex]
+ currentLine := state.StageableLines[state.SelectedLine]
var patch string
if hunk {
patch, err = p.ModifyPatchForHunk(state.Diff, state.HunkStarts, currentLine)
diff --git a/pkg/gui/stash_panel.go b/pkg/gui/stash_panel.go
index 62b4efda7..196a33a08 100644
--- a/pkg/gui/stash_panel.go
+++ b/pkg/gui/stash_panel.go
@@ -37,14 +37,7 @@ func (gui *Gui) getSelectedStashEntry(v *gocui.View) *commands.StashEntry {
return gui.State.StashEntries[lineNumber]
}
-func (gui *Gui) renderStashOptions(g *gocui.Gui) error {
- return gui.renderGlobalOptions(g)
-}
-
func (gui *Gui) handleStashEntrySelect(g *gocui.Gui, v *gocui.View) error {
- if err := gui.renderStashOptions(g); err != nil {
- return err
- }
go func() {
stashEntry := gui.getSelectedStashEntry(v)
if stashEntry == nil {
diff --git a/pkg/gui/status_panel.go b/pkg/gui/status_panel.go
index aeae19c50..15f3f27d1 100644
--- a/pkg/gui/status_panel.go
+++ b/pkg/gui/status_panel.go
@@ -42,10 +42,6 @@ func (gui *Gui) refreshStatus(g *gocui.Gui) error {
return nil
}
-func (gui *Gui) renderStatusOptions(g *gocui.Gui) error {
- return gui.renderGlobalOptions(g)
-}
-
func (gui *Gui) handleCheckForUpdate(g *gocui.Gui, v *gocui.View) error {
gui.Updater.CheckForNewUpdate(gui.onUserUpdateCheckFinish, true)
return gui.createMessagePanel(gui.g, v, "", gui.Tr.SLocalize("CheckingForUpdates"))
@@ -63,10 +59,7 @@ func (gui *Gui) handleStatusSelect(g *gocui.Gui, v *gocui.View) error {
"Buy Jesse a coffee: https://donorbox.org/lazygit",
}, "\n\n")
- if err := gui.renderString(g, "main", dashboardString); err != nil {
- return err
- }
- return gui.renderStatusOptions(g)
+ return gui.renderString(g, "main", dashboardString)
}
func (gui *Gui) handleOpenConfig(g *gocui.Gui, v *gocui.View) error {
diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go
index 525b05f97..4c5002efe 100644
--- a/pkg/gui/view_helpers.go
+++ b/pkg/gui/view_helpers.go
@@ -230,19 +230,46 @@ func (gui *Gui) resetOrigin(v *gocui.View) error {
// 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()
- ox, oy := v.Origin()
- _, height := v.Size()
- maxY := height - 1
- ly := v.LinesHeight() - 1
- if oy+cy <= ly {
+ 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 {
return nil
}
- newCy := utils.Min(ly, maxY)
- if err := v.SetCursor(cx, newCy); err != nil {
- return err
- }
- if err := v.SetOrigin(ox, ly-newCy); err != nil {
- return err
+ ox, oy := v.Origin()
+ _, height := v.Size()
+ ly := height - 1
+
+ // if line is above origin, move origin and set cursor to zero
+ // if line is below origin + height, move origin and set cursor to max
+ // otherwise set cursor to value - origin
+ if ly > v.LinesHeight() {
+ if err := v.SetCursor(cx, cy); err != nil {
+ return err
+ }
+ if err := v.SetOrigin(ox, 0); err != nil {
+ return err
+ }
+ } else if cy < oy {
+ if err := v.SetCursor(cx, 0); err != nil {
+ return err
+ }
+ if err := v.SetOrigin(ox, cy); err != nil {
+ return err
+ }
+ } else if cy > oy+ly {
+ if err := v.SetCursor(cx, ly); err != nil {
+ return err
+ }
+ if err := v.SetOrigin(ox, cy-ly); err != nil {
+ return err
+ }
+ } else {
+ if err := v.SetCursor(cx, cy-oy); err != nil {
+ return err
+ }
}
return nil
}
@@ -334,3 +361,59 @@ func (gui *Gui) resizePopupPanel(g *gocui.Gui, v *gocui.View) error {
_, err := g.SetView(v.Name(), x0, y0, x1, y1, 0)
return err
}
+
+// focusLine focuses and selects the given line
+func (gui *Gui) focusLine(lineNumber int, v *gocui.View) error {
+ _, height := v.Size()
+ overScroll := lineNumber - height + 1
+ if overScroll < 0 {
+ overScroll = 0
+ }
+ if err := v.SetOrigin(0, overScroll); err != nil {
+ return err
+ }
+ if err := v.SetCursor(0, lineNumber-overScroll); err != nil {
+ return err
+ }
+ return nil
+}
+
+// generalFocusLine takes a lineNumber to focus, and a bottomLine to ensure we can see
+func (gui *Gui) generalFocusLine(lineNumber int, bottomL