2018-08-14 11:05:26 +02:00
|
|
|
package gui
|
2018-05-26 13:23:39 +10:00
|
|
|
|
|
|
|
import (
|
2023-07-29 09:32:58 +10:00
|
|
|
"time"
|
|
|
|
|
2018-07-21 15:51:18 +10:00
|
|
|
"github.com/jesseduffield/gocui"
|
2022-06-13 11:01:26 +10:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
2023-03-10 13:35:19 +01:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/tasks"
|
2018-08-19 07:20:50 -04:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
2018-08-16 01:53:53 -04:00
|
|
|
"github.com/spkg/bom"
|
2018-05-26 13:23:39 +10:00
|
|
|
)
|
|
|
|
|
2022-12-30 23:24:24 +11:00
|
|
|
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)
|
|
|
|
}
|
2018-06-09 19:06:33 +10:00
|
|
|
}
|
|
|
|
|
2023-03-10 13:35:19 +01:00
|
|
|
// 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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-15 20:12:31 +11:00
|
|
|
func (gui *Gui) cleanString(s string) string {
|
2018-12-12 22:34:20 +11:00
|
|
|
output := string(bom.Clean([]byte(s)))
|
2019-01-15 20:12:31 +11:00
|
|
|
return utils.NormalizeLinefeeds(output)
|
|
|
|
}
|
|
|
|
|
2021-04-11 10:05:19 +10:00
|
|
|
func (gui *Gui) setViewContent(v *gocui.View, s string) {
|
2022-01-15 12:04:00 +11:00
|
|
|
v.SetContent(gui.cleanString(s))
|
2021-04-11 10:05:19 +10:00
|
|
|
}
|
|
|
|
|
2019-02-25 22:11:35 +11:00
|
|
|
func (gui *Gui) currentViewName() string {
|
|
|
|
currentView := gui.g.CurrentView()
|
2020-05-16 12:35:19 +10:00
|
|
|
if currentView == nil {
|
|
|
|
return ""
|
|
|
|
}
|
2018-08-14 11:05:26 +02:00
|
|
|
return currentView.Name()
|
|
|
|
}
|
2018-09-05 19:07:46 +10:00
|
|
|
|
2022-06-13 11:01:26 +10:00
|
|
|
func (gui *Gui) onViewTabClick(windowName string, tabIndex int) error {
|
|
|
|
tabs := gui.viewTabMap()[windowName]
|
|
|
|
if len(tabs) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
2020-08-17 21:58:30 +10:00
|
|
|
|
2022-06-13 11:01:26 +10:00
|
|
|
viewName := tabs[tabIndex].ViewName
|
|
|
|
|
2022-12-30 23:24:24 +11:00
|
|
|
context, ok := gui.helpers.View.ContextForView(viewName)
|
2022-06-13 11:01:26 +10:00
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
2020-08-19 19:31:58 +10:00
|
|
|
|
2022-01-16 14:46:53 +11:00
|
|
|
return gui.c.PushContext(context)
|
2020-08-19 19:31:58 +10:00
|
|
|
}
|
|
|
|
|
2022-06-13 11:01:26 +10:00
|
|
|
func (gui *Gui) handleNextTab() error {
|
|
|
|
view := getTabbedView(gui)
|
|
|
|
if view == nil {
|
2021-04-02 19:20:40 +11:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-06-13 11:01:26 +10:00
|
|
|
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
|
2020-08-19 19:31:58 +10:00
|
|
|
}
|
2020-10-02 07:56:14 +10:00
|
|
|
|
2022-06-13 11:01:26 +10:00
|
|
|
func (gui *Gui) handlePrevTab() error {
|
|
|
|
view := getTabbedView(gui)
|
|
|
|
if view == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2020-10-02 07:56:14 +10:00
|
|
|
|
2022-06-13 11:01:26 +10:00
|
|
|
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)),
|
|
|
|
)
|
|
|
|
}
|
2020-10-02 07:56:14 +10:00
|
|
|
}
|
|
|
|
|
2022-06-13 11:01:26 +10:00
|
|
|
return nil
|
2020-10-02 07:56:14 +10:00
|
|
|
}
|
2021-06-06 12:41:55 +02:00
|
|
|
|
|
|
|
func getTabbedView(gui *Gui) *gocui.View {
|
2021-06-15 19:58:43 +02:00
|
|
|
// It safe assumption that only static contexts have tabs
|
2022-12-30 23:24:24 +11:00
|
|
|
context := gui.c.CurrentStaticContext()
|
2021-06-15 19:58:43 +02:00
|
|
|
view, _ := gui.g.View(context.GetViewName())
|
|
|
|
return view
|
2021-06-06 12:41:55 +02:00
|
|
|
}
|
2021-11-01 09:35:54 +11:00
|
|
|
|
|
|
|
func (gui *Gui) render() {
|
2022-08-06 18:50:52 +10:00
|
|
|
gui.c.OnUIThread(func() error { return nil })
|
2021-11-01 09:35:54 +11:00
|
|
|
}
|
2022-12-30 23:24:24 +11:00
|
|
|
|
|
|
|
// 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 {
|
2023-07-29 09:32:58 +10:00
|
|
|
t := time.Now()
|
|
|
|
defer func() {
|
|
|
|
gui.Log.Infof("postRefreshUpdate for %s took %s", c.GetKey(), time.Since(t))
|
|
|
|
}()
|
|
|
|
|
2022-12-30 23:24:24 +11:00
|
|
|
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
|
|
|
|
}
|