summaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2020-08-16 13:58:29 +1000
committerJesse Duffield <jessedduffield@gmail.com>2020-08-23 14:29:18 +1000
commit7f89113245307be8a1642105014e9ce51a47210f (patch)
tree0b1237c4bdd4a465bedb7cc49c8372d0bfc46ea5 /pkg
parent0ea0c486310558e26af7ad6e4fcf17f57c2b62e3 (diff)
WIP
Diffstat (limited to 'pkg')
-rw-r--r--pkg/gui/arrangement.go33
-rw-r--r--pkg/gui/commit_files_panel.go10
-rw-r--r--pkg/gui/commit_message_panel.go10
-rw-r--r--pkg/gui/commits_panel.go6
-rw-r--r--pkg/gui/confirmation_panel.go12
-rw-r--r--pkg/gui/context.go381
-rw-r--r--pkg/gui/credentials_panel.go17
-rw-r--r--pkg/gui/files_panel.go22
-rw-r--r--pkg/gui/gui.go11
-rw-r--r--pkg/gui/keybindings.go14
-rw-r--r--pkg/gui/layout.go77
-rw-r--r--pkg/gui/line_by_line_panel.go2
-rw-r--r--pkg/gui/list_view.go108
-rw-r--r--pkg/gui/menu_panel.go15
-rw-r--r--pkg/gui/merge_panel.go2
-rw-r--r--pkg/gui/patch_building_panel.go2
-rw-r--r--pkg/gui/reflog_panel.go2
-rw-r--r--pkg/gui/remote_branches_panel.go2
-rw-r--r--pkg/gui/remotes_panel.go2
-rw-r--r--pkg/gui/searching.go6
-rw-r--r--pkg/gui/side_window.go66
-rw-r--r--pkg/gui/stack/stack.go21
-rw-r--r--pkg/gui/staging_panel.go14
-rw-r--r--pkg/gui/stash_panel.go2
-rw-r--r--pkg/gui/tags_panel.go1
-rw-r--r--pkg/gui/view_helpers.go192
-rw-r--r--pkg/gui/window.go37
-rw-r--r--pkg/i18n/dutch.go3
-rw-r--r--pkg/i18n/english.go3
-rw-r--r--pkg/i18n/polish.go3
30 files changed, 615 insertions, 461 deletions
diff --git a/pkg/gui/arrangement.go b/pkg/gui/arrangement.go
index 25988bbd2..49311b6d4 100644
--- a/pkg/gui/arrangement.go
+++ b/pkg/gui/arrangement.go
@@ -244,27 +244,22 @@ func (gui *Gui) sidePanelChildren(width int, height int) []*boxlayout.Box {
}
func (gui *Gui) currentCyclableViewName() string {
- currView := gui.g.CurrentView()
- currentCyclebleView := gui.State.PreviousView
- if currView != nil {
- viewName := currView.Name()
- usePreviousView := true
- for _, view := range gui.getCyclableViews() {
- if view == viewName {
- currentCyclebleView = viewName
- usePreviousView = false
- break
+ // there is always a cyclable context in the context stack. We'll look from top to bottom
+ for idx := range gui.State.ContextStack {
+ reversedIdx := len(gui.State.ContextStack) - 1 - idx
+ context := gui.State.ContextStack[reversedIdx]
+
+ if context.GetKind() == SIDE_CONTEXT {
+ viewName := context.GetViewName()
+
+ // unfortunate result of the fact that these are separate views, have to map explicitly
+ if viewName == "commitFiles" {
+ return "commits"
}
- }
- if usePreviousView {
- currentCyclebleView = gui.State.PreviousView
- }
- }
- // unfortunate result of the fact that these are separate views, have to map explicitly
- if currentCyclebleView == "commitFiles" {
- return "commits"
+ return viewName
+ }
}
- return currentCyclebleView
+ return "files" // default
}
diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go
index e2018480b..d37f3fd5e 100644
--- a/pkg/gui/commit_files_panel.go
+++ b/pkg/gui/commit_files_panel.go
@@ -44,8 +44,6 @@ func (gui *Gui) handleCommitFileSelect() error {
return err
}
- gui.getCommitFilesView().FocusPoint(0, gui.State.Panels.CommitFiles.SelectedLine)
-
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowCommitFileCmdStr(commitFile.Sha, commitFile.Name, false),
)
@@ -57,7 +55,7 @@ func (gui *Gui) handleCommitFileSelect() error {
}
func (gui *Gui) handleSwitchToCommitsPanel(g *gocui.Gui, v *gocui.View) error {
- return gui.switchFocus(v, gui.getCommitsView())
+ return gui.switchContext(gui.Contexts.BranchCommits.Context)
}
func (gui *Gui) handleCheckoutCommitFile(g *gocui.Gui, v *gocui.View) error {
@@ -223,8 +221,8 @@ func (gui *Gui) enterCommitFile(selectedLineIdx int) error {
}
}
- gui.changeMainViewsContext("patch-building")
- if err := gui.switchFocus(gui.getCommitFilesView(), gui.getMainView()); err != nil {
+ gui.changeMainViewsContext("patch-building") // TODO: bring into context code
+ if err := gui.switchContext(gui.Contexts.PatchBuilding.Context); err != nil {
return err
}
return gui.refreshPatchBuildingPanel(selectedLineIdx)
@@ -241,7 +239,7 @@ func (gui *Gui) enterCommitFile(selectedLineIdx int) error {
return enterTheFile(selectedLineIdx)
},
handleClose: func() error {
- return gui.switchFocus(nil, gui.getCommitFilesView())
+ return gui.switchContext(gui.Contexts.BranchCommits.Files.Context)
},
})
}
diff --git a/pkg/gui/commit_message_panel.go b/pkg/gui/commit_message_panel.go
index 9c1a3ff52..f84abcdeb 100644
--- a/pkg/gui/commit_message_panel.go
+++ b/pkg/gui/commit_message_panel.go
@@ -44,19 +44,19 @@ func (gui *Gui) handleCommitConfirm(g *gocui.Gui, v *gocui.View) error {
}
v.Clear()
+ _, _ = g.SetViewOnBottom("commitMessage") // TODO: bring into context code
_ = v.SetCursor(0, 0)
_ = v.SetOrigin(0, 0)
- _, _ = g.SetViewOnBottom("commitMessage")
- _ = gui.switchFocus(v, gui.getFilesView())
+ _ = gui.returnFromContext()
return gui.refreshSidePanels(refreshOptions{mode: ASYNC})
}
func (gui *Gui) handleCommitClose(g *gocui.Gui, v *gocui.View) error {
- _, _ = g.SetViewOnBottom("commitMessage")
- return gui.switchFocus(v, gui.getFilesView())
+ _, _ = g.SetViewOnBottom("commitMessage") // TODO: bring into context code
+ return gui.returnFromContext()
}
-func (gui *Gui) handleCommitFocused() error {
+func (gui *Gui) handleCommitMessageFocused() error {
if _, err := gui.g.SetViewOnTop("commitMessage"); err != nil {
return err
}
diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go
index 018782a34..6d88d30f9 100644
--- a/pkg/gui/commits_panel.go
+++ b/pkg/gui/commits_panel.go
@@ -54,8 +54,6 @@ func (gui *Gui) handleCommitSelect() error {
return gui.newStringTask("main", gui.Tr.SLocalize("NoCommitsThisBranch"))
}
- gui.getCommitsView().FocusPoint(0, gui.State.Panels.Commits.SelectedLine)
-
if gui.inDiffMode() {
return gui.renderDiff()
}
@@ -104,7 +102,7 @@ func (gui *Gui) refreshCommits() error {
go func() {
_ = gui.refreshCommitsWithLimit()
- if gui.g.CurrentView() == gui.getCommitFilesView() || (gui.g.CurrentView() == gui.getMainView() && gui.State.MainContext == "patch-building") {
+ if gui.g.CurrentView() == gui.getCommitFilesView() || (gui.currentContext().GetKey() == gui.Contexts.PatchBuilding.Context.GetKey()) {
_ = gui.refreshCommitFilesView()
}
wg.Done()
@@ -528,7 +526,7 @@ func (gui *Gui) handleSwitchToCommitFilesPanel() error {
return err
}
- return gui.switchFocus(gui.getCommitsView(), gui.getCommitFilesView())
+ return gui.switchContext(gui.Contexts.BranchCommits.Files.Context)
}
func (gui *Gui) hasCommit(commits []*commands.Commit, target string) (int, bool) {
diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go
index a7e41b246..3ead76fc1 100644
--- a/pkg/gui/confirmation_panel.go
+++ b/pkg/gui/confirmation_panel.go
@@ -94,15 +94,13 @@ func (gui *Gui) wrappedPromptConfirmationFunction(function func(string) error, r
}
func (gui *Gui) closeConfirmationPrompt(returnFocusOnClose bool) error {
- view, err := gui.g.View("confirmation")
- if err != nil {
+ view := gui.getConfirmationView()
+ if view == nil {
return nil // if it's already been closed we can just return
}
view.Editable = false
- if returnFocusOnClose {
- if err := gui.returnFocus(view); err != nil {
- panic(err)
- }
+ if err := gui.returnFromContext(); err != nil {
+ return err
}
gui.g.DeleteKeybinding("confirmation", gui.getKey("universal.confirm"), gocui.ModNone)
@@ -164,7 +162,7 @@ func (gui *Gui) prepareConfirmationPanel(currentView *gocui.View, title, prompt
confirmationView.FgColor = theme.GocuiDefaultTextColor
}
gui.g.Update(func(g *gocui.Gui) error {
- return gui.switchFocus(currentView, confirmationView)
+ return gui.switchContext(gui.Contexts.Confirmation.Context)
})
return confirmationView, nil
}
diff --git a/pkg/gui/context.go b/pkg/gui/context.go
index 06664571f..b209156da 100644
--- a/pkg/gui/context.go
+++ b/pkg/gui/context.go
@@ -1,7 +1,8 @@
package gui
import (
- "github.com/jesseduffield/lazygit/pkg/gui/stack"
+ "github.com/golang-collections/collections/stack"
+ "github.com/jesseduffield/gocui"
)
// changeContext is a helper function for when we want to change a 'main' context
@@ -22,6 +23,27 @@ func (gui *Gui) changeMainViewsContext(context string) {
gui.State.MainContext = context
}
+type Stack struct {
+ stack []Context
+}
+
+func (s *Stack) Push(contextKey Context) {
+ s.stack = append(s.stack, contextKey)
+}
+
+func (s *Stack) Pop() (Context, bool) {
+ if len(s.stack) == 0 {
+ return nil, false
+ }
+
+ n := len(s.stack) - 1
+ value := s.stack[n]
+ s.stack = s.stack[:n]
+
+ return value, true
+}
+
+// the context manager maintains a stack of contexts so that we can easily switch focus back and forth
type contextManager struct {
gui *Gui
stack stack.Stack
@@ -33,54 +55,345 @@ func (c *contextManager) push(contextKey string) {
// push focus, pop focus.
+const (
+ SIDE_CONTEXT int = iota
+ MAIN_CONTEXT
+ TEMPORARY_POPUP
+ PERSISTENT_POPUP
+)
+
+func GetKindWrapper(k int) func() int { return func() int { return k } }
+
type Context interface {
- OnFocus() error
+ HandleFocus() error
+ HandleFocusLost() error
+ GetKind() int
+ GetViewName() string
+ GetKey() string
}
-type SimpleContext struct {
- Self Context
+type BasicContext struct {
+ OnFocus func() error
+ OnFocusLost func() error
+ Kind int
+ Key string
+ ViewName string
}
-type RemotesContext struct {
- Self Context
- Branches Context
+func (c BasicContext) GetViewName() string {
+ return c.ViewName
}
-type CommitsContext struct {
- Self Context
- Files Context
+func (c BasicContext) HandleFocus() error {
+ return c.OnFocus()
+}
+
+func (c BasicContext) HandleFocusLost() error {
+ if c.OnFocusLost != nil {
+ return c.OnFocusLost()
+ }
+ return nil
+}
+
+func (c BasicContext) GetKind() int {
+ return c.Kind
+}
+
+func (c BasicContext) GetKey() string {
+ return c.Key
+}
+
+type SimpleContextNode struct {
+ Context Context
+}
+
+type RemotesContextNode struct {
+ Context Context
+ Branches SimpleContextNode
+}
+
+type CommitsContextNode struct {
+ Context Context
+ Files SimpleContextNode
}
type ContextTree struct {
- Status SimpleContext
- Files SimpleContext
- Branches SimpleContext
- Remotes RemotesContext
- Tags SimpleContext
- Commits CommitsContext
- Stash SimpleContext
- Staging SimpleContext
- PatchBuilding SimpleContext
- Merging SimpleContext
- Menu SimpleContext
- Credentials SimpleContext
- Confirmation SimpleContext
- CommitMessage SimpleContext
+ Status SimpleContextNode
+ Files SimpleContextNode
+ Menu SimpleContextNode
+ Branches SimpleContextNode
+ Remotes RemotesContextNode
+ Tags SimpleContextNode
+ BranchCommits CommitsContextNode
+ ReflogCommits SimpleContextNode
+ Stash SimpleContextNode
+ Staging SimpleContextNode
+ PatchBuilding SimpleContextNode
+ Merging SimpleContextNode
+ Credentials SimpleContextNode
+ Confirmation SimpleContextNode
+ CommitMessage SimpleContextNode
+ Search SimpleContextNode
+}
+
+func (gui *Gui) switchContext(c Context) error {
+ // push onto stack
+ // if we are switching to a side context, remove all other contexts in the stack
+ if c.GetKind() == SIDE_CONTEXT {
+ gui.State.ContextStack = []Context{c}
+ } else {
+ // TODO: think about other exceptional cases
+ gui.State.ContextStack = append(gui.State.ContextStack, c)
+ }
+
+ return gui.activateContext(c)
+}
+
+// switchContextToView is to be used when you don't know which context you
+// want to switch to: you only know the view that you want to switch to. It will
+// look up the context currently active for that view and switch to that context
+func (gui *Gui) switchContextToView(viewName string) error {
+ return gui.switchContext(gui.State.ViewContextMap[viewName])
+}
+
+func (gui *Gui) renderContextStack() string {
+ result := ""
+ for _, context := range gui.State.ContextStack {
+ result += context.GetViewName() + "\n"
+ }
+ return result
+}
+
+func (gui *Gui) activateContext(c Context) error {
+ gui.Log.Warn(gui.renderContextStack())
+
+ if _, err := gui.g.SetCurrentView(c.GetViewName()); err != nil {
+ return err
+ }
+
+ if _, err := gui.g.SetViewOnTop(c.GetViewName()); err != nil {
+ return err
+ }
+
+ newView := gui.g.CurrentView()
+
+ gui.g.Cursor = newView.Editable
+
+ // TODO: move this logic to the context
+ if err := gui.renderPanelOptions(); err != nil {
+ return err
+ }
+
+ // return gui.newLineFocused(newView)
+
+ if err := c.HandleFocus(); err != nil {
+ return err
+ }
+
+ gui.State.ViewContextMap[c.GetViewName()] = c
+
+ return nil
+}
+
+func (gui *Gui) returnFromContext() error {
+ // TODO: add mutexes
+
+ if len(gui.State.ContextStack) == 1 {
+ // cannot escape from bottommost context
+ return nil
+ }
+
+ n := len(gui.State.ContextStack) - 1
+
+ currentContext := gui.State.ContextStack[n]
+ newContext := gui.State.ContextStack[n-1]
+
+ gui.State.ContextStack = gui.State.ContextStack[:n]
+
+ if err := currentContext.HandleFocusLost(); err != nil {
+ return err
+ }
+
+ return gui.activateContext(newContext)
+}
+
+func (gui *Gui) currentContext() Context {
+ return gui.State.ContextStack[len(gui.State.ContextStack)-1]
}
func (gui *Gui) createContextTree() {
- gui.State.Contexts = ContextTree{
- Files: SimpleContext{
- Self: gui.filesListView(),
+ gui.Contexts = ContextTree{
+ Status: SimpleContextNode{
+ Context: BasicContext{
+ OnFocus: gui.handleStatusSelect,
+ Kind: SIDE_CONTEXT,
+ ViewName: "status",
+ },
+ },
+ Files: SimpleContextNode{
+ Context: gui.filesListView(),
+ },
+ Menu: SimpleContextNode{
+ Context: gui.menuListView(),
+ },
+ Remotes: RemotesContextNode{
+ Context: gui.remotesListView(),
+ Branches: SimpleContextNode{
+ Context: gui.remoteBranchesListView(),
+ },
+ },
+ BranchCommits: CommitsContextNode{
+ Context: gui.branchCommitsListView(),
+ Files: SimpleContextNode{
+ Context: gui.commitFilesListView(),
+ },
+ },
+ ReflogCommits: SimpleContextNode{
+ Context: gui.reflogCommitsListView(),
+ },
+ Branches: SimpleContextNode{
+ Context: gui.branchesListView(),
+ },
+ Tags: SimpleContextNode{
+ Context: gui.tagsListView(),
+ },
+ Stash: SimpleContextNode{
+ Context: gui.stashListView(),
+ },
+ Staging: SimpleContextNode{
+ Context: BasicContext{
+ // TODO: think about different situations where this arises
+ OnFocus: func() error {
+ return gui.refreshStagingPanel(false, -1)
+ },
+ Kind: MAIN_CONTEXT,
+ ViewName: "main",
+ Key: "staging",
+ },
+ },
+ PatchBuilding: SimpleContextNode{
+ Context: BasicContext{
+ // TODO: think about different situations where this arises
+ OnFocus: func() error {
+ return gui.refreshPatchBuildingPanel(-1)
+ },
+ Kind: MAIN_CONTEXT,
+ ViewName: "main",
+ Key: "patch-building",
+ },
},
+ Merging: SimpleContextNode{
+ Context: BasicContext{
+ // TODO: think about different situations where this arises
+ OnFocus: func() error {
+ return gui.refreshMergePanel()
+ },
+ Kind: MAIN_CONTEXT,
+ ViewName: "main",
+ Key: "merging",
+ },
+ },
+ Credentials: SimpleContextNode{
+ Context: BasicContext{
+ OnFocus: func() error { return gui.handleCredentialsViewFocused() },
+ Kind: PERSISTENT_POPUP,
+ ViewName: "credentials",
+ Key: "credentials",
+ },
+ },
+ Confirmation: SimpleContextNode{
+ Context: BasicContext{
+ OnFocus: func() error { return nil },
+ Kind: TEMPORARY_POPUP,
+ ViewName: "confirmation",
+ Key: "confirmation",
+ },
+ },
+ CommitMessage: SimpleContextNode{
+ Context: BasicContext{
+ OnFocus: func() error { return gui.handleCommitMessageFocused() },
+ Kind: PERSISTENT_POPUP,
+ ViewName: "commitMessage",
+ Key: "commit-message",
+ },
+ },
+ Search: SimpleContextNode{
+ Context: BasicContext{
+ OnFocus: func() error { return nil },
+ Kind: PERSISTENT_POPUP,
+ ViewName: "search",
+ Key: "search",
+ },
+ },
+ }
+
+ gui.State.ViewContextMap = map[string]Context{
+ "status": gui.Contexts.Status.Context,
+ "files": gui.Contexts.Files.Context,
+ "branches": gui.Contexts.Branches.Context,
+ "commits": gui.Contexts.BranchCommits.Context,
+ "stash": gui.Contexts.Stash.Context,
+ "menu": gui.Contexts.Menu.Context,
+ "confirmation": gui.Contexts.Confirmation.Context,
+ "credentials": gui.Contexts.Credentials.Context,
+ "commitMessage": gui.Contexts.CommitMessage.Context,
+ "main": gui.Contexts.Staging.Context,
}
}
-// func (c *contextManager) pop() (string, bool) {
-// value, ok := c.stack.Pop()
+// getFocusLayout returns a manager function for when view gain and lose focus
+func (gui *Gui) getFocusLayout() func(g *gocui.Gui) error {
+ var previousView *gocui.View
+ return func(g *gocui.Gui) error {
+ newView := gui.g.CurrentView()
+ if err := gui.onFocusChange(); err != nil {
+ return err
+ }
+ // for now we don't consider losing focus to a popup panel as actually losing focus
+ if newView != previousView && !gui.isPopupPanel(newView.Name()) {
+ if err := gui.onViewFocusLost(previousView, newView); err != nil {
+ return err
+ }
+
+ if err := gui.onViewFocus(newView); err != nil {
+ return err
+ }
+ previousView = newView
+ }
+ return nil
+ }
+}
-// if !ok {
-// // bottom of the stack, let's go to the default context: the files context
-// c.gui.switchFocus(nil, newView)
-// }
-// }
+func (gui *Gui) onFocusChange() error {
+ currentView := gui.g.CurrentView()
+ for _, view := range gui.g.Views() {
+ view.Highlight = view.Name() != "main" && view == currentView
+ }
+ return nil
+}
+
+func (gui *Gui) onViewFocusLost(v *gocui.View, newView *gocui.View) error {
+ if v == nil {
+ return nil
+ }
+
+ if v.IsSearching() && newView.Name() != "search" {
+ if err := gui.onSearchEscape(); err != nil {
+ return err
+ }
+ }
+
+ if v.Name() == "main" {
+ // if we have lost focus to a first-class panel, we need to do some cleanup
+ gui.changeMainViewsContext("normal")
+ }
+
+ gui.Log.Info(v.Name() + " focus lost")
+ return nil
+}
+
+func (gui *Gui) onViewFocus(newView *gocui.View) error {
+ gui.setViewAsActiveForWindow(newView.Name())
+
+ return nil
+}
diff --git a/pkg/gui/credentials_panel.go b/pkg/gui/credentials_panel.go
index ede5c865c..d1eed5b25 100644
--- a/pkg/gui/credentials_panel.go
+++ b/pkg/gui/credentials_panel.go
@@ -20,10 +20,11 @@ func (gui *Gui) promptUserForCredential(passOrUname string) string {
credentialsView.Title = gui.Tr.SLocalize("CredentialsPassword")
credentialsView.Mask = '*'
}
- err := gui.switchFocus(gui.g.CurrentView(), credentialsView)
- if err != nil {
+
+ if err := gui.switchContext(gui.Contexts.Credentials.Context); err != nil {
return err
}
+
gui.RenderCommitLength()
return nil
})
@@ -38,15 +39,11 @@ func (gui *Gui) handleSubmitCredential(g *gocui.Gui, v *gocui.View) error {
gui.credentials <- message
v.Clear()
_ = v.SetCursor(0, 0)
- _, _ = g.SetViewOnBottom("credentials")
- nextView, err := gui.g.View("confirmation")
- if err != nil {
- nextView = gui.getFilesView()
- }
- err = gui.switchFocus(nil, nextView)
- if err != nil {
+ _, _ = g.SetViewOnBottom("credentials") // TODO: move to context code
+ if err := gui.returnFromContext(); err != nil {
return err
}
+
return gui.refreshSidePanels(refreshOptions{})
}
@@ -57,7 +54,7 @@ func (gui *Gui) handleCloseCredentialsView(g *gocui.Gui, v *gocui.View) error {
}
gui.credentials <- ""
- return gui.switchFocus(nil, gui.getFilesView())
+ return gui.returnFromContext()
}
func (gui *Gui) handleCredentialsViewFocused() error {
diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go
index 37918067d..a2e51d7c8 100644
--- a/pkg/gui/files_panel.go
+++ b/pkg/gui/files_panel.go
@@ -171,11 +171,10 @@ func (gui *Gui) enterFile(forceSecondaryFocused bool, selectedLineIdx int) error
if file.HasMergeConflicts {
return gui.createErrorPanel(gui.Tr.SLocalize("FileStagingRequirements"))
}
- gui.changeMainViewsContext("staging")
- if err := gui.switchFocus(gui.getFilesView(), gui.getMainView()); err != nil {
- return err
- }
- return gui.refreshStagingPanel(forceSecondaryFocused, selectedLineIdx)
+ gui.changeMainViewsContext("staging") // TODO: move into context code
+ gui.switchContext(gui.Contexts.Staging.Context)
+
+ return gui.refreshStagingPanel(forceSecondaryFocused, selectedLineIdx) // TODO: check if this is broken, try moving into context code
}
func (gui *Gui) handleFilePress() error {
@@ -310,11 +309,7 @@ func (gui *Gui) handleCommitPress() error {
}
gui.g.Update(func(g *gocui.Gui) error {
- if _, err := g.SetViewOnTop("commitMessage"); err != nil {
- return err
- }
-
- if err := gui.switchFocus(gui.getFilesView(), commitMessageView); err != nil {
+ if err := gui.switchContext(gui.Contexts.CommitMessage.Context); err != nil {
return err
}
@@ -596,11 +591,8 @@ func (gui *Gui) handleSwitchToMerge() error {
if !file.HasInlineMergeConflicts {
return gui.createErrorPanel(gui.Tr.SLocalize("FileNoMergeCons"))
}
- gui.changeMainViewsContext("merging")
- if err := gui.switchFocus(gui.g.CurrentView(), gui.getMainView()); err != nil {
- return err
- }
- return gui.refreshMergePanel()
+ gui.changeMainViewsContext("merging") // TODO: move into context code
+ return gui.switchContext(gui.Contexts.Merging.Context)
}
func (gui *Gui) openFile(filename string) error {
diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go
index 5530032d9..0ddf4b2ce 100644
--- a/pkg/gui/gui.go
+++ b/pkg/gui/gui.go
@@ -97,6 +97,7 @@ type Gui struct {
// when lazygit is opened outside a git directory we want to open to the most
// recent repo with the recent repos popup showing
showRecentRepos bool
+ Contexts ContextTree
}
// for now the staging panel state, unlike the other panel states, is going to be
@@ -237,7 +238,15 @@ type guiState struct {
FilterPath string // the filename that gets passed to git log
Diff DiffState
- Contexts ContextTree
+ ContextStack []Context
+ ViewContextMap map[string]Context
+
+ // WindowViewNameMap is a mapping of windows to the current view of that window.
+ // Currently the only case where the distinction between a window and a view
+ // matters is with the commits view and the commitFiles view which both appear
+ // in the same place (and thus constitute the 'commits' window).
+ // If a window contains only one view, it shares the same name as the view.
+ WindowViewNameMap map[string]string
}
func (gui *Gui) resetState() {
diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go
index 102cc62a6..a1d51d356 100644
--- a/pkg/gui/keybindings.go
+++ b/pkg/gui/keybindings.go
@@ -1393,17 +1393,17 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
for _, viewName := range []string{"status", "branches", "files", "commits", "commitFiles", "stash", "menu"} {
bindings = append(bindings, []*Binding{
- {ViewName: viewName, Key: gui.getKey("universal.togglePanel"), Modifier: gocui.ModNone, Handler: gui.nextView},
- {ViewName: viewName, Key: gui.getKey("universal.prevBlock"), Modifier: gocui.ModNone, Handler: gui.previousView},
- {ViewName: viewName, Key: gui.getKey("universal.nextBlock"), Modifier: gocui.ModNone, Handler: gui.nextView},
- {ViewName: viewName, Key: gui.getKey("universal.prevBlock-alt"), Modifier: gocui.ModNone, Handler: gui.previousView},
- {ViewName: viewName, Key: gui.getKey("universal.nextBlock-alt"), Modifier: gocui.ModNone, Handler: gui.nextView},
+ {ViewName: viewName, Key: gui.getKey("universal.togglePanel"), Modifier: gocui.ModNone, Handler: gui.wrappedHandler(gui.nextSideWindow)},
+ {ViewName: viewName, Key: gui.getKey("universal.prevBlock"), Modifier: gocui.ModNone, Handler: gui.wrappedHandler(gui.previousSideWindow)},
+ {ViewName: viewName, Key: gui.getKey("universal.nextBlock"), Modifier: gocui.ModNone, Handler: gui.wrappedHandler(gui.nextSideWindow)},
+ {ViewName: viewName, Key: gui.getKey("universal.prevBlock-alt"), Modifier: gocui.ModNone, Handler: gui.wrappedHandler(gui.previousSideWindow)},
+ {ViewName: viewName, Key: gui.getKey("universal.nextBlock-alt"), Modifier: gocui.ModNone, Handler: gui.wrappedHandler(gui.nextSideWindow)},
}...)
}
// Appends keybindings to jump to a particular sideView using numbers
- for i, viewName := range []string{"status", "files", "branches", "commits", "stash"} {
- bindings = append(bindings, &Binding{ViewName: "", Key: rune(i+1) + '0', Modifier: gocui.ModNone, Handler: gui.goToSideView(viewName)})
+ for i, window := range []string{"status", "files", "branches", "commits", "stash"} {
+ bindings = append(bindings, &Binding{ViewName: "", Key: rune(i+1) + '0', Modifier: gocui.ModNone, Handler: gui.goToSideWindow(window)})
}
for _, listView := range gui.getListViews() {
diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go
index 7e7772d88..66f2eca5e 100644
--- a/pkg/gui/layout.go
+++ b/pkg/gui/layout.go
@@ -12,68 +12,6 @@ import (
const SEARCH_PREFIX = "search: "
const INFO_SECTION_PADDING = " "
-// getFocusLayout returns a manager function for when view gain and lose focus
-func (gui *Gui) getFocusLayout() func(g *gocui.Gui) error {
- var previousView *gocui.View
- return func(g *gocui.Gui) error {
- newView := gui.g.CurrentView()