1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2024-12-04 10:34:55 +02:00
lazygit/pkg/gui/view_helpers.go
Jesse Duffield 5f30ccfbc3 Log duration of post-refresh-update call
Notably, the reflog view is taking ages here because it's got a
few thousand lines to write to the view.

In future we should only populate the view's viewport.
2023-07-29 09:39:22 +10:00

151 lines
3.7 KiB
Go

package gui
import (
"time"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/tasks"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/spkg/bom"
)
func (gui *Gui) resetViewOrigin(v *gocui.View) {
if err := v.SetCursor(0, 0); err != nil {
gui.Log.Error(err)
}
if err := v.SetOrigin(0, 0); err != nil {
gui.Log.Error(err)
}
}
// Returns the number of lines that we should read initially from a cmd task so
// that the scrollbar has the correct size, along with the number of lines after
// which the view is filled and we can do a first refresh.
func (gui *Gui) linesToReadFromCmdTask(v *gocui.View) tasks.LinesToRead {
_, height := v.Size()
_, oy := v.Origin()
linesForFirstRefresh := height + oy + 10
// We want to read as many lines initially as necessary to let the
// scrollbar go to its minimum height, so that the scrollbar thumb doesn't
// change size as you scroll down.
minScrollbarHeight := 2
linesToReadForAccurateScrollbar := height*(height-1)/minScrollbarHeight + oy
// However, cap it at some arbitrary max limit, so that we don't get
// performance problems for huge monitors or tiny font sizes
if linesToReadForAccurateScrollbar > 5000 {
linesToReadForAccurateScrollbar = 5000
}
return tasks.LinesToRead{
Total: linesToReadForAccurateScrollbar,
InitialRefreshAfter: linesForFirstRefresh,
}
}
func (gui *Gui) cleanString(s string) string {
output := string(bom.Clean([]byte(s)))
return utils.NormalizeLinefeeds(output)
}
func (gui *Gui) setViewContent(v *gocui.View, s string) {
v.SetContent(gui.cleanString(s))
}
func (gui *Gui) currentViewName() string {
currentView := gui.g.CurrentView()
if currentView == nil {
return ""
}
return currentView.Name()
}
func (gui *Gui) onViewTabClick(windowName string, tabIndex int) error {
tabs := gui.viewTabMap()[windowName]
if len(tabs) == 0 {
return nil
}
viewName := tabs[tabIndex].ViewName
context, ok := gui.helpers.View.ContextForView(viewName)
if !ok {
return nil
}
return gui.c.PushContext(context)
}
func (gui *Gui) handleNextTab() error {
view := getTabbedView(gui)
if view == nil {
return nil
}
for _, context := range gui.State.Contexts.Flatten() {
if context.GetViewName() == view.Name() {
return gui.onViewTabClick(
context.GetWindowName(),
utils.ModuloWithWrap(view.TabIndex+1, len(view.Tabs)),
)
}
}
return nil
}
func (gui *Gui) handlePrevTab() error {
view := getTabbedView(gui)
if view == nil {
return nil
}
for _, context := range gui.State.Contexts.Flatten() {
if context.GetViewName() == view.Name() {
return gui.onViewTabClick(
context.GetWindowName(),
utils.ModuloWithWrap(view.TabIndex-1, len(view.Tabs)),
)
}
}
return nil
}
func getTabbedView(gui *Gui) *gocui.View {
// It safe assumption that only static contexts have tabs
context := gui.c.CurrentStaticContext()
view, _ := gui.g.View(context.GetViewName())
return view
}
func (gui *Gui) render() {
gui.c.OnUIThread(func() error { 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 types.Context) error {
t := time.Now()
defer func() {
gui.Log.Infof("postRefreshUpdate for %s took %s", c.GetKey(), time.Since(t))
}()
if err := c.HandleRender(); err != nil {
return err
}
if gui.currentViewName() == c.GetViewName() {
if err := c.HandleFocus(types.OnFocusOpts{}); err != nil {
return err
}
}
return nil
}