mirror of
				https://github.com/jesseduffield/lazygit.git
				synced 2025-10-30 23:57:43 +02:00 
			
		
		
		
	Rerender certain views when their width changes
Situations where a view's width changes: - changing screen modes - enter staging or patch building - resizing the terminal window For the first of these we currently have special code to force a rerender, since some views render different content depending on whether they are in full-screen mode. We'll be able to remove that code now, since this new generic mechanism takes care of that too. But we will need this more general mechanism for cases where views truncate their content to the view width; we'll add one example for that later in this branch.
This commit is contained in:
		| @@ -20,10 +20,11 @@ type BaseContext struct { | ||||
| 	onFocusFn           onFocusFn | ||||
| 	onFocusLostFn       onFocusLostFn | ||||
|  | ||||
| 	focusable           bool | ||||
| 	transient           bool | ||||
| 	hasControlledBounds bool | ||||
| 	highlightOnFocus    bool | ||||
| 	focusable                  bool | ||||
| 	transient                  bool | ||||
| 	hasControlledBounds        bool | ||||
| 	needsRerenderOnWidthChange bool | ||||
| 	highlightOnFocus           bool | ||||
|  | ||||
| 	*ParentContextMgr | ||||
| } | ||||
| @@ -36,14 +37,15 @@ type ( | ||||
| var _ types.IBaseContext = &BaseContext{} | ||||
|  | ||||
| type NewBaseContextOpts struct { | ||||
| 	Kind                  types.ContextKind | ||||
| 	Key                   types.ContextKey | ||||
| 	View                  *gocui.View | ||||
| 	WindowName            string | ||||
| 	Focusable             bool | ||||
| 	Transient             bool | ||||
| 	HasUncontrolledBounds bool // negating for the sake of making false the default | ||||
| 	HighlightOnFocus      bool | ||||
| 	Kind                       types.ContextKind | ||||
| 	Key                        types.ContextKey | ||||
| 	View                       *gocui.View | ||||
| 	WindowName                 string | ||||
| 	Focusable                  bool | ||||
| 	Transient                  bool | ||||
| 	HasUncontrolledBounds      bool // negating for the sake of making false the default | ||||
| 	HighlightOnFocus           bool | ||||
| 	NeedsRerenderOnWidthChange bool | ||||
|  | ||||
| 	OnGetOptionsMap func() map[string]string | ||||
| } | ||||
| @@ -54,17 +56,18 @@ func NewBaseContext(opts NewBaseContextOpts) *BaseContext { | ||||
| 	hasControlledBounds := !opts.HasUncontrolledBounds | ||||
|  | ||||
| 	return &BaseContext{ | ||||
| 		kind:                opts.Kind, | ||||
| 		key:                 opts.Key, | ||||
| 		view:                opts.View, | ||||
| 		windowName:          opts.WindowName, | ||||
| 		onGetOptionsMap:     opts.OnGetOptionsMap, | ||||
| 		focusable:           opts.Focusable, | ||||
| 		transient:           opts.Transient, | ||||
| 		hasControlledBounds: hasControlledBounds, | ||||
| 		highlightOnFocus:    opts.HighlightOnFocus, | ||||
| 		ParentContextMgr:    &ParentContextMgr{}, | ||||
| 		viewTrait:           viewTrait, | ||||
| 		kind:                       opts.Kind, | ||||
| 		key:                        opts.Key, | ||||
| 		view:                       opts.View, | ||||
| 		windowName:                 opts.WindowName, | ||||
| 		onGetOptionsMap:            opts.OnGetOptionsMap, | ||||
| 		focusable:                  opts.Focusable, | ||||
| 		transient:                  opts.Transient, | ||||
| 		hasControlledBounds:        hasControlledBounds, | ||||
| 		highlightOnFocus:           opts.HighlightOnFocus, | ||||
| 		needsRerenderOnWidthChange: opts.NeedsRerenderOnWidthChange, | ||||
| 		ParentContextMgr:           &ParentContextMgr{}, | ||||
| 		viewTrait:                  viewTrait, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -190,6 +193,10 @@ func (self *BaseContext) HasControlledBounds() bool { | ||||
| 	return self.hasControlledBounds | ||||
| } | ||||
|  | ||||
| func (self *BaseContext) NeedsRerenderOnWidthChange() bool { | ||||
| 	return self.needsRerenderOnWidthChange | ||||
| } | ||||
|  | ||||
| func (self *BaseContext) Title() string { | ||||
| 	return "" | ||||
| } | ||||
|   | ||||
| @@ -40,11 +40,12 @@ func NewBranchesContext(c *ContextCommon) *BranchesContext { | ||||
| 		FilteredListViewModel: viewModel, | ||||
| 		ListContextTrait: &ListContextTrait{ | ||||
| 			Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ | ||||
| 				View:       c.Views().Branches, | ||||
| 				WindowName: "branches", | ||||
| 				Key:        LOCAL_BRANCHES_CONTEXT_KEY, | ||||
| 				Kind:       types.SIDE_CONTEXT, | ||||
| 				Focusable:  true, | ||||
| 				View:                       c.Views().Branches, | ||||
| 				WindowName:                 "branches", | ||||
| 				Key:                        LOCAL_BRANCHES_CONTEXT_KEY, | ||||
| 				Kind:                       types.SIDE_CONTEXT, | ||||
| 				Focusable:                  true, | ||||
| 				NeedsRerenderOnWidthChange: true, | ||||
| 			})), | ||||
| 			ListRenderer: ListRenderer{ | ||||
| 				list:              viewModel, | ||||
|   | ||||
| @@ -68,11 +68,12 @@ func NewLocalCommitsContext(c *ContextCommon) *LocalCommitsContext { | ||||
| 		SearchTrait:           NewSearchTrait(c), | ||||
| 		ListContextTrait: &ListContextTrait{ | ||||
| 			Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ | ||||
| 				View:       c.Views().Commits, | ||||
| 				WindowName: "commits", | ||||
| 				Key:        LOCAL_COMMITS_CONTEXT_KEY, | ||||
| 				Kind:       types.SIDE_CONTEXT, | ||||
| 				Focusable:  true, | ||||
| 				View:                       c.Views().Commits, | ||||
| 				WindowName:                 "commits", | ||||
| 				Key:                        LOCAL_COMMITS_CONTEXT_KEY, | ||||
| 				Kind:                       types.SIDE_CONTEXT, | ||||
| 				Focusable:                  true, | ||||
| 				NeedsRerenderOnWidthChange: true, | ||||
| 			})), | ||||
| 			ListRenderer: ListRenderer{ | ||||
| 				list:              viewModel, | ||||
|   | ||||
| @@ -43,11 +43,12 @@ func NewReflogCommitsContext(c *ContextCommon) *ReflogCommitsContext { | ||||
| 		FilteredListViewModel: viewModel, | ||||
| 		ListContextTrait: &ListContextTrait{ | ||||
| 			Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ | ||||
| 				View:       c.Views().ReflogCommits, | ||||
| 				WindowName: "commits", | ||||
| 				Key:        REFLOG_COMMITS_CONTEXT_KEY, | ||||
| 				Kind:       types.SIDE_CONTEXT, | ||||
| 				Focusable:  true, | ||||
| 				View:                       c.Views().ReflogCommits, | ||||
| 				WindowName:                 "commits", | ||||
| 				Key:                        REFLOG_COMMITS_CONTEXT_KEY, | ||||
| 				Kind:                       types.SIDE_CONTEXT, | ||||
| 				Focusable:                  true, | ||||
| 				NeedsRerenderOnWidthChange: true, | ||||
| 			})), | ||||
| 			ListRenderer: ListRenderer{ | ||||
| 				list:              viewModel, | ||||
|   | ||||
| @@ -36,12 +36,13 @@ func NewRemoteBranchesContext( | ||||
| 		DynamicTitleBuilder:   NewDynamicTitleBuilder(c.Tr.RemoteBranchesDynamicTitle), | ||||
| 		ListContextTrait: &ListContextTrait{ | ||||
| 			Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ | ||||
| 				View:       c.Views().RemoteBranches, | ||||
| 				WindowName: "branches", | ||||
| 				Key:        REMOTE_BRANCHES_CONTEXT_KEY, | ||||
| 				Kind:       types.SIDE_CONTEXT, | ||||
| 				Focusable:  true, | ||||
| 				Transient:  true, | ||||
| 				View:                       c.Views().RemoteBranches, | ||||
| 				WindowName:                 "branches", | ||||
| 				Key:                        REMOTE_BRANCHES_CONTEXT_KEY, | ||||
| 				Kind:                       types.SIDE_CONTEXT, | ||||
| 				Focusable:                  true, | ||||
| 				Transient:                  true, | ||||
| 				NeedsRerenderOnWidthChange: true, | ||||
| 			})), | ||||
| 			ListRenderer: ListRenderer{ | ||||
| 				list:              viewModel, | ||||
|   | ||||
| @@ -115,12 +115,13 @@ func NewSubCommitsContext( | ||||
| 		DynamicTitleBuilder: NewDynamicTitleBuilder(c.Tr.SubCommitsDynamicTitle), | ||||
| 		ListContextTrait: &ListContextTrait{ | ||||
| 			Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ | ||||
| 				View:       c.Views().SubCommits, | ||||
| 				WindowName: "branches", | ||||
| 				Key:        SUB_COMMITS_CONTEXT_KEY, | ||||
| 				Kind:       types.SIDE_CONTEXT, | ||||
| 				Focusable:  true, | ||||
| 				Transient:  true, | ||||
| 				View:                       c.Views().SubCommits, | ||||
| 				WindowName:                 "branches", | ||||
| 				Key:                        SUB_COMMITS_CONTEXT_KEY, | ||||
| 				Kind:                       types.SIDE_CONTEXT, | ||||
| 				Focusable:                  true, | ||||
| 				Transient:                  true, | ||||
| 				NeedsRerenderOnWidthChange: true, | ||||
| 			})), | ||||
| 			ListRenderer: ListRenderer{ | ||||
| 				list:              viewModel, | ||||
|   | ||||
| @@ -44,8 +44,13 @@ func (gui *Gui) layout(g *gocui.Gui) error { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	contextsToRerender := []types.Context{} | ||||
|  | ||||
| 	// we assume that the view has already been created. | ||||
| 	setViewFromDimensions := func(viewName string, windowName string) (*gocui.View, error) { | ||||
| 	setViewFromDimensions := func(context types.Context) (*gocui.View, error) { | ||||
| 		viewName := context.GetViewName() | ||||
| 		windowName := context.GetWindowName() | ||||
|  | ||||
| 		dimensionsObj, ok := viewDimensions[windowName] | ||||
|  | ||||
| 		view, err := g.View(viewName) | ||||
| @@ -67,6 +72,16 @@ func (gui *Gui) layout(g *gocui.Gui) error { | ||||
| 		if view.Frame { | ||||
| 			frameOffset = 0 | ||||
| 		} | ||||
|  | ||||
| 		if context.NeedsRerenderOnWidthChange() { | ||||
| 			// view.Width() returns the width -1 for some reason | ||||
| 			oldWidth := view.Width() + 1 | ||||
| 			newWidth := dimensionsObj.X1 - dimensionsObj.X0 + 2*frameOffset | ||||
| 			if oldWidth != newWidth { | ||||
| 				contextsToRerender = append(contextsToRerender, context) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		_, err = g.SetView( | ||||
| 			viewName, | ||||
| 			dimensionsObj.X0-frameOffset, | ||||
| @@ -85,7 +100,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		_, err := setViewFromDimensions(context.GetViewName(), context.GetWindowName()) | ||||
| 		_, err := setViewFromDimensions(context) | ||||
| 		if err != nil && !gocui.IsUnknownView(err) { | ||||
| 			return err | ||||
| 		} | ||||
| @@ -146,6 +161,12 @@ func (gui *Gui) layout(g *gocui.Gui) error { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for _, context := range contextsToRerender { | ||||
| 		if err := context.HandleRender(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// here is a good place log some stuff | ||||
| 	// if you run `lazygit --logs` | ||||
| 	// this will let you see these branches as prettified json | ||||
|   | ||||
| @@ -60,6 +60,9 @@ type IBaseContext interface { | ||||
| 	// determined independently. | ||||
| 	HasControlledBounds() bool | ||||
|  | ||||
| 	// true if the view needs to be rerendered when its width changes | ||||
| 	NeedsRerenderOnWidthChange() bool | ||||
|  | ||||
| 	// returns the desired title for the view upon activation. If there is no desired title (returns empty string), then | ||||
| 	// no title will be set | ||||
| 	Title() string | ||||
|   | ||||
		Reference in New Issue
	
	Block a user