diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2022-01-31 22:11:34 +1100 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2022-03-17 19:13:40 +1100 |
commit | 2a1e3faa0c61cc8c2418310089485dbab268228f (patch) | |
tree | 742988b455946b12a84adccb950b8df5a631417b /pkg/gui/gui.go | |
parent | eb056576cfe7d97503ef1baf3e1730c87d63976f (diff) |
resetting controllers on new repo
Diffstat (limited to 'pkg/gui/gui.go')
-rw-r--r-- | pkg/gui/gui.go | 226 |
1 files changed, 115 insertions, 111 deletions
diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 490ffca53..74a086e36 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -68,14 +68,14 @@ func NewContextManager(initialContext types.Context) ContextManager { } type Helpers struct { - refs *RefsHelper - bisect *controllers.BisectHelper - suggestions *SuggestionsHelper - files *FilesHelper - workingTree *WorkingTreeHelper - tags *controllers.TagsHelper - rebase *controllers.RebaseHelper - cherryPick *controllers.CherryPickHelper + Refs *controllers.RefsHelper + Bisect *controllers.BisectHelper + Suggestions *controllers.SuggestionsHelper + Files *controllers.FilesHelper + WorkingTree *controllers.WorkingTreeHelper + Tags *controllers.TagsHelper + Rebase *controllers.RebaseHelper + CherryPick *controllers.CherryPickHelper } type Repo string @@ -174,40 +174,23 @@ type PrevLayout struct { } type GuiRepoState struct { - CommitFiles []*models.CommitFile - Files []*models.File - Submodules []*models.SubmoduleConfig - Branches []*models.Branch - Commits []*models.Commit - StashEntries []*models.StashEntry - SubCommits []*models.Commit - Remotes []*models.Remote - RemoteBranches []*models.RemoteBranch - Tags []*models.Tag - // FilteredReflogCommits are the ones that appear in the reflog panel. - // when in filtering mode we only include the ones that match the given path - FilteredReflogCommits []*models.Commit - // ReflogCommits are the ones used by the branches panel to obtain recency values - // if we're not in filtering mode, CommitFiles and FilteredReflogCommits will be - // one and the same - ReflogCommits []*models.Commit + Model *types.Model + Modes Modes // Suggestions will sometimes appear when typing into a prompt - Suggestions []*types.Suggestion - MenuItems []*types.MenuItem - BisectInfo *git_commands.BisectInfo + Suggestions []*types.Suggestion + MenuItems []*types.MenuItem + Updating bool Panels *panelStates SplitMainPanel bool - MainContext types.ContextKey // used to keep the main and secondary views' contexts in sync IsRefreshingFiles bool Searching searchingState Ptmx *os.File StartupStage StartupStage // Allows us to not load everything at once - Modes Modes - + MainContext types.ContextKey // used to keep the main and secondary views' contexts in sync ContextManager ContextManager Contexts context.ContextTree ViewContextMap map[string]types.Context @@ -223,9 +206,6 @@ type GuiRepoState struct { // back in sync with the repo state ViewsSetup bool - // for displaying suggestions while typing in a file name - FilesTrie *patricia.Trie - // this is the message of the last failed commit attempt failedCommitMessage string @@ -390,6 +370,29 @@ type guiMutexes struct { SubprocessMutex *sync.Mutex } +func (gui *Gui) onNewRepo(filterPath string, reuseState bool) error { + var err error + gui.git, err = commands.NewGitCommand( + gui.Common, + gui.OSCommand, + git_config.NewStdCachedGitConfig(gui.Log), + gui.Mutexes.SyncMutex, + ) + if err != nil { + return err + } + + gui.resetState(filterPath, reuseState) + + gui.resetControllers() + + if err := gui.resetKeybindings(); err != nil { + return err + } + + return nil +} + // reuseState determines if we pull the repo state from our repo state map or // just re-initialize it. For now we're only re-using state when we're going // in and out of submodules, for the sake of having the cursor back on the submodule @@ -407,7 +410,6 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { if state := gui.RepoStateMap[Repo(currentDir)]; state != nil { gui.State = state gui.State.ViewsSetup = false - return } } else { gui.c.Log.Error(err) @@ -424,12 +426,17 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { } gui.State = &GuiRepoState{ - Files: make([]*models.File, 0), - Commits: make([]*models.Commit, 0), - FilteredReflogCommits: make([]*models.Commit, 0), - ReflogCommits: make([]*models.Commit, 0), - StashEntries: make([]*models.StashEntry, 0), - BisectInfo: git_commands.NewNullBisectInfo(), + Model: &types.Model{ + CommitFiles: nil, + Files: make([]*models.File, 0), + Commits: make([]*models.Commit, 0), + StashEntries: make([]*models.StashEntry, 0), + FilteredReflogCommits: make([]*models.Commit, 0), + ReflogCommits: make([]*models.Commit, 0), + BisectInfo: git_commands.NewNullBisectInfo(), + FilesTrie: patricia.NewTrie(), + }, + Panels: &panelStates{ // TODO: work out why some of these are -1 and some are 0. Last time I checked there was a good reason but I'm less certain now Submodules: &submodulePanelState{listPanelState{SelectedLineIdx: -1}}, @@ -459,7 +466,6 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { // TODO: put contexts in the context manager ContextManager: NewContextManager(initialContext), Contexts: contexts, - FilesTrie: patricia.NewTrie(), } gui.RepoStateMap[Repo(currentDir)] = gui.State @@ -472,7 +478,6 @@ func NewGui( config config.AppConfigurer, gitConfig git_config.IGitConfig, updater *updates.Updater, - filterPath string, showRecentRepos bool, initialDir string, ) (*Gui, error) { @@ -513,16 +518,6 @@ func NewGui( osCommand := oscommands.NewOSCommand(cmn, oscommands.GetPlatform(), guiIO) gui.OSCommand = osCommand - var err error - gui.git, err = commands.NewGitCommand( - cmn, - osCommand, - gitConfig, - gui.Mutexes.SyncMutex, - ) - if err != nil { - return nil, err - } gui.watchFilesForChanges() @@ -544,35 +539,32 @@ func NewGui( // TODO: reset these controllers upon changing repos due to state changing gui.c = controllerCommon - gui.resetState(filterPath, false) - gui.setControllers() authors.SetCustomAuthors(gui.UserConfig.Gui.AuthorColors) presentation.SetCustomBranches(gui.UserConfig.Gui.BranchColors) return gui, nil } -func (gui *Gui) setControllers() { +func (gui *Gui) resetControllers() { controllerCommon := gui.c osCommand := gui.OSCommand - getState := func() *GuiRepoState { return gui.State } getContexts := func() context.ContextTree { return gui.State.Contexts } - // TODO: have a getGit function too rebaseHelper := controllers.NewRebaseHelper(controllerCommon, getContexts, gui.git, gui.takeOverMergeConflictScrolling) + model := gui.State.Model gui.helpers = &Helpers{ - refs: NewRefsHelper( + Refs: controllers.NewRefsHelper( controllerCommon, gui.git, getContexts, - getState, + func() { gui.State.Panels.Commits.LimitCommits = true }, ), - bisect: controllers.NewBisectHelper(controllerCommon, gui.git), - suggestions: NewSuggestionsHelper(controllerCommon, getState, gui.refreshSuggestions), - files: NewFilesHelper(controllerCommon, gui.git, osCommand), - workingTree: NewWorkingTreeHelper(func() []*models.File { return gui.State.Files }), - tags: controllers.NewTagsHelper(controllerCommon, gui.git), - rebase: rebaseHelper, - cherryPick: controllers.NewCherryPickHelper( + Bisect: controllers.NewBisectHelper(controllerCommon, gui.git), + Suggestions: controllers.NewSuggestionsHelper(controllerCommon, model, gui.refreshSuggestions), + Files: controllers.NewFilesHelper(controllerCommon, gui.git, osCommand), + WorkingTree: controllers.NewWorkingTreeHelper(model), + Tags: controllers.NewTagsHelper(controllerCommon, gui.git), + Rebase: rebaseHelper, + CherryPick: controllers.NewCherryPickHelper( controllerCommon, gui.git, getContexts, @@ -585,9 +577,9 @@ func (gui *Gui) setControllers() { controllerCommon, gui.git, gui.getCheckedOutBranch, - gui.helpers.suggestions, + gui.helpers.Suggestions, gui.getSuggestedRemote, - gui.helpers.rebase.CheckMergeOrRebase, + gui.helpers.Rebase.CheckMergeOrRebase, ) gui.Controllers = Controllers{ @@ -601,32 +593,32 @@ func (gui *Gui) setControllers() { Files: controllers.NewFilesController( controllerCommon, func() *context.WorkingTreeContext { return gui.State.Contexts.Files }, - func() []*models.File { return gui.State.Files }, + func() []*models.File { return gui.State.Model.Files }, gui.git, osCommand, gui.getSelectedFileNode, getContexts, gui.enterSubmodule, - func() []*models.SubmoduleConfig { return gui.State.Submodules }, + func() []*models.SubmoduleConfig { return gui.State.Model.Submodules }, gui.getSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitMessage }), gui.withGpgHandling, func() string { return gui.State.failedCommitMessage }, - func() []*models.Commit { return gui.State.Commits }, + func() []*models.Commit { return gui.State.Model.Commits }, gui.getSelectedPath, gui.switchToMerge, - gui.helpers.suggestions, - gui.helpers.refs, - gui.helpers.files, - gui.helpers.workingTree, + gui.helpers.Suggestions, + gui.helpers.Refs, + gui.helpers.Files, + gui.helpers.WorkingTree, ), Tags: controllers.NewTagsController( controllerCommon, func() *context.TagsContext { return gui.State.Contexts.Tags }, gui.git, getContexts, - gui.helpers.tags, - gui.helpers.refs, - gui.helpers.suggestions, + gui.helpers.Tags, + gui.helpers.Refs, + gui.helpers.Suggestions, gui.switchToSubCommitsContext, ), LocalCommits: controllers.NewLocalCommitsController( @@ -634,18 +626,17 @@ func (gui *Gui) setControllers() { func() types.IListContext { return gui.State.Contexts.BranchCommits }, osCommand, gui.git, - gui.helpers.tags, - gui.helpers.refs, - gui.helpers.cherryPick, - gui.helpers.rebase, + gui.helpers.Tags, + gui.helpers.Refs, + gui.helpers.CherryPick, + gui.helpers.Rebase, gui.getSelectedLocalCommit, - func() []*models.Commit { return gui.State.Commits }, + func() []*models.Commit { return gui.State.Model.Commits }, func() int { return gui.State.Panels.Commits.SelectedLineIdx }, - gui.helpers.rebase.CheckMergeOrRebase, + gui.helpers.Rebase.CheckMergeOrRebase, syncController.HandlePull, gui.getHostingServiceMgr, gui.SwitchToCommitFilesContext, - gui.handleOpenSearch, func() bool { return gui.State.Panels.Commits.LimitCommits }, func(value bool) { gui.State.Panels.Commits.LimitCommits = value }, func() bool { return gui.ShowWholeGitGraph }, @@ -657,7 +648,7 @@ func (gui *Gui) setControllers() { gui.git, getContexts, gui.getSelectedRemote, - func(branches []*models.RemoteBranch) { gui.State.RemoteBranches = branches }, + func(branches []*models.RemoteBranch) { gui.State.Model.RemoteBranches = branches }, ), Menu: controllers.NewMenuController( controllerCommon, @@ -668,16 +659,16 @@ func (gui *Gui) setControllers() { controllerCommon, func() types.IListContext { return gui.State.Contexts.BranchCommits }, gui.git, - gui.helpers.bisect, + gui.helpers.Bisect, gui.getSelectedLocalCommit, - func() []*models.Commit { return gui.State.Commits }, + func() []*models.Commit { return gui.State.Model.Commits }, ), Undo: controllers.NewUndoController( controllerCommon, gui.git, - gui.helpers.refs, - gui.helpers.workingTree, - func() []*models.Commit { return gui.State.FilteredReflogCommits }, + gui.helpers.Refs, + gui.helpers.WorkingTree, + func() []*models.Commit { return gui.State.Model.FilteredReflogCommits }, ), Sync: syncController, } @@ -689,8 +680,7 @@ var RuneReplacements = map[rune]string{ graph.CommitSymbol: "o", } -// Run setup the gui with keybindings and start the mainloop -func (gui *Gui) Run() error { +func (gui *Gui) initGocui() (*gocui.Gui, error) { recordEvents := recordingEvents() playMode := gocui.NORMAL if recordEvents { @@ -701,19 +691,30 @@ func (gui *Gui) Run() error { g, err := gocui.NewGui(gocui.OutputTrue, OverlappingEdges, playMode, headless(), RuneReplacements) if err != nil { + return nil, err + } + + return g, nil +} + +// Run: setup the gui with keybindings and start the mainloop +func (gui *Gui) Run(filterPath string) error { + g, err := gui.initGocui() + if err != nil { return err } - gui.g = g // TODO: always use gui.g rather than passing g around everywhere - defer g.Close() + gui.g = g + defer gui.g.Close() if replaying() { - g.RecordingConfig = gocui.RecordingConfig{ + gui.g.RecordingConfig = gocui.RecordingConfig{ Speed: getRecordingSpeed(), Leeway: 100, } - g.Recording, err = gui.loadRecording() + var err error + gui.g.Recording, err = gui.loadRecording() if err != nil { return err } @@ -724,25 +725,32 @@ func (gui *Gui) Run() error { }) } - g.OnSearchEscape = gui.onSearchEscape + gui.g.OnSearchEscape = gui.onSearchEscape if err := gui.Config.ReloadUserConfig(); err != nil { return nil } userConfig := gui.UserConfig - g.SearchEscapeKey = gui.getKey(userConfig.Keybinding.Universal.Return) - g.NextSearchMatchKey = gui.getKey(userConfig.Keybinding.Universal.NextMatch) - g.PrevSearchMatchKey = gui.getKey(userConfig.Keybinding.Universal.PrevMatch) + gui.g.SearchEscapeKey = gui.getKey(userConfig.Keybinding.Universal.Return) + gui.g.NextSearchMatchKey = gui.getKey(userConfig.Keybinding.Universal.NextMatch) + gui.g.PrevSearchMatchKey = gui.getKey(userConfig.Keybinding.Universal.PrevMatch) - g.ShowListFooter = userConfig.Gui.ShowListFooter + gui.g.ShowListFooter = userConfig.Gui.ShowListFooter if userConfig.Gui.MouseEvents { - g.Mouse = true + gui.g.Mouse = true } if err := gui.setColorScheme(); err != nil { return err } + gui.g.SetManager(gocui.ManagerFunc(gui.layout), gocui.ManagerFunc(gui.getFocusLayout())) + + // onNewRepo must be called after g.SetManager because SetManager deletes keybindings + if err := gui.onNewRepo(filterPath, false); err != nil { + return err + } + gui.waitForIntro.Add(1) if gui.c.UserConfig.Git.AutoFetch { go utils.Safe(gui.startBackgroundFetch) @@ -750,19 +758,15 @@ func (gui *Gui) Run() error { gui.goEvery(time.Second*time.Duration(userConfig.Refresher.RefreshInterval), gui.stopChan, gui.refreshFilesAndSubmodules) - g.SetManager(gocui.ManagerFunc(gui.layout), gocui.ManagerFunc(gui.getFocusLayout())) - gui.c.Log.Info("starting main loop") - err = g.MainLoop() - return err + return gui.g.MainLoop() } -// RunAndHandleError -func (gui *Gui) RunAndHandleError() error { +func (gui *Gui) RunAndHandleError(filterPath string) error { gui.stopChan = make(chan struct{}) return utils.SafeWithError(func() error { - if err := gui.Run(); err != nil { + if err := gui.Run(filterPath); err != nil { for _, manager := range gui.viewBufferManagerMap { manager.Close() } |