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