summaryrefslogtreecommitdiffstats
path: root/pkg/gui/controllers/helpers/window_helper.go
blob: 4bdd7a889723b92f1161b7cb70977fb8c4140c07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package helpers

import (
	"fmt"

	"github.com/jesseduffield/gocui"
	"github.com/jesseduffield/lazygit/pkg/gui/types"
	"github.com/jesseduffield/lazygit/pkg/utils"
	"github.com/samber/lo"
)

type WindowHelper struct {
	c          *HelperCommon
	viewHelper *ViewHelper
}

func NewWindowHelper(c *HelperCommon, viewHelper *ViewHelper) *WindowHelper {
	return &WindowHelper{
		c:          c,
		viewHelper: viewHelper,
	}
}

// A window refers to a place on the screen which can hold one or more views.
// A view is a box that renders content, and within a window only one view will
// appear at a time. When a view appears within a window, it occupies the whole
// space. Right now most windows are 1:1 with views, except for commitFiles which
// is a view that moves between windows

func (self *WindowHelper) GetViewNameForWindow(window string) string {
	viewName, ok := self.windowViewNameMap().Get(window)
	if !ok {
		panic(fmt.Sprintf("Viewname not found for window: %s", window))
	}

	return viewName
}

func (self *WindowHelper) GetContextForWindow(window string) types.Context {
	viewName := self.GetViewNameForWindow(window)

	context, ok := self.viewHelper.ContextForView(viewName)
	if !ok {
		panic("TODO: fix this")
	}

	return context
}

// for now all we actually care about is the context's view so we're storing that
func (self *WindowHelper) SetWindowContext(c types.Context) {
	if c.IsTransient() {
		self.resetWindowContext(c)
	}

	self.windowViewNameMap().Set(c.GetWindowName(), c.GetViewName())
}

func (self *WindowHelper) windowViewNameMap() *utils.ThreadSafeMap[string, string] {
	return self.c.State().GetRepoState().GetWindowViewNameMap()
}

func (self *WindowHelper) CurrentWindow() string {
	return self.c.CurrentContext().GetWindowName()
}

// assumes the context's windowName has been set to the new window if necessary
func (self *WindowHelper) resetWindowContext(c types.Context) {
	for _, windowName := range self.windowViewNameMap().Keys() {
		viewName, ok := self.windowViewNameMap().Get(windowName)
		if !ok {
			continue
		}
		if viewName == c.GetViewName() && windowName != c.GetWindowName() {
			for _, context := range self.c.Contexts().Flatten() {
				if context.GetKey() != c.GetKey() && context.GetWindowName() == windowName {
					self.windowViewNameMap().Set(windowName, context.GetViewName())
				}
			}
		}
	}
}

// moves given context's view to the top of the window
func (self *WindowHelper) MoveToTopOfWindow(context types.Context) {
	view := context.GetView()
	if view == nil {
		return
	}

	window := context.GetWindowName()

	topView := self.TopViewInWindow(window)

	if topView != nil && view.Name() != topView.Name() {
		if err := self.c.GocuiGui().SetViewOnTopOf(view.Name(), topView.Name()); err != nil {
			self.c.Log.Error(err)
		}
	}
}

func (self *WindowHelper) TopViewInWindow(windowName string) *gocui.View {
	// now I need to find all views in that same window, via contexts. And I guess then I need to find the index of the highest view in that list.
	viewNamesInWindow := self.viewNamesInWindow(windowName)

	// The views list is ordered highest-last, so we're grabbing the last view of the window
	var topView *gocui.View
	for _, currentView := range self.c.GocuiGui().Views() {
		if lo.Contains(viewNamesInWindow, currentView.Name()) && currentView.Visible {
			topView = currentView
		}
	}

	return topView
}

func (self *WindowHelper) viewNamesInWindow(windowName string) []string {
	result := []string{}
	for _, context := range self.c.Contexts().Flatten() {
		if context.GetWindowName() == windowName {
			result = append(result, context.GetViewName())
		}
	}

	return result
}

func (self *WindowHelper) WindowForView(viewName string) string {
	context, ok := self.viewHelper.ContextForView(viewName)
	if !ok {
		panic("todo: deal with this")
	}

	return context.GetWindowName()
}

func (self *WindowHelper) SideWindows() []string {
	return []string{"status", "files", "branches", "commits", "stash"}
}