mirror of
https://github.com/jesseduffield/lazygit.git
synced 2024-12-02 09:21:40 +02:00
more standardisation of rendering
This commit is contained in:
parent
2f5d5034db
commit
2b812b01e9
@ -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)
|
||||
}
|
||||
|
||||
|
@ -98,159 +98,26 @@ type ContextTree struct {
|
||||
Search SimpleContextNode
|
||||
}
|
||||
|
||||
func (gui *Gui) switchContext(c Context) error {
|
||||
gui.g.Update(func(*gocui.Gui) error {
|
||||
// push onto stack
|
||||
// if we are switching to a side context, remove all other contexts in the stack
|
||||
if c.GetKind() == SIDE_CONTEXT {
|
||||
for _, stackContext := range gui.State.ContextStack {
|
||||
if stackContext.GetKey() != c.GetKey() {
|
||||
if err := gui.deactivateContext(stackContext); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
gui.State.ContextStack = []Context{c}
|
||||
} else {
|
||||
// TODO: think about other exceptional cases
|
||||
gui.State.ContextStack = append(gui.State.ContextStack, c)
|
||||
}
|
||||
|
||||
return gui.activateContext(c)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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) returnFromContext() error {
|
||||
gui.g.Update(func(*gocui.Gui) 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 := gui.deactivateContext(currentContext); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.activateContext(newContext)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) deactivateContext(c Context) error {
|
||||
// if we are the kind of context that is sent to back upon deactivation, we should do that
|
||||
if c.GetKind() == TEMPORARY_POPUP || c.GetKind() == PERSISTENT_POPUP {
|
||||
_, _ = gui.g.SetViewOnBottom(c.GetViewName())
|
||||
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,
|
||||
}
|
||||
|
||||
if err := c.HandleFocusLost(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) rerenderIfVisible(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 {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) activateContext(c Context) error {
|
||||
gui.Log.Warn(spew.Sdump(gui.renderContextStack()))
|
||||
|
||||
viewName := c.GetViewName()
|
||||
v, err := gui.g.View(viewName)
|
||||
// if view no longer exists, pop again
|
||||
if err != nil {
|
||||
return gui.returnFromContext()
|
||||
}
|
||||
|
||||
// if the new context's view was previously displaying another context, render the new context
|
||||
if v.Context != c.GetKey() {
|
||||
if err := c.HandleRender(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if viewName == "main" {
|
||||
gui.changeMainViewsContext(c.GetKey())
|
||||
} else {
|
||||
gui.changeMainViewsContext("normal")
|
||||
}
|
||||
|
||||
gui.setViewTabForContext(c)
|
||||
|
||||
if _, err := gui.g.SetCurrentView(viewName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := gui.g.SetViewOnTop(viewName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newView := gui.g.CurrentView()
|
||||
newView.Context = c.GetKey()
|
||||
|
||||
gui.g.Cursor = newView.Editable
|
||||
|
||||
// TODO: move this logic to the context
|
||||
if err := gui.renderPanelOptions(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.HandleFocus(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: consider removing this and instead depending on the .Context field of views
|
||||
gui.State.ViewContextMap[c.GetViewName()] = c
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) renderContextStack() string {
|
||||
result := ""
|
||||
for _, context := range gui.State.ContextStack {
|
||||
result += context.GetKey() + "\n"
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (gui *Gui) currentContextKey() string {
|
||||
// on startup the stack can be empty so we'll return an empty string in that case
|
||||
if len(gui.State.ContextStack) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return gui.State.ContextStack[len(gui.State.ContextStack)-1].GetKey()
|
||||
}
|
||||
|
||||
func (gui *Gui) contextTree() ContextTree {
|
||||
@ -389,6 +256,174 @@ func (gui *Gui) initialViewContextMap() map[string]Context {
|
||||
}
|
||||
}
|
||||
|
||||
func (gui *Gui) switchContext(c Context) error {
|
||||
gui.g.Update(func(*gocui.Gui) error {
|
||||
// push onto stack
|
||||
// if we are switching to a side context, remove all other contexts in the stack
|
||||
if c.GetKind() == SIDE_CONTEXT {
|
||||
for _, stackContext := range gui.State.ContextStack {
|
||||
if stackContext.GetKey() != c.GetKey() {
|
||||
if err := gui.deactivateContext(stackContext); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
gui.State.ContextStack = []Context{c}
|
||||
} else {
|
||||
// TODO: think about other exceptional cases
|
||||
gui.State.ContextStack = append(gui.State.ContextStack, c)
|
||||
}
|
||||
|
||||
return gui.activateContext(c)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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) returnFromContext() error {
|
||||
gui.g.Update(func(*gocui.Gui) 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 := gui.deactivateContext(currentContext); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.activateContext(newContext)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) deactivateContext(c Context) error {
|
||||
// if we are the kind of context that is sent to back upon deactivation, we should do that
|
||||
if c.GetKind() == TEMPORARY_POPUP || c.GetKind() == PERSISTENT_POPUP {
|
||||
_, _ = gui.g.SetViewOnBottom(c.GetViewName())
|
||||
}
|
||||
|
||||
if err := c.HandleFocusLost(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := c.HandleRender(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if gui.currentViewName() == c.GetViewName() {
|
||||
if err := c.HandleFocus(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) activateContext(c Context) error {
|
||||
gui.Log.Warn(spew.Sdump(gui.renderContextStack()))
|
||||
|
||||
viewName := c.GetViewName()
|
||||
v, err := gui.g.View(viewName)
|
||||
// if view no longer exists, pop again
|
||||
if err != nil {
|
||||
return gui.returnFromContext()
|
||||
}
|
||||
|
||||
// if the new context's view was previously displaying another context, render the new context
|
||||
if v.Context != c.GetKey() {
|
||||
if err := c.HandleRender(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
gui.setViewAsActiveForWindow(viewName)
|
||||
|
||||
if viewName == "main" {
|
||||
gui.changeMainViewsContext(c.GetKey())
|
||||
} else {
|
||||
gui.changeMainViewsContext("normal")
|
||||
}
|
||||
|
||||
gui.setViewTabForContext(c)
|
||||
|
||||
if _, err := gui.g.SetCurrentView(viewName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := gui.g.SetViewOnTop(viewName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newView := gui.g.CurrentView()
|
||||
newView.Context = c.GetKey()
|
||||
|
||||
gui.g.Cursor = newView.Editable
|
||||
|
||||
// TODO: move this logic to the context
|
||||
if err := gui.renderPanelOptions(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.HandleFocus(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: consider removing this and instead depending on the .Context field of views
|
||||
gui.State.ViewContextMap[c.GetViewName()] = c
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) renderContextStack() string {
|
||||
result := ""
|
||||
for _, context := range gui.State.ContextStack {
|
||||
result += context.GetKey() + "\n"
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (gui *Gui) currentContextKey() string {
|
||||
// on startup the stack can be empty so we'll return an empty string in that case
|
||||
if len(gui.State.ContextStack) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return gui.State.ContextStack[len(gui.State.ContextStack)-1].GetKey()
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user