summaryrefslogtreecommitdiffstats
path: root/pkg/gui/gui.go
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2022-12-30 23:24:24 +1100
committerJesse Duffield <jessedduffield@gmail.com>2023-04-30 13:19:52 +1000
commit8edad826caf2fa48bfad33f9f8c4f3ba49a052da (patch)
tree0b49145e4f656e72441199b5a5c30176c898d7a7 /pkg/gui/gui.go
parent826128a8e03fb50f7287029ebac93c85712faecb (diff)
Begin refactoring gui
This begins a big refactor of moving more code out of the Gui struct into contexts, controllers, and helpers. We also move some code into structs in the gui package purely for the sake of better encapsulation
Diffstat (limited to 'pkg/gui/gui.go')
-rw-r--r--pkg/gui/gui.go177
1 files changed, 132 insertions, 45 deletions
diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go
index aed1d5430..4235f2eb0 100644
--- a/pkg/gui/gui.go
+++ b/pkg/gui/gui.go
@@ -8,6 +8,7 @@ import (
"sync"
"github.com/jesseduffield/gocui"
+ "github.com/jesseduffield/lazycore/pkg/boxlayout"
appTypes "github.com/jesseduffield/lazygit/pkg/app/types"
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
@@ -32,7 +33,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/integration/components"
integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
- "github.com/jesseduffield/lazygit/pkg/snake"
"github.com/jesseduffield/lazygit/pkg/tasks"
"github.com/jesseduffield/lazygit/pkg/theme"
"github.com/jesseduffield/lazygit/pkg/updates"
@@ -58,18 +58,6 @@ const StartupPopupVersion = 5
// OverlappingEdges determines if panel edges overlap
var OverlappingEdges = false
-type ContextManager struct {
- ContextStack []types.Context
- sync.RWMutex
-}
-
-func NewContextManager() ContextManager {
- return ContextManager{
- ContextStack: []types.Context{},
- RWMutex: sync.RWMutex{},
- }
-}
-
type Repo string
// Gui wraps the gocui Gui object which handles rendering and events
@@ -117,12 +105,7 @@ type Gui struct {
// this tells us whether our views have been initially set up
ViewsSetup bool
- Views Views
-
- // if we've suspended the gui (e.g. because we've switched to a subprocess)
- // we typically want to pause some things that are running like background
- // file refreshes
- PauseBackgroundThreads bool
+ Views types.Views
// Log of the commands that get run, to be displayed to the user.
CmdLog []string
@@ -139,6 +122,8 @@ type Gui struct {
// flag as to whether or not the diff view should ignore whitespace
IgnoreWhitespaceInDiffView bool
+ IsRefreshingFiles bool
+
// we use this to decide whether we'll return to the original directory that
// lazygit was opened in, or if we'll retain the one we're currently in.
RetainOriginalDir bool
@@ -153,10 +138,52 @@ type Gui struct {
// process
InitialDir string
+ BackgroundRoutineMgr *BackgroundRoutineMgr
+ // for accessing the gui's state from outside this package
+ stateAccessor *StateAccessor
+
+ Updating bool
+
c *types.HelperCommon
helpers *helpers.Helpers
+}
+
+type StateAccessor struct {
+ gui *Gui
+}
+
+var _ types.IStateAccessor = new(StateAccessor)
+
+func (self *StateAccessor) GetIgnoreWhitespaceInDiffView() bool {
+ return self.gui.IgnoreWhitespaceInDiffView
+}
+
+func (self *StateAccessor) SetIgnoreWhitespaceInDiffView(value bool) {
+ self.gui.IgnoreWhitespaceInDiffView = value
+}
- snakeGame *snake.Game
+func (self *StateAccessor) GetRepoPathStack() *utils.StringStack {
+ return self.gui.RepoPathStack
+}
+
+func (self *StateAccessor) GetUpdating() bool {
+ return self.gui.Updating
+}
+
+func (self *StateAccessor) SetUpdating(value bool) {
+ self.gui.Updating = value
+}
+
+func (self *StateAccessor) GetRepoState() types.IRepoStateAccessor {
+ return self.gui.State
+}
+
+func (self *StateAccessor) GetIsRefreshingFiles() bool {
+ return self.gui.IsRefreshingFiles
+}
+
+func (self *StateAccessor) SetIsRefreshingFiles(value bool) {
+ self.gui.IsRefreshingFiles = value
}
// we keep track of some stuff from one render to the next to see if certain
@@ -174,16 +201,14 @@ type GuiRepoState struct {
// Suggestions will sometimes appear when typing into a prompt
Suggestions []*types.Suggestion
- Updating bool
SplitMainPanel bool
LimitCommits bool
- IsRefreshingFiles bool
- Searching searchingState
- StartupStage StartupStage // Allows us to not load everything at once
+ Searching searchingState
+ StartupStage types.StartupStage // Allows us to not load everything at once
- ContextManager ContextManager
- Contexts *context.ContextTree
+ ContextMgr ContextMgr
+ Contexts *context.ContextTree
// WindowViewNameMap is a mapping of windows to the current view of that window.
// Some views move between windows for example the commitFiles view and when cycling through
@@ -204,20 +229,38 @@ type GuiRepoState struct {
CurrentPopupOpts *types.CreatePopupPanelOpts
}
+var _ types.IRepoStateAccessor = new(GuiRepoState)
+
+func (self *GuiRepoState) GetViewsSetup() bool {
+ return self.ViewsSetup
+}
+
+func (self *GuiRepoState) GetWindowViewNameMap() *utils.ThreadSafeMap[string, string] {
+ return self.WindowViewNameMap
+}
+
+func (self *GuiRepoState) GetStartupStage() types.StartupStage {
+ return self.StartupStage
+}
+
+func (self *GuiRepoState) SetStartupStage(value types.StartupStage) {
+ self.StartupStage = value
+}
+
+func (self *GuiRepoState) GetCurrentPopupOpts() *types.CreatePopupPanelOpts {
+ return self.CurrentPopupOpts
+}
+
+func (self *GuiRepoState) SetCurrentPopupOpts(value *types.CreatePopupPanelOpts) {
+ self.CurrentPopupOpts = value
+}
+
type searchingState struct {
view *gocui.View
isSearching bool
searchString string
}
-// startup stages so we don't need to load everything at once
-type StartupStage int
-
-const (
- INITIAL StartupStage = iota
- COMPLETE
-)
-
func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, reuseState bool) error {
var err error
gui.git, err = commands.NewGitCommand(
@@ -278,8 +321,6 @@ func (gui *Gui) resetState(startArgs appTypes.StartArgs, reuseState bool) {
initialContext := initialContext(contextTree, startArgs)
initialScreenMode := initialScreenMode(startArgs, gui.Config)
- initialWindowViewNameMap := gui.initialWindowViewNameMap(contextTree)
-
gui.State = &GuiRepoState{
Model: &types.Model{
CommitFiles: nil,
@@ -298,9 +339,9 @@ func (gui *Gui) resetState(startArgs appTypes.StartArgs, reuseState bool) {
},
ScreenMode: initialScreenMode,
// TODO: put contexts in the context manager
- ContextManager: NewContextManager(),
+ ContextMgr: NewContextMgr(initialContext, gui),
Contexts: contextTree,
- WindowViewNameMap: initialWindowViewNameMap,
+ WindowViewNameMap: initialWindowViewNameMap(contextTree),
}
if err := gui.c.PushContext(initialContext); err != nil {
@@ -310,6 +351,16 @@ func (gui *Gui) resetState(startArgs appTypes.StartArgs, reuseState bool) {
gui.RepoStateMap[Repo(currentDir)] = gui.State
}
+func initialWindowViewNameMap(contextTree *context.ContextTree) *utils.ThreadSafeMap[string, string] {
+ result := utils.NewThreadSafeMap[string, string]()
+
+ for _, context := range contextTree.Flatten() {
+ result.Set(context.GetWindowName(), context.GetViewName())
+ }
+
+ return result
+}
+
func initialScreenMode(startArgs appTypes.StartArgs, config config.AppConfigurer) WindowMaximisation {
if startArgs.FilterPath != "" || startArgs.GitArg != appTypes.GitArgNone {
return SCREEN_HALF
@@ -391,7 +442,7 @@ func NewGui(
InitialDir: initialDir,
}
- gui.watchFilesForChanges()
+ gui.WatchFilesForChanges()
gui.PopupHandler = popup.NewPopupHandler(
cmn,
@@ -429,6 +480,9 @@ func NewGui(
icons.SetIconEnabled(gui.UserConfig.Gui.ShowIcons)
presentation.SetCustomBranches(gui.UserConfig.Gui.BranchColors)
+ gui.BackgroundRoutineMgr = &BackgroundRoutineMgr{gui: gui}
+ gui.stateAccessor = &StateAccessor{gui: gui}
+
return gui, nil
}
@@ -539,7 +593,7 @@ func (gui *Gui) Run(startArgs appTypes.StartArgs) error {
gui.waitForIntro.Add(1)
- gui.startBackgroundRoutines()
+ gui.BackgroundRoutineMgr.startBackgroundRoutines()
gui.c.Log.Info("starting main loop")
@@ -565,11 +619,11 @@ func (gui *Gui) RunAndHandleError(startArgs appTypes.StartArgs) error {
switch err {
case gocui.ErrQuit:
if gui.RetainOriginalDir {
- if err := gui.recordDirectory(gui.InitialDir); err != nil {
+ if err := gui.helpers.RecordDirectory.RecordDirectory(gui.InitialDir); err != nil {
return err
}
} else {
- if err := gui.recordCurrentDirectory(); err != nil {
+ if err := gui.helpers.RecordDirectory.RecordCurrentDirectory(); err != nil {
return err
}
}
@@ -639,7 +693,8 @@ func (gui *Gui) runSubprocessWithSuspense(subprocess oscommands.ICmdObj) (bool,
return false, gui.c.Error(err)
}
- gui.PauseBackgroundThreads = true
+ gui.BackgroundRoutineMgr.PauseBackgroundThreads(true)
+ defer gui.BackgroundRoutineMgr.PauseBackgroundThreads(false)
cmdErr := gui.runSubprocess(subprocess)
@@ -647,8 +702,6 @@ func (gui *Gui) runSubprocessWithSuspense(subprocess oscommands.ICmdObj) (bool,
return false, err
}
- gui.PauseBackgroundThreads = false
-
if cmdErr != nil {
return false, gui.c.Error(cmdErr)
}
@@ -751,3 +804,37 @@ func (gui *Gui) onUIThread(f func() error) {
return f()
})
}
+
+func (gui *Gui) startBackgroundRoutines() {
+ mgr := &BackgroundRoutineMgr{gui: gui}
+ mgr.startBackgroundRoutines()
+}
+
+func (gui *Gui) getWindowDimensions(informationStr string, appStatus string) map[string]boxlayout.Dimensions {
+ windowArranger := &WindowArranger{gui: gui}
+ return windowArranger.getWindowDimensions(informationStr, appStatus)
+}
+
+func (gui *Gui) replaceContext(c types.Context) error {
+ return gui.State.ContextMgr.replaceContext(c)
+}
+
+func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error {
+ return gui.State.ContextMgr.pushContext(c, opts...)
+}
+
+func (gui *Gui) popContext() error {
+ return gui.State.ContextMgr.popContext()
+}
+
+func (gui *Gui) currentContext() types.Context {
+ return gui.State.ContextMgr.currentContext()
+}
+
+func (gui *Gui) currentSideContext() types.Context {
+ return gui.State.ContextMgr.currentSideContext()
+}
+
+func (gui *Gui) currentStaticContext() types.Context {
+ return gui.State.ContextMgr.currentStaticContext()
+}