diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2020-08-19 19:07:14 +1000 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2020-08-23 14:29:18 +1000 |
commit | 2b812b01e9d80409a0bf212eb7208dcdd6f5c974 (patch) | |
tree | 4c1b0cd51ba170c92bc38410ec6005373736720b | |
parent | 2f5d5034dbe4523c44faa58ba6f30c2fef06c128 (diff) |
more standardisation of rendering
-rw-r--r-- | pkg/gui/branches_panel.go | 2 | ||||
-rw-r--r-- | pkg/gui/context.go | 343 | ||||
-rw-r--r-- | pkg/gui/global_handlers.go | 26 | ||||
-rw-r--r-- | pkg/gui/searching.go | 2 |
4 files changed, 212 insertions, 161 deletions
diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go index a783f49fe..b82301aaa 100644 --- a/pkg/gui/branches_panel.go +++ b/pkg/gui/branches_panel.go @@ -76,7 +76,7 @@ func (gui *Gui) refreshBranches() { } gui.State.Branches = builder.Build() - if err := gui.rerenderIfVisible(gui.Contexts.Branches.Context); err != nil { + if err := gui.postRefreshUpdate(gui.Contexts.Branches.Context); err != nil { gui.Log.Error(err) } diff --git a/pkg/gui/context.go b/pkg/gui/context.go index a54625306..559cfa108 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -98,6 +98,164 @@ type ContextTree struct { Search SimpleContextNode } +func (gui *Gui) allContexts() []Context { + return []Context{ + gui.Contexts.Status.Context, + gui.Contexts.Files.Context, + gui.Contexts.Branches.Context, + gui.Contexts.Remotes.Context, + gui.Contexts.Remotes.Branches.Context, + gui.Contexts.BranchCommits.Context, + gui.Contexts.BranchCommits.Files.Context, + gui.Contexts.ReflogCommits.Context, + gui.Contexts.Stash.Context, + gui.Contexts.Menu.Context, + gui.Contexts.Confirmation.Context, + gui.Contexts.Credentials.Context, + gui.Contexts.CommitMessage.Context, + gui.Contexts.Normal.Context, + gui.Contexts.Staging.Context, + gui.Contexts.Merging.Context, + gui.Contexts.PatchBuilding.Context, + } +} + +func (gui *Gui) contextTree() ContextTree { + return ContextTree{ + Status: SimpleContextNode{ + Context: BasicContext{ + OnFocus: gui.handleStatusSelect, + Kind: SIDE_CONTEXT, + ViewName: "status", + Key: "status", + }, + }, + Files: SimpleContextNode{ + Context: gui.filesListContext(), + }, + Menu: SimpleContextNode{ + Context: gui.menuListContext(), + }, + Remotes: RemotesContextNode{ + Context: gui.remotesListContext(), + Branches: SimpleContextNode{ + Context: gui.remoteBranchesListContext(), + }, + }, + BranchCommits: CommitsContextNode{ + Context: gui.branchCommitsListContext(), + Files: SimpleContextNode{ + Context: gui.commitFilesListContext(), + }, + }, + ReflogCommits: SimpleContextNode{ + Context: gui.reflogCommitsListContext(), + }, + Branches: SimpleContextNode{ + Context: gui.branchesListContext(), + }, + Tags: SimpleContextNode{ + Context: gui.tagsListContext(), + }, + Stash: SimpleContextNode{ + Context: gui.stashListContext(), + }, + Normal: SimpleContextNode{ + Context: BasicContext{ + OnFocus: func() error { + return nil // TODO: should we do something here? We should allow for scrolling the panel + }, + Kind: MAIN_CONTEXT, + ViewName: "main", + Key: "normal", + }, + }, + Staging: SimpleContextNode{ + Context: BasicContext{ + // TODO: think about different situations where this arises + OnFocus: func() error { + return nil + // 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", // admittedly awkward to have view names in camelCase and contexts in kebab-case + }, + }, + Search: SimpleContextNode{ + Context: BasicContext{ + OnFocus: func() error { return nil }, + Kind: PERSISTENT_POPUP, + ViewName: "search", + Key: "search", + }, + }, + } +} + +func (gui *Gui) initialViewContextMap() map[string]Context { + return map[string]Context{ + "status": gui.Contexts.Status.Context, + "files": gui.Contexts.Files.Context, + "branches": gui.Contexts.Branches.Context, + "commits": gui.Contexts.BranchCommits.Context, + "commitFiles": gui.Contexts.BranchCommits.Files.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.Normal.Context, + "secondary": gui.Contexts.Normal.Context, + } +} + func (gui *Gui) switchContext(c Context) error { gui.g.Update(func(*gocui.Gui) error { // push onto stack @@ -168,14 +326,25 @@ func (gui *Gui) deactivateContext(c Context) error { return nil } -func (gui *Gui) rerenderIfVisible(c Context) error { +// postRefreshUpdate is to be called on a context after the state that it depends on has been refreshed +// if the context's view is set to another context we do nothing. +// if the context's view is the current view we trigger a focus; re-selecting the current item. +func (gui *Gui) postRefreshUpdate(c Context) error { v, err := gui.g.View(c.GetViewName()) if err != nil { return nil } - if v.Context == c.GetKey() { - if err := c.HandleRender(); err != nil { + if v.Context != c.GetKey() { + return nil + } + + if err := c.HandleRender(); err != nil { + return err + } + + if gui.currentViewName() == c.GetViewName() { + if err := c.HandleFocus(); err != nil { return err } } @@ -200,6 +369,8 @@ func (gui *Gui) activateContext(c Context) error { } } + gui.setViewAsActiveForWindow(viewName) + if viewName == "main" { gui.changeMainViewsContext(c.GetKey()) } else { @@ -253,142 +424,6 @@ func (gui *Gui) currentContextKey() string { return gui.State.ContextStack[len(gui.State.ContextStack)-1].GetKey() } -func (gui *Gui) contextTree() ContextTree { - return ContextTree{ - Status: SimpleContextNode{ - Context: BasicContext{ - OnFocus: gui.handleStatusSelect, - Kind: SIDE_CONTEXT, - ViewName: "status", - Key: "status", - }, - }, - Files: SimpleContextNode{ - Context: gui.filesListContext(), - }, - Menu: SimpleContextNode{ - Context: gui.menuListContext(), - }, - Remotes: RemotesContextNode{ - Context: gui.remotesListContext(), - Branches: SimpleContextNode{ - Context: gui.remoteBranchesListContext(), - }, - }, - BranchCommits: CommitsContextNode{ - Context: gui.branchCommitsListContext(), - Files: SimpleContextNode{ - Context: gui.commitFilesListContext(), - }, - }, - ReflogCommits: SimpleContextNode{ - Context: gui.reflogCommitsListContext(), - }, - Branches: SimpleContextNode{ - Context: gui.branchesListContext(), - }, - Tags: SimpleContextNode{ - Context: gui.tagsListContext(), - }, - Stash: SimpleContextNode{ - Context: gui.stashListContext(), - }, - Normal: SimpleContextNode{ - Context: BasicContext{ - OnFocus: func() error { - return nil // TODO: should we do something here? We should allow for scrolling the panel - }, - Kind: MAIN_CONTEXT, - ViewName: "main", - Key: "normal", - }, - }, - Staging: SimpleContextNode{ - Context: BasicContext{ - // TODO: think about different situations where this arises - OnFocus: func() error { - return nil - // 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", // admittedly awkward to have view names in camelCase and contexts in kebab-case - }, - }, - Search: SimpleContextNode{ - Context: BasicContext{ - OnFocus: func() error { return nil }, - Kind: PERSISTENT_POPUP, - ViewName: "search", - Key: "search", - }, - }, - } -} - -func (gui *Gui) initialViewContextMap() map[string]Context { - return map[string]Context{ - "status": gui.Contexts.Status.Context, - "files": gui.Contexts.Files.Context, - "branches": gui.Contexts.Branches.Context, - "commits": gui.Contexts.BranchCommits.Context, - "commitFiles": gui.Contexts.BranchCommits.Files.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.Normal.Context, - "secondary": gui.Contexts.Normal.Context, - } -} - func (gui *Gui) setInitialViewContexts() { // arguably we should only have our ViewContextMap and we should do away with // contexts on views, or vice versa @@ -417,9 +452,6 @@ func (gui *Gui) getFocusLayout() func(g *gocui.Gui) error { return err } - if err := gui.onViewFocus(newView); err != nil { - return err - } previousView = newView } return nil @@ -449,12 +481,6 @@ func (gui *Gui) onViewFocusLost(v *gocui.View, newView *gocui.View) error { return nil } -func (gui *Gui) onViewFocus(newView *gocui.View) error { - gui.setViewAsActiveForWindow(newView.Name()) - - return nil -} - // changeContext is a helper function for when we want to change a 'main' context // which currently just means a context that affects both the main and secondary views // other views can have their context changed directly but this function helps @@ -553,7 +579,24 @@ type tabContext struct { contexts []Context } -func (gui *Gui) handleContextRefresh(c Context) { - // if context is not the current context of it's view, return +func (gui *Gui) contextForContextKey(contextKey string) Context { + for _, context := range gui.allContexts() { + if context.GetKey() == contextKey { + return context + } + } + + panic(fmt.Sprintf("context now found for key %s", contextKey)) +} + +func (gui *Gui) rerenderView(viewName string) error { + v, err := gui.g.View(viewName) + if err != nil { + return nil + } + + contextKey := v.Context + context := gui.contextForContextKey(contextKey) + return context.HandleRender() } diff --git a/pkg/gui/global_handlers.go b/pkg/gui/global_handlers.go index ef98b98e6..d37fb8dea 100644 --- a/pkg/gui/global_handlers.go +++ b/pkg/gui/global_handlers.go @@ -9,15 +9,23 @@ import ( "github.com/jesseduffield/lazygit/pkg/utils" ) +// these views need to be re-rendered when the screen mode changes. The commits view, +// for example, will show authorship information in half and full screen mode. +func (gui *Gui) viewsWithScreenModeDependentContent() []string { + return []string{"branches", "commits"} +} + func (gui *Gui) nextScreenMode(g *gocui.Gui, v *gocui.View) error { gui.State.ScreenMode = utils.NextIntInCycle([]int{SCREEN_NORMAL, SCREEN_HALF, SCREEN_FULL}, gui.State.ScreenMode) // commits render differently depending on whether we're in fullscreen more or not if err := gui.refreshCommitsViewWithSelection(); err != nil { return err } - // same with branches - if err := gui.refreshBranchesViewWithSelection(); err != nil { - return err + + for _, viewName := range gui.viewsWithScreenModeDependentContent() { + if err := gui.rerenderView(viewName); err != nil { + return err + } } return nil @@ -25,13 +33,11 @@ func (gui *Gui) nextScreenMode(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) prevScreenMode(g *gocui.Gui, v *gocui.View) error { gui.State.ScreenMode = utils.PrevIntInCycle([]int{SCREEN_NORMAL, SCREEN_HALF, SCREEN_FULL}, gui.State.ScreenMode) - // commits render differently depending on whether we're in fullscreen more or not - if err := gui.refreshCommitsViewWithSelection(); err != nil { - return err - } - // same with branches - if err := gui.refreshBranchesViewWithSelection(); err != nil { - return err + + for _, viewName := range gui.viewsWithScreenModeDependentContent() { + if err := gui.rerenderView(viewName); err != nil { + return err + } } return nil diff --git a/pkg/gui/searching.go b/pkg/gui/searching.go index 261815824..ddf595a5f 100644 --- a/pkg/gui/searching.go +++ b/pkg/gui/searching.go @@ -11,7 +11,9 @@ import ( func (gui *Gui) handleOpenSearch(g *gocui.Gui, v *gocui.View) error { gui.State.Searching.isSearching = true gui.State.Searching.view = v + gui.renderString("search", "") + if err := gui.switchContext(gui.Contexts.Search.Context); err != nil { return err } |